[
  {
    "path": ".eslintignore",
    "content": "**/node_modules/**\n**/dist/**\n*.json\n**/template/**\npackages/*/lib/*\nfixtures\n"
  },
  {
    "path": ".eslintrc.json",
    "content": "{\n  \"extends\": [\"plugin:@typescript-eslint/recommended\", \"airbnb\", \"plugin:prettier/recommended\"],\n  \"env\": {\n    \"browser\": true,\n    \"commonjs\": true,\n    \"es6\": true,\n    \"node\": true\n  },\n  \"parser\": \"@typescript-eslint/parser\",\n  \"parserOptions\": {\n    \"sourceType\": \"module\",\n    \"ecmaFeatures\": {\n      \"jsx\": true,\n      \"experimentalObjectRestSpread\": true\n    }\n  },\n  \"globals\": {\n    \"describe\": \"readonly\",\n    \"it\": \"readonly\",\n    \"expect\": \"readonly\",\n    \"jest\": \"readonly\",\n    \"$\": \"readonly\",\n    \"afterEach\": \"readonly\",\n    \"beforeEach\": \"readonly\",\n    \"NodeJS\": \"writable\"\n  },\n  \"rules\": {\n    \"prettier/prettier\": [\n      \"error\",\n      {\n        \"trailingComma\": \"es5\",\n        \"printWidth\": 100\n      }\n    ],\n    \"linebreak-style\": [\"error\", \"unix\"],\n    \"max-classes-per-file\": 0,\n    \"no-case-declarations\": 0,\n    \"no-continue\": 0,\n    \"no-empty\": 0,\n    \"no-empty-function\": 0,\n    \"no-param-reassign\": 0,\n    \"no-prototype-builtins\": 0,\n    \"no-shadow\": 0,\n    \"no-restricted-syntax\": 0,\n    \"no-underscore-dangle\": 0,\n    \"no-useless-constructor\": 0,\n    \"no-useless-escape\": 0,\n    \"no-use-before-define\": [\"error\", {\"functions\": false, \"classes\": false}],\n    \"no-unused-vars\": 0,\n    \"no-unused-expressions\": [\"error\", {\"allowShortCircuit\": true, \"allowTernary\": true}],\n    \"no-plusplus\": 0,\n    \"no-nested-ternary\": 0,\n    \"one-var\": 0,\n    \"prefer-promise-reject-errors\": 0,\n    \"prefer-regex-literals\": 0,\n    \"prefer-destructuring\": 0,\n    \"global-require\": 0,\n    \"guard-for-in\": 0,\n    \"func-names\": 0,\n    \"strict\": 0,\n    \"radix\": 0,\n    \"class-methods-use-this\": 0,\n    \"import/no-extraneous-dependencies\": 1,\n    \"import/no-dynamic-require\": 0,\n    \"import/no-mutable-exports\": 0,\n    \"import/no-unresolved\": 0,\n    \"import/extensions\": 0,\n    \"import/prefer-default-export\": 0,\n    \"react/jsx-filename-extension\": [1, {\"extensions\": [\".js\", \".jsx\", \"ts\", \"tsx\"]}],\n    \"react/sort-comp\": 0,\n    \"react/prefer-stateless-function\": 0,\n    \"react/no-array-index-key\": 0,\n    \"react/no-children-prop\": 0,\n    \"react/jsx-props-no-spreading\": 0,\n    \"react/jsx-one-expression-per-line\": 0,\n    \"react/no-multi-comp\": 0,\n    \"react/destructuring-assignment\": 0,\n    \"react/button-has-type\": 0,\n    \"react/require-default-props\": 0,\n    \"jsx-a11y/click-events-have-key-events\": 0,\n    \"jsx-a11y/no-static-element-interactions\": 0,\n    \"jsx-a11y/no-noninteractive-element-interactions\": 0,\n    \"@typescript-eslint/ban-ts-comment\": 0,\n    \"@typescript-eslint/explicit-function-return-type\": 0,\n    \"@typescript-eslint/explicit-module-boundary-types\": 0,\n    \"@typescript-eslint/no-empty-function\": 0,\n    \"@typescript-eslint/no-unused-vars\": [2, {\"vars\": \"all\", \"args\": \"none\"}]\n  }\n}\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Desktop (please complete the following information):**\n - OS: [e.g. MacOS]\n - node version [e.g. v16.13.1]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!--\n  Thanks so much for your PR and contribution.\n  \n  Before submitting, please make sure to follow the Pull Request Guidelines: https://github.com/arco-design/arco-cli/blob/master/CONTRIBUTING.md\n-->\n\n<!-- Put an `x` in \"[ ]\" to check a box) -->\n\n## Types of changes\n\n<!-- What types of changes does this PR introduce -->\n- [ ] New feature\n- [ ] Bug fix\n- [ ] Documentation change\n- [ ] Coding style change\n- [ ] Refactoring\n- [ ] Performance improvement\n- [ ] Test cases\n- [ ] Continuous integration\n- [ ] Typescript definition change\n- [ ] Breaking change\n\n## Background and context\n\n<!-- Explain what problem does the PR solve -->\n<!-- Link to related open issues if applicable -->\n\n## Solution\n\n<!-- Describe how the problem is fixed in detail -->\n\n## How is the change tested?\n\n<!-- Unit tests should be added/updated for bug fixes and new features, if applicable -->\n<!-- Please describe how you tested the change. E.g. Creating/updating unit tests or attaching a screenshot of how it works with your change -->\n\n## Changelog\n\n| Changelog(CN) | Changelog(EN) | Related issues | \n| ------------- | ------------- | -------------- |\n\n## Checklist:\n\n- [ ] Provide changelog for relevant changes (e.g. bug fixes and new features) if applicable.\n- [ ] Changes are submitted to the appropriate branch (e.g. features should be submitted to `feature` branch and others should be submitted to `master` branch)\n\n## Other information\n\n<!-- Please describe what other information that should be taken care of. E.g. describe the impact if introduce a breaking change -->\n"
  },
  {
    "path": ".gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n.npmrc\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 (http://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\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/stylelint cache\n.eslintcache\n.stylelintcache\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\n# next.js build output\n.next\n\n**/__test__/fixtures/es\n**/__test__/fixtures/lib\n**/__test__/fixtures/dist\n\n.idea\n\n**/.DS_Store\n\npackage-lock.json\nfixtures/**/dist\npackages/**/dist\n"
  },
  {
    "path": ".husky/pre-commit",
    "content": "#!/usr/bin/env sh\n. \"$(dirname -- \"$0\")/_/husky.sh\"\n\nnpm run eslint\nnpm run stylelint\n"
  },
  {
    "path": ".prettierrc.json",
    "content": "{\n  \"arrowParens\": \"always\",\n  \"jsxBracketSameLine\": false,\n  \"jsxSingleQuote\": false,\n  \"printWidth\": 100,\n  \"semi\": true,\n  \"singleQuote\": true,\n  \"tabWidth\": 2,\n  \"trailingComma\": \"es5\",\n  \"useTabs\": false\n}\n"
  },
  {
    "path": ".scripts/build-esm.sh",
    "content": "root=`git rev-parse --show-toplevel`\nbabel_config_path=\"${root}/babel.config.js\"\n\nbabel_options=\"\"\n\nif [[ $1 == dev ]]; then\n  babel_options=\"--watch --source-maps\"\nfi\n\n# Compile .ts with babel and copy tsc un-support files\nbabel src -d dist -x \".ts,.tsx,.js\" --copy-files --verbose --config-file $babel_config_path $babel_options\n"
  },
  {
    "path": ".scripts/build-type.sh",
    "content": "# disable this command for now\n# tsc --emitDeclarationOnly\n"
  },
  {
    "path": ".scripts/build.sh",
    "content": "root=`git rev-parse --show-toplevel`\nbabel_config_path=\"${root}/babel.config.js\"\n\nflag_no_source_maps=\"no-source-maps\"\nbabel_options=\"--plugins=@babel/plugin-transform-modules-commonjs\"\n\nif [[ $1 == dev ]]; then\n  babel_options=\"$babel_options --watch\"\nfi\n\nif [[ \"$*\" != *\"$flag_no_source_maps\"* ]]; then\n  babel_options=\"$babel_options --source-maps\"\nfi\n\n# Compile .ts with babel and copy tsc un-support files\nbabel src -d dist -x \".ts,.tsx,.js\" --copy-files --verbose --config-file $babel_config_path $babel_options\n"
  },
  {
    "path": ".scripts/flatPackages.js",
    "content": "/* eslint-disable */\nconst path = require('path');\nconst fs = require('fs-extra');\nconst gulp = require('gulp');\nconst gulpReplace = require('gulp-replace');\nconst getLocalPackages = require('./getLocalPackages');\n\nconst NEW_PACKAGES_DIR = path.resolve(__dirname, '../_packages');\nconst PATH_IGNORE_PATTERN = /ui-foundation|app|stone|legacy/;\n\nconst DEFAULT_PACKAGE_JSON = {\n  version: '0.1.0',\n  scripts: {\n    dev: 'sh ../../.scripts/build.sh dev',\n    build: 'sh ../../.scripts/build.sh',\n    'build-type': 'sh ../../.scripts/build-type.sh',\n    clean: 'rm -rf dist',\n    'clean-type': 'find dist -name *.d.ts |xargs rm -rf',\n    prepublishOnly: 'npm run build',\n  },\n  files: ['dist'],\n  license: 'MIT',\n};\n\nasync function flatPackages() {\n  const originPackages = await getLocalPackages();\n  const newPackages = {};\n\n  originPackages.forEach(({ name, location }) => {\n    if (location.match(PATH_IGNORE_PATTERN)) {\n      return;\n    }\n\n    const parentDir = path.dirname(location);\n    const dirname = parentDir.split('/').pop();\n    newPackages[parentDir] ||= {\n      dirname,\n      name: `@arco-cli/${dirname}`,\n      path: path.resolve(NEW_PACKAGES_DIR, dirname),\n      packages: [],\n      children: [],\n    };\n    newPackages[parentDir].packages.push(name);\n    newPackages[parentDir].children.push(location);\n  });\n\n  Object.values(newPackages).forEach(({ path: newPackagePath, name, children }) => {\n    const newPackageJson = {\n      name,\n      ...DEFAULT_PACKAGE_JSON,\n    };\n    const childrenDeps = {\n      peerDependencies: {},\n      dependencies: {},\n      devDependencies: {},\n    };\n\n    children.forEach((location) => {\n      const packageJson = fs.readJsonSync(path.resolve(location, 'package.json'));\n      Object.assign(childrenDeps.peerDependencies, packageJson.peerDependencies);\n      Object.assign(childrenDeps.dependencies, packageJson.dependencies);\n      Object.assign(childrenDeps.devDependencies, packageJson.devDependencies);\n    });\n\n    Object.entries(childrenDeps).forEach(([depType, deps]) => {\n      Object.entries(deps)\n        .sort(([keyA], [keyB]) => {\n          return keyB.startsWith('@') && !keyA.startsWith('@') ? 1 : keyA > keyB ? 1 : -1;\n        })\n        .map(([key, value]) => {\n          if (key.startsWith('@arco-cli/')) {\n            const newPackagesInfo = Object.values(newPackages);\n            for (const { name, packages } of newPackagesInfo) {\n              if (packages.indexOf(key) > -1) {\n                return [name, value];\n              }\n            }\n          }\n\n          return [key, value];\n        })\n        .forEach(([key, value]) => {\n          if (key !== newPackageJson.name) {\n            newPackageJson[depType] ||= {};\n            newPackageJson[depType][key] = value;\n          }\n        });\n    });\n\n    // write new packageJson\n    fs.ensureDirSync(`${newPackagePath}/src`);\n    fs.writeJsonSync(path.join(newPackagePath, 'package.json'), newPackageJson, { spaces: 2 });\n\n    // copy children's source file\n    for (const childLocation of children) {\n      fs.copySync(\n        `${childLocation}/src`,\n        `${newPackagePath}/src/${childLocation.split('/').pop()}`\n      );\n    }\n  });\n\n  return Promise.all(\n    Object.values(newPackages).map(({ name, path: newPackagePath, packages }) => {\n      return new Promise((resolve, reject) => {\n        gulp\n          .src(`${newPackagePath}/src/**/*.*`)\n          .pipe(\n            gulpReplace(/'@arco-cli\\/[^']+'/g, function doReplace(match) {\n              if (PATH_IGNORE_PATTERN.test(match)) {\n                return match;\n              }\n\n              const fileRelativePath = this.file.relative;\n              const splitPaths = match.replace(/'/g, '').split('/');\n              const originPackage = splitPaths.slice(0, 2).join('/');\n              const originImportFrom = splitPaths.slice(2).join('/');\n\n              let newPackage = Object.values(newPackages).find(({ packages }) => {\n                return packages.indexOf(originPackage) > -1;\n              })?.name;\n\n              if (!newPackage) {\n                return 'NO_MATCH';\n              }\n\n              const newImportFrom = `${\n                newPackage === name\n                  ? `@self`\n                  : `${newPackage}/dist`\n              }/${originPackage.split('/').pop()}`;\n\n              if (originImportFrom) {\n                return `'${newImportFrom}/${originImportFrom.replace('dist/', '')}'`;\n              } else {\n                return `'${newImportFrom}'`;\n              }\n            })\n          )\n          .pipe(gulp.dest(`${newPackagePath}/src`))\n          .on('end', () => {\n            console.log(`_________ ${newPackagePath}`);\n            resolve();\n          })\n          .on('error', (error) => {\n            reject(error);\n            console.error(error);\n          });\n      });\n    })\n  );\n}\n\nflatPackages()\n  .then()\n  .catch((err) => {\n    console.log(err);\n  });\n"
  },
  {
    "path": ".scripts/getLocalPackages.js",
    "content": "/* eslint-disable */\nconst path = require('path');\nconst { exec } = require('child_process');\n\nconst DIR_PACKAGES = path.resolve(__dirname, '../packages');\n\n/**\n * @returns {Promise<Array<{ name: string; location: string }>>}\n */\nmodule.exports = function () {\n  return new Promise((resolve, reject) => {\n    exec('lerna list --json', (error, stdout, stderr) => {\n      const errMsg = 'Failed to collect packages info via [lerna list]';\n\n      if (error) {\n        reject({\n          error,\n          msg: errMsg,\n        });\n      }\n\n      try {\n        const infoList = JSON.parse(stdout).filter(({ location }) =>\n          location.startsWith(DIR_PACKAGES)\n        );\n        resolve(infoList);\n      } catch (error) {\n        reject({\n          error,\n          msg: stderr || errMsg,\n        });\n      }\n    });\n  });\n};\n"
  },
  {
    "path": ".scripts/linkLocalPackages.js",
    "content": "/* eslint-disable */\nconst path = require('path');\nconst fs = require('fs-extra');\nconst chalk = require('chalk');\nconst getLocalPackages = require('./getLocalPackages');\n\nconst DIR_NODE_MODULES = path.resolve(__dirname, '../node_modules');\n\nasync function linkLocalPackages() {\n  try {\n    const packages = await getLocalPackages();\n    const packagesDone = [];\n    packages.forEach(({ name, location }) => {\n      const from = location;\n      const to = `${DIR_NODE_MODULES}/${name}`;\n      const nodeModulesEntryDir = path.resolve(\n        DIR_NODE_MODULES,\n        name.split('/').slice(0, -1).join('')\n      );\n\n      try {\n        if (!fs.existsSync(to)) {\n          fs.ensureDirSync(nodeModulesEntryDir);\n          fs.symlinkSync(from, to, 'dir');\n        }\n\n        packagesDone.push(name);\n      } catch (error) {\n        console.error(chalk.red(`Failed to link ${to} from ${from}\\n`), error);\n      }\n    });\n\n    console.log(\n      chalk.green(\n        'Link workspace packages successfully. Following packages are linked to node_modules:\\n'\n      ),\n      packagesDone\n    );\n    process.exit(0);\n  } catch ({ error, msg }) {\n    console.error(chalk.red(`${msg}\\n`), error);\n    process.exit(1);\n  }\n}\n\nlinkLocalPackages().finally(() => {});\n"
  },
  {
    "path": ".scripts/linkTsPaths.js",
    "content": "/* eslint-disable */\nconst path = require('path');\nconst fs = require('fs-extra');\nconst chalk = require('chalk');\nconst getLocalPackages = require('./getLocalPackages');\n\nconst ROOT_PATH = path.resolve(__dirname, '..');\nconst FILE_TSCONFIG = path.resolve(ROOT_PATH, 'tsconfig.paths.json');\n\nasync function linkLocalPackages() {\n  try {\n    const packages = await getLocalPackages();\n    const tsconfig = fs.readJsonSync(FILE_TSCONFIG);\n    const paths = {};\n\n    packages.forEach(({ name, location }) => {\n      location = `./node_modules/${name}`;\n      paths[name] = [`${location}/src/index.ts`];\n      paths[`${name}/dist/*`] = [`${location}/src/*`];\n    });\n    tsconfig.compilerOptions.paths = paths;\n    fs.writeFileSync(FILE_TSCONFIG, JSON.stringify(tsconfig, null, 2));\n\n    console.error(chalk.green('Generate tsconfig paths successfully.'));\n  } catch ({ error, msg }) {\n    console.error(chalk.red(`${msg}\\n`), error);\n    process.exit(1);\n  }\n}\n\nlinkLocalPackages().finally(() => {});\n"
  },
  {
    "path": ".stylelintignore",
    "content": "**/node_modules/**\n**/dist/**\n"
  },
  {
    "path": ".stylelintrc",
    "content": "{\n  \"extends\": \"stylelint-config-standard-scss\",\n  \"rules\": {\n    \"block-no-empty\": null,\n    \"block-opening-brace-space-before\": \"always\",\n    \"declaration-block-trailing-semicolon\": \"always\",\n    \"font-family-no-missing-generic-family-keyword\": null,\n    \"import-notation\": null,\n    \"no-invalid-double-slash-comments\": null,\n    \"no-duplicate-selectors\": null,\n    \"selector-class-pattern\": null,\n    \"selector-pseudo-class-no-unknown\": [\n      true,\n      {\n        \"ignorePseudoClasses\": [\"global\"]\n      }\n    ],\n    \"string-quotes\": \"single\",\n    \"scss/no-global-function-names\": null\n  }\n}\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n- Using welcoming and inclusive language\n- Being respectful of differing viewpoints and experiences\n- Gracefully accepting constructive criticism\n- Focusing on what is best for the community\n- Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n- The use of sexualized language or imagery and unwelcome sexual attention or advances\n- Trolling, insulting/derogatory comments, and personal or political attacks\n- Public or private harassment\n- Publishing others' private information, such as a physical or electronic address, without explicit permission\n- Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies within all project spaces, and it also applies when an individual is representing the project or its community in public spaces. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at pengjiyuan@bytendance.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "\n> English | [简体中文](./CONTRIBUTING.zh-CN.md)\n# Contributing\n\nThank you for taking your time to contribute and make this project better! Here are some guidelines to help you get started. Please make sure to take a moment and read through them before submitting your contributions.\n\n## Code of Conduct\n\nThis project is governed by the [Contributor Covenant Code of Conduct](./CODE_OF_CONDUCT.md). By participating, you are expected to adhere to it.\n\n## Open Development\n\nAll work happens directly on GitHub. Both core team members and external contributors send pull requests which go through the same review process.\n\n## Semantic Versioning\n\nThis project follows semantic versioning. We release patch versions for bug fixes or other changes that do not change the behavior of the API, minor versions for new features that are backward-compatible, and major versions for any breaking changes.\n\nEvery significant change is documented in the changelog file.\n\n## Reporting Issues\n\nWe use [Github issues](https://github.com/arco-design/arco-cli/issues) for bug reports and feature requests. Before reporting an issue, please make sure you have searched for similar [issues](https://github.com/arco-design/arco-cli/issues) as they may have been already answered or being fixed. A new issue should be submitted via [issue helper](https://arco-design/issue-helper?repo=arco-cli). For bug reporting, please include the minimum code that can be used to reproduce the problem. For feature request, please specify what changes you want and what behavior you expect.\n\n## Sending a pull request\n\n1. Fork [the repository](https://github.com/arco-design/arco-cli) and create your branch from `master`. For new feature, please submit your changes directly to the `feature` branch. Other changes should go against `master` branch.\n1. Run `npm run init` in the repository root.\n1. Make changes to the codebase. Please add tests if applicable.\n1. Commit your changes, adhering to the [Commit Guidelines](#commit-guidelines)\n1. Open a new pull request, [referencing corresponding issues](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) if available.\n\n\n## Commit Guidelines\n\nCommit messages are required to follow the [conventional-changelog standard](https://www.conventionalcommits.org/en/v1.0.0/):\n\n```bash\n<type>[optional scope]: <description>\n\n[optional body]\n\n[optional footer(s)]\n```\n\n### Commit types\n\nThe following is a list of commit types:\n\n- feat: A new feature or functionality\n- fix: A bug fix\n- docs: Documentation only changes\n- style: Code formatting\n- refactor: Code changes that neither fixes a bug nor adds a feature.\n- perf: Improve performance.\n- test: Add missing or correct existing tests.\n- chore: Other commits that don’t modify src or test files.\n\n## License\n\nBy contributing your code to the repository, you agree to license your contribution under the [MIT license](./LICENSE)."
  },
  {
    "path": "CONTRIBUTING.zh-CN.md",
    "content": "\n> [English](./CONTRIBUTING.md) | 简体中文\n\n# 贡献指南\n\n感谢你的宝贵时间。你的贡献将使这个项目变得更好！在提交贡献之前，请务必花点时间阅读下面的入门指南。\n\n## 行为准则\n\n该项目有一份 [行为准则](./CODE_OF_CONDUCT.md)，希望参与项目的贡献者都能严格遵守。\n\n## 透明的开发\n\n所有工作都直接透明地在 GitHub 上进行。核心团队成员和外部贡献者的 pull requests 都需要经过相同的 review 流程。\n\n## 语义化版本\n\n该项目遵循语义化版本。我们对重要的漏洞修复发布修订号，对新特性或不重要的变更发布次版本号，对重大且不兼容的变更发布主版本号。\n\n每个重大更改都将记录在 changelog 中。\n\n## 报告 Issues\n\n我们使用 [Github issues](https://github.com/arco-design/arco-cli/issues) 进行 bug 报告和新 feature 建议。在报告 bug 之前，请确保已经搜索过类似的 [问题](https://github.com/arco-design/arco-cli/issues?repo=arco-cli)，因为它们可能已经得到解答或正在被修复。新问题应通过 [问题助手](https://arco-design/issue-helper) 提交。对于 bug 报告，请包含可用于重现问题的代码。对于新 feature 建议，请指出你想要的更改以及期望的行为。\n\n## 提交 Pull Request\n\n1. Fork [此仓库](https://github.com/arco-design/arco-cli)，从 `master` 创建分支。新功能实现请发 pull request 到 `feature` 分支。其他更改发到 `master` 分支。\n1. 在仓库根目录下执行 `npm run init`。\n1. 对代码库进行更改。如果适用的话，请确保写了相应的测试。\n1. 提交 git commit, 请同时遵守 [Commit 规范](#commit-guidelines)。\n1. 提交 pull request, 如果有对应的 issue，请进行[关联](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword)。\n\n## Commit 指南\n\nCommit messages 请遵循[conventional-changelog 标准](https://www.conventionalcommits.org/en/v1.0.0/)：\n\n```bash\n<类型>[可选 范围]: <描述>\n\n[可选 正文]\n\n[可选 脚注]\n```\n\n### Commit 类型\n\n以下是 commit 类型列表:\n\n- feat: 新特性或功能\n- fix: 缺陷修复\n- docs: 文档更新\n- style: 代码风格更新\n- refactor: 代码重构，不引入新功能和缺陷修复\n- perf: 性能优化\n- test: 单元测试\n- chore: 其他不修改 src 或测试文件的提交\n\n## License\n\n[MIT 协议](./LICENSE)."
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 Bytedance, Inc. and its affiliates.\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."
  },
  {
    "path": "README.md",
    "content": "# Arco CLI\n\nA command-line interface tool for creating, developing and managing Arco materials.\n\n## How to start\n\n`npm run init` to set up environment.\n\n`lerna run dev` to enter dev mode.\n"
  },
  {
    "path": "babel.config.js",
    "content": "// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst createResolvePath = require('babel-plugin-tsconfig-paths-module-resolver/create-resolve');\n\nconst defaultResolvePath = createResolvePath();\n\nmodule.exports = function (api) {\n  api.cache(true);\n\n  const presets = ['@babel/preset-react', '@babel/typescript'];\n\n  const plugins = [\n    'babel-plugin-transform-typescript-metadata',\n    '@babel/plugin-transform-runtime',\n    ['@babel/plugin-proposal-decorators', { legacy: true }],\n    '@babel/plugin-proposal-export-namespace-from',\n    '@babel/plugin-proposal-object-rest-spread',\n    '@babel/plugin-proposal-optional-chaining',\n    '@babel/plugin-proposal-class-properties',\n    '@babel/plugin-proposal-logical-assignment-operators',\n    [\n      'tsconfig-paths-module-resolver',\n      {\n        resolvePath: function customResolvePath(sourceFile, currentFile, opts) {\n          // alias for @arco-cli/packages is only for IDE ts-hint\n          // we don't need to transform it while compiling\n          if (sourceFile.startsWith('@arco-cli/')) {\n            return null;\n          }\n\n          return defaultResolvePath(sourceFile, currentFile, opts);\n        },\n      },\n    ],\n  ];\n\n  return {\n    presets,\n    plugins,\n    only: ['**/*.ts', '**/*.tsx'],\n    //  in generator/src/templates, babel should only compile files NOT ends with tpl.ts\n    ignore: [/generator\\/src\\/templates\\/([^/]+\\/)*.+(?<!(tpl|desc).)tsx?$/],\n  };\n};\n"
  },
  {
    "path": "jest.config.ts",
    "content": "import type { Config } from 'jest';\n\nconst config: Config = {\n  preset: 'ts-jest',\n  testEnvironment: 'node',\n  collectCoverage: true,\n  collectCoverageFrom: ['packages/*/src/*.{j,t}s'],\n  testRegex: '.*\\\\.test\\\\.(j|t)sx?$',\n  testPathIgnorePatterns: ['/node_modules/'],\n  transformIgnorePatterns: ['node_modules/[^/]+?/(?!(es|node_modules)/)'],\n};\n\nexport default config;\n"
  },
  {
    "path": "lerna.json",
    "content": "{\n  \"version\": \"independent\",\n  \"useWorkspaces\": true,\n  \"npmClient\": \"pnpm\",\n  \"ignoreChanges\": [\"**/ui/**\"]\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"@arco-design/arco-cli\",\n  \"description\": \"Arco CLI & Arco Scripts\",\n  \"private\": true,\n  \"scripts\": {\n    \"prepare\": \"husky install\",\n    \"init\": \"pnpm i && npm run build\",\n    \"clean\": \"lerna run clean --parallel --ignore=\\\"@arco-cli/workspace-materials\\\"\",\n    \"build\": \"lerna run build --parallel --ignore=\\\"@arco-cli/workspace-materials\\\" && npm run build:materials\",\n    \"build:materials\": \"lerna run build --scope=\\\"@arco-cli/workspace-materials\\\"\",\n    \"link\": \"node ./scripts/linkLocalPackages.js\",\n    \"format\": \"prettier --config --write \\\"packages/**/*.{js,jsx,ts,tsx}\\\"\",\n    \"eslint\": \"eslint packages/ --fix --cache --quiet --ext .js,.jsx,.ts,.tsx\",\n    \"stylelint\": \"stylelint 'packages/**/*.scss' --fix --cache\"\n  },\n  \"dependencies\": {\n    \"@babel/cli\": \"^7.19.3\",\n    \"@babel/core\": \"^7.20.5\",\n    \"@babel/plugin-proposal-class-properties\": \"^7.18.6\",\n    \"@babel/plugin-proposal-decorators\": \"^7.20.5\",\n    \"@babel/plugin-proposal-export-namespace-from\": \"^7.18.9\",\n    \"@babel/plugin-proposal-logical-assignment-operators\": \"^7.20.7\",\n    \"@babel/plugin-proposal-object-rest-spread\": \"^7.20.2\",\n    \"@babel/plugin-proposal-optional-chaining\": \"^7.21.0\",\n    \"@babel/plugin-transform-modules-commonjs\": \"^7.19.6\",\n    \"@babel/plugin-transform-runtime\": \"^7.19.6\",\n    \"@babel/preset-env\": \"^7.20.2\",\n    \"@babel/preset-react\": \"^7.18.6\",\n    \"@babel/preset-typescript\": \"^7.18.6\",\n    \"@babel/runtime\": \"^7.20.6\",\n    \"@mdx-js/react\": \"^1.6.22\",\n    \"babel-plugin-tsconfig-paths-module-resolver\": \"^1.0.4\",\n    \"chalk\": \"^4.1.2\",\n    \"fs-extra\": \"^10.1.0\",\n    \"lodash\": \"^4.17.21\",\n    \"react\": \"^17.0.2\",\n    \"react-dom\": \"^17.0.2\",\n    \"react-router-dom\": \"^6.5.0\",\n    \"ts-jest\": \"^29.0.3\",\n    \"ts-node\": \"^10.9.1\",\n    \"typescript\": \"^4.9.3\"\n  },\n  \"devDependencies\": {\n    \"@types/fs-extra\": \"^9.0.11\",\n    \"@types/gulp\": \"^4.0.8\",\n    \"@types/gulp-if\": \"^0.0.33\",\n    \"@types/gulp-plumber\": \"^0.0.32\",\n    \"@types/jest\": \"^29.2.5\",\n    \"@types/lodash\": \"^4.14.191\",\n    \"@types/merge-stream\": \"^1.1.2\",\n    \"@types/node\": \"^15.6.0\",\n    \"@types/react\": \"^17.0.39\",\n    \"@types/through2\": \"^2.0.36\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.42.0\",\n    \"@typescript-eslint/parser\": \"^5.42.0\",\n    \"eslint\": \"^8.26.0\",\n    \"eslint-config-airbnb\": \"^19.0.4\",\n    \"eslint-config-prettier\": \"^8.5.0\",\n    \"eslint-plugin-import\": \"^2.26.0\",\n    \"eslint-plugin-jsx-a11y\": \"^6.6.1\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"eslint-plugin-react\": \"^7.31.10\",\n    \"eslint-plugin-react-hooks\": \"^4.6.0\",\n    \"husky\": \"^8.0.3\",\n    \"jest\": \"^29.2.2\",\n    \"lerna\": \"^6.0.3\",\n    \"lint-staged\": \"^13.1.1\",\n    \"prettier\": \"^2.7.1\",\n    \"stylelint\": \"^14.14.0\",\n    \"stylelint-config-standard-scss\": \"^6.1.0\"\n  }\n}\n"
  },
  {
    "path": "packages/arco/bin/arco",
    "content": "#!/usr/bin/env node\nrequire('../dist/app');\n"
  },
  {
    "path": "packages/arco/package.json",
    "content": "{\n  \"name\": \"@arco-cli/arco\",\n  \"version\": \"2.4.5\",\n  \"description\": \"Main entry for arco cli\",\n  \"homepage\": \"https://github.com/arco-design/arco-cli\",\n  \"repository\": \"https://github.com/arco-design/arco-cli\",\n  \"main\": \"./dist/index.js\",\n  \"bin\": {\n    \"arco\": \"bin/arco\"\n  },\n  \"scripts\": {\n    \"dev\": \"sh ../../.scripts/build.sh dev\",\n    \"build\": \"sh ../../.scripts/build.sh\",\n    \"build-type\": \"sh ../../.scripts/build-type.sh\",\n    \"clean\": \"rm -rf dist\",\n    \"clean-type\": \"find dist -name *.d.ts |xargs rm -rf\",\n    \"prepublishOnly\": \"npm run build\"\n  },\n  \"dependencies\": {\n    \"@arco-cli/aspect\": \"^2.4.5\",\n    \"@arco-cli/core\": \"^2.3.2\",\n    \"@arco-cli/legacy\": \"^2.3.2\",\n    \"@arco-cli/react\": \"^2.4.5\",\n    \"@arco-cli/service\": \"^2.4.5\",\n    \"@arco-cli/stone\": \"^2.0.0-beta.0\",\n    \"fs-extra\": \"^10.1.0\"\n  },\n  \"files\": [\n    \"dist\",\n    \"bin\"\n  ],\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "packages/arco/src/app.ts",
    "content": "/* eslint-disable import/first */\nprocess.on('uncaughtException', (error) => {\n  console.error('uncaughtException', error);\n  process.exit(1);\n});\n\nimport { bootstrap } from '@arco-cli/legacy/dist/bootstrap';\nimport { handleErrorAndExit } from '@arco-cli/legacy/dist/cli/handleErrors';\nimport { setCliVersion } from '@arco-cli/legacy/dist/utils';\nimport { runCLI } from './loadCli';\nimport packageJson from '../package.json';\n\n(async function initApp() {\n  try {\n    setCliVersion(packageJson.version);\n    await bootstrap();\n    await runCLI();\n  } catch (err: any) {\n    const originalError = err.originalError || err;\n    await handleErrorAndExit(originalError, process.argv[2]);\n  }\n})();\n"
  },
  {
    "path": "packages/arco/src/arco.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\nimport { CORE_ASPECT_ID_MAP } from '@arco-cli/legacy/dist/constants';\n\nexport const ArcoAspect = Aspect.create({\n  id: CORE_ASPECT_ID_MAP.APP_ARCO,\n});\n\nexport default ArcoAspect;\n"
  },
  {
    "path": "packages/arco/src/arco.main.runtime.ts",
    "content": "import { MainRuntime } from '@arco-cli/core/dist/cli';\n\nimport { manifestMap } from './manifest';\n\nconst manifests = Object.values(manifestMap);\n\nexport const ArcoMain = {\n  name: 'arco',\n  runtime: MainRuntime,\n  dependencies: manifests,\n  provider: () => {},\n};\n"
  },
  {
    "path": "packages/arco/src/index.ts",
    "content": ""
  },
  {
    "path": "packages/arco/src/loadCli.ts",
    "content": "import path from 'path';\nimport logger from '@arco-cli/legacy/dist/logger';\nimport { Stone, Extension, RuntimeDefinition } from '@arco-cli/stone';\nimport { ConfigOptions, StoneConfig as Config } from '@arco-cli/stone/dist/stoneConfig';\nimport {\n  AspectLoaderAspect,\n  AspectLoaderMain,\n  getAspectDef,\n} from '@arco-cli/core/dist/aspect-loader';\nimport { CLIAspect, MainRuntime, CLIMain } from '@arco-cli/core/dist/cli';\nimport { getWorkspaceInfo } from '@arco-cli/legacy/dist/workspace/workspaceLocator';\n\nimport { ArcoAspect } from './arco.aspect';\nimport { ArcoMain } from './arco.main.runtime';\nimport { manifestMap } from './manifest';\n\n// add ArcoMain here to make sure every aspect in manifest is loaded\nArcoAspect.addRuntime(ArcoMain);\n\nexport async function requireAspects(aspect: Extension, runtime: RuntimeDefinition) {\n  const id = aspect.name;\n  if (!id) throw new Error('could not retrieve aspect id');\n\n  // resolve aspect packages from the dir where @arco-cli/arco located\n  // otherwise resolve.resolve can't find these packages\n  const resolveModuleFrom = path.resolve(__dirname, '../../..');\n  const { runtimePath } = await getAspectDef(id, runtime.name, resolveModuleFrom);\n\n  // eslint-disable-next-line\n  return runtimePath ? require(runtimePath) : null;\n}\n\nasync function getConfig(cwd = process.cwd()): Promise<Config> {\n  const workspaceInfo = await getWorkspaceInfo(cwd);\n  if (workspaceInfo) {\n    const configOpts: ConfigOptions = {\n      shouldThrow: false,\n      cwd: workspaceInfo?.path,\n    };\n    return Config.load(workspaceInfo.configFilename, configOpts);\n  }\n  return null;\n}\n\nasync function loadArco(path = process.cwd()) {\n  logger.info(`*** Loading arco *** argv:\\n${process.argv.join('\\n')}`);\n\n  const config = await getConfig();\n  const configMap = config ? config.toObject() : {};\n  configMap[ArcoAspect.id] ||= {};\n  configMap[ArcoAspect.id].cwd = path;\n\n  const stone = await Stone.load([CLIAspect, ArcoAspect], MainRuntime.name, configMap);\n  await stone.run(async (aspect: Extension, runtime: RuntimeDefinition) =>\n    requireAspects(aspect, runtime)\n  );\n\n  const aspectLoader = stone.get<AspectLoaderMain>(AspectLoaderAspect.id);\n  aspectLoader.setCoreAspects(Object.values(manifestMap));\n\n  return stone;\n}\n\nexport async function runCLI() {\n  const stone = await loadArco();\n  const cli = stone.get<CLIMain>(CLIAspect.id);\n  cli.run(false);\n}\n"
  },
  {
    "path": "packages/arco/src/manifest.ts",
    "content": "import { AspectLoaderAspect } from '@arco-cli/core/dist/aspect-loader';\nimport { LoggerAspect } from '@arco-cli/core/dist/logger';\nimport { PubsubAspect } from '@arco-cli/aspect/dist/pubsub';\nimport { ExpressAspect } from '@arco-cli/core/dist/express';\nimport { GraphqlAspect } from '@arco-cli/core/dist/graphql';\nimport { ComponentAspect } from '@arco-cli/aspect/dist/component';\nimport { EnvsAspect } from '@arco-cli/aspect/dist/envs';\nimport { ReactAspect } from '@arco-cli/react';\nimport { ReactRouterAspect } from '@arco-cli/aspect/dist/react-router';\nimport { BundlerAspect } from '@arco-cli/aspect/dist/bundler';\nimport { JestAspect } from '@arco-cli/aspect/dist/jest';\nimport { DocsAspect } from '@arco-cli/aspect/dist/docs';\nimport { WorkspaceAspect } from '@arco-cli/aspect/dist/workspace';\nimport { LessAspect } from '@arco-cli/aspect/dist/less';\nimport { SassAspect } from '@arco-cli/aspect/dist/sass';\nimport { MDXAspect } from '@arco-cli/aspect/dist/mdx';\nimport { UIAspect } from '@arco-cli/service/dist/ui';\nimport { PreviewAspect } from '@arco-cli/service/dist/preview';\nimport { TesterAspect } from '@arco-cli/service/dist/tester';\nimport { CompilerAspect } from '@arco-cli/service/dist/compiler';\nimport { BuilderAspect } from '@arco-cli/service/dist/builder';\nimport { SyncerAspect } from '@arco-cli/service/dist/syncer';\nimport { ForkAspect } from '@arco-cli/service/dist/fork';\nimport { GeneratorAspect } from '@arco-cli/service/dist/generator';\nimport { ArcoAspect } from './arco.aspect';\n\nexport const manifestMap = {\n  [AspectLoaderAspect.id]: AspectLoaderAspect,\n  [LoggerAspect.id]: LoggerAspect,\n  [PubsubAspect.id]: PubsubAspect,\n  [ExpressAspect.id]: ExpressAspect,\n  [GraphqlAspect.id]: GraphqlAspect,\n  [ComponentAspect.id]: ComponentAspect,\n  [EnvsAspect.id]: EnvsAspect,\n  [ReactAspect.id]: ReactAspect,\n  [ReactRouterAspect.id]: ReactRouterAspect,\n  [BundlerAspect.id]: BundlerAspect,\n  [JestAspect.id]: JestAspect,\n  [DocsAspect.id]: DocsAspect,\n  [LessAspect.id]: LessAspect,\n  [SassAspect.id]: SassAspect,\n  [WorkspaceAspect.id]: WorkspaceAspect,\n  [MDXAspect.id]: MDXAspect,\n  [UIAspect.id]: UIAspect,\n  [PreviewAspect.id]: PreviewAspect,\n  [CompilerAspect.id]: CompilerAspect,\n  [TesterAspect.id]: TesterAspect,\n  [BuilderAspect.id]: BuilderAspect,\n  [SyncerAspect.id]: SyncerAspect,\n  [ForkAspect.id]: ForkAspect,\n  [GeneratorAspect.id]: GeneratorAspect,\n};\n\nexport function isCoreAspect(id: string) {\n  const _reserved = [ArcoAspect.id];\n  if (_reserved.includes(id)) return true;\n  return !!manifestMap[id];\n}\n\nexport function getAllCoreAspectsIds(): string[] {\n  const _reserved = [ArcoAspect.id];\n  return [...Object.keys(manifestMap), ..._reserved];\n}\n"
  },
  {
    "path": "packages/arco/src/types.ts",
    "content": "import type { WorkspaceConfig } from '@arco-cli/aspect/dist/workspace';\nimport type { CompilerAspectConfig } from '@arco-cli/service/dist/compiler';\nimport type { GeneratorConfig } from '@arco-cli/service/dist/generator';\n\n/**\n * type of arco.workspace.json config\n */\nexport type ArcoWorkspaceFile = {\n  'arco.aspect/workspace'?: WorkspaceConfig;\n  'arco.service/compiler'?: CompilerAspectConfig;\n  'arco.service/generator'?: GeneratorConfig;\n};\n\n/**\n * type of arco.env.js config\n */\nexport type { ArcoEnvConfig } from '@arco-cli/aspect/dist/envs/types';\n"
  },
  {
    "path": "packages/arco/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"dist\",\n    \"paths\": {\n      \"@arco-cli/stone\": [\"../stone/src\"],\n      \"@arco-cli/stone/dist/*\": [\"../stone/src/*\"],\n      \"@arco-cli/react\": [\"../react/src\"],\n      \"@arco-cli/legacy/dist/*\": [\"../legacy/src/*\"],\n      \"@arco-cli/core/dist/*\": [\"../core/src/*\"],\n      \"@arco-cli/aspect/dist/*\": [\"../aspect/src/*\"],\n      \"@arco-cli/service/dist*\": [\"../service/src/*\"],\n      \"@arco-cli/ui-foundation-react\": [\"../ui-foundation-react/src\"],\n      \"@arco-cli/ui-foundation-react/dist/*\": [\"../ui-foundation-react/src/*\"]\n    }\n  }\n}\n"
  },
  {
    "path": "packages/aspect/package.json",
    "content": "{\n  \"name\": \"@arco-cli/aspect\",\n  \"version\": \"2.4.5\",\n  \"homepage\": \"https://github.com/arco-design/arco-cli\",\n  \"repository\": \"https://github.com/arco-design/arco-cli\",\n  \"main\": \"./dist/index.js\",\n  \"scripts\": {\n    \"dev\": \"sh ../../.scripts/build.sh dev\",\n    \"build\": \"sh ../../.scripts/build.sh\",\n    \"build-type\": \"sh ../../.scripts/build-type.sh\",\n    \"clean\": \"rm -rf dist\",\n    \"clean-type\": \"find dist -name *.d.ts |xargs rm -rf\",\n    \"prepublishOnly\": \"npm run build\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@apollo/client\": \"^3.7.2\",\n    \"@arco-cli/core\": \"^2.3.2\",\n    \"@arco-cli/legacy\": \"^2.3.2\",\n    \"@arco-cli/service\": \"^2.4.5\",\n    \"@arco-cli/stone\": \"^2.0.0-beta.0\",\n    \"@arco-cli/ui-foundation-react\": \"^2.4.5\",\n    \"@arco-design/web-react\": \"^2.42.2\",\n    \"@babel/runtime\": \"^7.20.6\",\n    \"@jest/test-result\": \"^29.5.0\",\n    \"@mdx-js/mdx\": \"^1.6.22\",\n    \"assert\": \"^2.0.0\",\n    \"browserify-zlib\": \"^0.2.0\",\n    \"buffer\": \"^6.0.3\",\n    \"chalk\": \"^4.1.2\",\n    \"chokidar\": \"^3.5.3\",\n    \"comment-json\": \"^4.2.3\",\n    \"compression-webpack-plugin\": \"^10.0.0\",\n    \"constants-browserify\": \"^1.0.0\",\n    \"crypto-browserify\": \"^3.12.0\",\n    \"domain-browser\": \"^4.22.0\",\n    \"enhanced-resolve\": \"^4.5.0\",\n    \"eventemitter2\": \"^6.4.9\",\n    \"fs-extra\": \"^10.1.0\",\n    \"glob\": \"^8.0.3\",\n    \"graphql-tag\": \"^2.12.6\",\n    \"html-webpack-plugin\": \"^5.5.0\",\n    \"https-browserify\": \"^1.0.0\",\n    \"less\": \"^4.1.3\",\n    \"loader-utils\": \"^3.2.1\",\n    \"lodash\": \"^4.17.21\",\n    \"lodash-es\": \"^4.17.21\",\n    \"minimatch\": \"^6.1.6\",\n    \"os-browserify\": \"^0.3.0\",\n    \"p-map-series\": \"^2.1.0\",\n    \"p-queue\": \"^6.6.2\",\n    \"path-browserify\": \"^1.0.1\",\n    \"penpal\": \"^6.2.2\",\n    \"process\": \"^0.11.10\",\n    \"punycode\": \"^2.1.1\",\n    \"querystring-es3\": \"^0.2.1\",\n    \"react-dev-utils\": \"^12.0.1\",\n    \"remark-admonitions\": \"^1.2.1\",\n    \"remark-frontmatter\": \"^2.0.0\",\n    \"reset-css\": \"^5.0.1\",\n    \"sass\": \"^1.57.0\",\n    \"semver\": \"^7.3.8\",\n    \"speed-measure-webpack-plugin\": \"^1.5.0\",\n    \"stream-browserify\": \"^3.0.0\",\n    \"stream-http\": \"^3.2.0\",\n    \"string_decoder\": \"^1.3.0\",\n    \"timers-browserify\": \"^2.0.12\",\n    \"tty-browserify\": \"^0.0.1\",\n    \"typescript\": \"^4.9.3\",\n    \"unist-util-remove\": \"^2.1.0\",\n    \"unist-util-visit\": \"^2.0.3\",\n    \"url\": \"^0.11.0\",\n    \"util\": \"^0.12.5\",\n    \"vfile\": \"^4.2.1\",\n    \"vm-browserify\": \"^1.1.2\",\n    \"webpack\": \"^5.75.0\",\n    \"webpack-assets-manifest\": \"^5.1.0\",\n    \"webpack-dev-server\": \"^4.11.1\",\n    \"webpack-merge\": \"^5.8.0\",\n    \"yaml\": \"^1.10.2\"\n  },\n  \"devDependencies\": {\n    \"@types/glob\": \"^8.0.1\",\n    \"@types/less\": \"^3.0.3\"\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/bundler/browserRuntime.ts",
    "content": "import { ExecutionContext } from '@aspect/envs';\n\nexport type BrowserRuntime = {\n  entry: (context: ExecutionContext) => Promise<string[]>;\n};\n"
  },
  {
    "path": "packages/aspect/src/bundler/bundler.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const BundlerAspect = Aspect.create({\n  id: 'arco.aspect/bundler',\n});\n\nexport default BundlerAspect;\n"
  },
  {
    "path": "packages/aspect/src/bundler/bundler.main.runtime.ts",
    "content": "import { MainRuntime } from '@arco-cli/core/dist/cli';\nimport { Slot, SlotRegistry } from '@arco-cli/stone';\nimport { GraphqlAspect, GraphqlMain } from '@arco-cli/core/dist/graphql';\n\nimport { EnvsAspect, EnvsMain } from '@aspect/envs';\nimport { ComponentAspect, Component } from '@aspect/component';\n\nimport { BundlerAspect } from './bundler.aspect';\nimport { BrowserRuntime } from './browserRuntime';\nimport { DevServerService } from './devServer.service';\nimport { ComponentServer } from './componentServer';\nimport getDevServerSchema from './devServer.graphql';\n\nexport type BrowserRuntimeSlot = SlotRegistry<BrowserRuntime>;\n\nexport class BundlerMain {\n  static runtime = MainRuntime;\n\n  static dependencies = [EnvsAspect, GraphqlAspect, ComponentAspect];\n\n  static slots = [Slot.withType<BrowserRuntime>()];\n\n  static async provider(\n    [envs, graphql]: [EnvsMain, GraphqlMain],\n    _config,\n    [runtimeSlot]: [BrowserRuntimeSlot]\n  ) {\n    const devServerService = new DevServerService(runtimeSlot);\n    const bundler = new BundlerMain(envs, runtimeSlot, devServerService);\n    graphql.register(getDevServerSchema(bundler));\n    return bundler;\n  }\n\n  constructor(\n    private envs: EnvsMain,\n    private runtimeSlot: BrowserRuntimeSlot,\n    private devService: DevServerService\n  ) {}\n\n  private componentServers: ComponentServer[] = [];\n\n  /**\n   * register a new browser runtime environment.\n   */\n  registerTarget(runtime: BrowserRuntime) {\n    this.runtimeSlot.register(runtime);\n    return this;\n  }\n\n  async devServer(components: Component[]): Promise<ComponentServer[]> {\n    const envRuntime = await this.envs.createEnvironment(components);\n    const servers: ComponentServer[] = await envRuntime.runOnce<ComponentServer[]>(this.devService);\n    this.componentServers = servers;\n    return servers;\n  }\n\n  /**\n   * get a dev server instance containing a component.\n   * @param component\n   */\n  getComponentServer(component: Component): undefined | ComponentServer {\n    const envId = component.env;\n    const server = this.componentServers.find(\n      (componentServer) =>\n        componentServer.context.relatedContexts.includes(envId) ||\n        componentServer.context.id === envId\n    );\n    return server;\n  }\n}\n\nBundlerAspect.addRuntime(BundlerMain);\n"
  },
  {
    "path": "packages/aspect/src/bundler/bundler.ts",
    "content": "import { Component } from '@aspect/component';\n\nexport type Asset = {\n  /**\n   * name of the asset.\n   */\n  name: string;\n\n  /**\n   * size of the asset in bytes.\n   */\n  size: number;\n\n  /**\n   * size of the compressed asset in bytes.\n   */\n  compressedSize?: number;\n};\n\nexport type Chunk = {\n  runtime: string[];\n  files: string[];\n  auxiliaryFiles: string[];\n};\n\nexport type ChunksAssetsMap = {\n  [assetName: string]: string[];\n};\n\nexport type EntryAssets = {\n  assets: Asset[];\n  auxiliaryAssets: Asset[];\n  assetsSize: number;\n  compressedAssetsSize?: number;\n  auxiliaryAssetsSize: number;\n  compressedAuxiliaryAssetsSize: number;\n};\n\nexport type EntriesAssetsMap = {\n  [entryId: string]: EntryAssets;\n};\n\nexport type BundlerResult = {\n  /**\n   * list of generated assets.\n   */\n  assets: Asset[];\n\n  /**\n   * A map of assets names for each chunk\n   */\n  assetsByChunkName?: ChunksAssetsMap;\n\n  /**\n   * A map of assets for each entry point\n   */\n  entriesAssetsMap?: EntriesAssetsMap;\n\n  /**\n   * Chunks info for built assets\n   */\n  chunks?: Chunk[];\n\n  /**\n   * errors thrown during the bundling process.\n   */\n  errors: Error[];\n\n  /**\n   * warnings thrown during the bundling process.\n   */\n  warnings: string[];\n\n  /**\n   * components included in the bundling process.\n   */\n  components: Component[];\n\n  /**\n   * timestamp in milliseconds when the task started\n   */\n  startTime?: number;\n\n  /**\n   * timestamp in milliseconds when the task ended\n   */\n  endTime?: number;\n\n  /**\n   * out put path of the Bundler Result\n   */\n  outputPath?: string;\n};\n\nexport interface Bundler {\n  run(): Promise<BundlerResult[]>;\n}\n\nexport type BundlerMode = 'dev' | 'prod';\n"
  },
  {
    "path": "packages/aspect/src/bundler/bundlerContext.ts",
    "content": "import { BuildContext } from '@arco-cli/service/dist/builder';\n\nimport { Component } from '@aspect/component';\n\nexport type LibraryOptions = {\n  /**\n   * Specify a name for the library\n   */\n  name: string;\n\n  /**\n   * Configure how the library will be exposed\n   * could be values like: 'umd', 'umd2', 'amd', 'commonjs',\n   */\n  type?: string;\n};\n\nexport type Chunking = {\n  /**\n   * include all types of chunks (async / non-async) in splitting\n   */\n  splitChunks: boolean;\n};\n\nexport type MetaData = {\n  /**\n   * Who initiate the bundling process\n   */\n  initiator?: string;\n  /**\n   * Env id (used usually to calculate the config)\n   */\n  envId?: string;\n};\n\nexport type HtmlConfig = {\n  /**\n   * The title to use for the generated HTML document\n   */\n  title: string;\n  /**\n   * The file to write the HTML to. Defaults to index.html\n   */\n  filename?: string;\n  /**\n   * Allows you to add only some chunks (e.g only the unit-test chunk)\n   */\n  chunks?: string[];\n  /**\n   * Load chunks according to their order in the `chunks` array\n   * @default auto\n   */\n  chunkOrder?: 'auto' | 'manual';\n  /**\n   * provide an inline template\n   */\n  templateContent: string;\n  /**\n   * Controls if and in what ways the output should be minified\n   */\n  minify?: boolean;\n\n  /**\n   * The favicon for the html page\n   */\n  favicon?: string;\n};\n\nexport type Entry = {\n  /**\n   * Specifies the name of each output file on disk\n   */\n  filename: string;\n  /**\n   * Module(s) that are loaded upon startup\n   */\n  import: string | string[];\n\n  /**\n   * Specify library options to bundle a library from current entry\n   */\n  library?: LibraryOptions;\n};\n\nexport type EntryMap = {\n  [entryName: string]: Entry;\n};\n\nexport type ModuleTarget = {\n  /**\n   * name of the module.\n   */\n  name: string;\n\n  /**\n   * module exposes.\n   */\n  exposes: {\n    [internalPath: string]: string;\n  };\n\n  shared: {\n    [key: string]: any;\n  };\n};\n\nexport type Target = {\n  /**\n   * entries of the target.\n   */\n  entries: string[] | EntryMap;\n\n  /**\n   * array of components included in the target.\n   */\n  components: Component[];\n\n  /**\n   * output path of the target\n   */\n  outputPath: string;\n\n  /**\n   * This option determines the name of each output bundle\n   */\n  filename?: string;\n\n  /**\n   * This option determines the name of non-initial chunk files\n   */\n  chunkFilename?: string;\n\n  /**\n   * Whether to run compression by the bundler\n   */\n  compress?: boolean;\n\n  /**\n   * List of peer dependencies\n   */\n  peers?: string[];\n\n  /**\n   * config for html generation\n   */\n  html?: HtmlConfig[];\n\n  /**\n   * module targets to expose.\n   */\n  modules?: ModuleTarget[];\n\n  /**\n   * Name for the runtime chunk\n   */\n  runtimeChunkName?: string;\n\n  /**\n   * Different configuration related to chunking\n   */\n  chunking?: Chunking;\n\n  /**\n   * A path for the host root dir\n   * Host root dir is usually the env root dir\n   * This can be used in different bundle options which run require.resolve\n   * for example when configuring webpack aliases or webpack expose loader on the peers deps\n   */\n  hostRootDir?: string;\n};\n\nexport interface BundlerContext extends BuildContext {\n  /**\n   * all components about to be build\n   */\n  components: Component[];\n\n  /**\n   * targets for bundling.\n   */\n  targets: Target[];\n\n  /**\n   * determines whether it is a production build, default is `true`.\n   * in development, expect the bundler to favour debugging on the expanse of optimization.\n   */\n  development?: boolean;\n\n  /**\n   * public path output of the bundle.\n   */\n  publicPath?: string;\n\n  /**\n   * root path\n   */\n  rootPath?: string;\n\n  /**\n   * Whether to run compression by the bundler\n   */\n  compress?: boolean;\n\n  /**\n   * config for html generation for all targets\n   */\n  html?: HtmlConfig[];\n\n  /**\n   * modules for bundle to expose. used by module federation at webpack, or with different methods applied by various bundlers.\n   */\n  modules?: {\n    name: string;\n    fileName: string;\n    exposes: { [key: string]: string };\n  };\n\n  /**\n   * Additional info that can be used by the bundler for different stuff like logging info\n   */\n  metaData?: MetaData;\n}\n"
  },
  {
    "path": "packages/aspect/src/bundler/componentServer.ts",
    "content": "import { AddressInfo } from 'net';\nimport { Port } from '@arco-cli/legacy/dist/utils/network/port';\nimport { ExecutionContext } from '@aspect/envs';\nimport { DevServer } from './devServer';\nimport { BindError } from './exceptions';\n\nexport class ComponentServer {\n  errors?: Error[];\n\n  private _port: number;\n\n  constructor(\n    /**\n     * components contained in the existing component server.\n     */\n    readonly context: ExecutionContext,\n\n    /**\n     * port range of the component server.\n     */\n    readonly portRange: number[],\n\n    /**\n     * env dev server.\n     */\n    readonly devServer: DevServer\n  ) {}\n\n  hostname: string | undefined;\n\n  private async selectPort(portRange?: number[] | number) {\n    return Port.getPortFromRange(portRange || [3100, 3200]);\n  }\n\n  private getHostname(address: string | AddressInfo | null) {\n    if (address === null) throw new BindError();\n    if (typeof address === 'string') return address;\n\n    let hostname = address.address;\n    if (hostname === '::') {\n      hostname = 'localhost';\n    }\n\n    return hostname;\n  }\n\n  get port() {\n    return this._port;\n  }\n\n  /**\n   * get the url of the component server.\n   */\n  get url() {\n    // tailing `/` is required!\n    return `/preview/${this.context.envRuntime.id}/`;\n  }\n\n  async listen() {\n    const port = await this.selectPort(this.portRange);\n    this._port = port;\n    const server = await this.devServer.listen(port);\n    const address = server.address();\n    const hostname = this.getHostname(address);\n    if (!address) throw new BindError();\n    this.hostname = hostname;\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/bundler/dedupEnvs.ts",
    "content": "import type { ExecutionContext } from '@aspect/envs';\n\ntype GroupIdContextMap = Record<string, ExecutionContext[]>;\n\n/**\n * de-duping dev servers by the amount of type the dev server configuration was overridden by envs.\n * This will split the dev server to groups of dev server that share the same webpack config\n */\nexport function dedupEnvs(contexts: ExecutionContext[]) {\n  const groupedEnvs: GroupIdContextMap = {};\n\n  contexts.forEach((context) => {\n    const envId = context.env?.getDevEnvId(context);\n    if (!envId) return;\n    if (!(envId in groupedEnvs)) groupedEnvs[envId] = [];\n    groupedEnvs[envId].push(context);\n  });\n\n  return groupedEnvs;\n}\n"
  },
  {
    "path": "packages/aspect/src/bundler/devServer.graphql.ts",
    "content": "import gql from 'graphql-tag';\n\nimport { Component } from '@aspect/component';\n\nimport { BundlerMain } from './bundler.main.runtime';\n\nexport default function (bundler: BundlerMain) {\n  return {\n    typeDefs: gql`\n      extend type Component {\n        server: ComponentServer\n      }\n\n      type ComponentServer {\n        env: String\n        url: String\n      }\n    `,\n    resolvers: {\n      Component: {\n        server: (component: Component) => {\n          const componentServer = bundler.getComponentServer(component);\n          return componentServer\n            ? {\n                env: componentServer.context.envRuntime.id,\n                url: componentServer.url,\n              }\n            : {};\n        },\n      },\n    },\n  };\n}\n"
  },
  {
    "path": "packages/aspect/src/bundler/devServer.service.ts",
    "content": "import { sep } from 'path';\nimport { flatten } from 'lodash';\n\nimport { EnvService, ExecutionContext, EnvDefinition } from '@aspect/envs';\n\nimport { BrowserRuntimeSlot } from './bundler.main.runtime';\nimport { ComponentServer } from './componentServer';\nimport { dedupEnvs } from './dedupEnvs';\nimport { DevServer } from './devServer';\nimport { DevServerContext } from './devServerContext';\nimport { getEntry } from './getEntry';\n\nexport type DevServerDescriptor = {\n  /**\n   * id of the dev server (e.g. jest/mocha)\n   */\n  id: string;\n\n  /**\n   * display name of the dev server (e.g. Jest / Mocha)\n   */\n  displayName: string;\n\n  /**\n   * string containing the config for display.\n   */\n  config: string;\n\n  version?: string;\n};\n\nexport class DevServerService implements EnvService<ComponentServer, DevServerDescriptor> {\n  name = 'dev server';\n\n  constructor(\n    /**\n     * browser runtime slot\n     */\n    private runtimeSlot: BrowserRuntimeSlot\n  ) {}\n\n  private getComponentsFromContexts(contexts: ExecutionContext[]) {\n    return flatten(\n      contexts.map((context) => {\n        return context.components;\n      })\n    );\n  }\n\n  /**\n   * builds the execution context for the dev server.\n   */\n  private async buildContext(\n    context: ExecutionContext,\n    additionalContexts: ExecutionContext[] = []\n  ): Promise<DevServerContext> {\n    context.relatedContexts = additionalContexts.map((ctx) => ctx.envDefinition.id);\n    context.components = context.components.concat(\n      this.getComponentsFromContexts(additionalContexts)\n    );\n\n    return Object.assign(context, {\n      entry: await getEntry(context, this.runtimeSlot),\n      // don't start with a leading \"/\" because it generates errors on Windows\n      rootPath: `preview/${context.envRuntime.id}`,\n      publicPath: `${sep}public`,\n    });\n  }\n\n  async getDescriptor(\n    environment: EnvDefinition,\n    context?: ExecutionContext[]\n  ): Promise<DevServerDescriptor | undefined> {\n    if (!environment.env.getDevServer || !context) return undefined;\n    const mergedContext = await this.buildContext(context[0], []);\n    const devServer: DevServer = environment.env.getDevServer(mergedContext);\n\n    return {\n      id: devServer.id || '',\n      displayName: devServer.displayName || '',\n      config: devServer.displayConfig ? devServer.displayConfig() : '',\n      version: devServer.version ? devServer.version() : '?',\n    };\n  }\n\n  async runOnce(contexts: ExecutionContext[]): Promise<ComponentServer[]> {\n    const groupedEnvs = await dedupEnvs(contexts);\n\n    const servers = await Promise.all(\n      Object.entries(groupedEnvs).map(async ([id, contextList]) => {\n        const mainContext =\n          contextList.find((context) => context.envDefinition.id === id) || contextList[0];\n        const additionalContexts = contextList.filter((context) => context.envDefinition.id !== id);\n\n        const devServerContext = await this.buildContext(mainContext, additionalContexts);\n        const devServer: DevServer = await devServerContext.envRuntime.env.getDevServer(\n          devServerContext\n        );\n\n        return new ComponentServer(devServerContext, [3300, 3400], devServer);\n      })\n    );\n\n    return servers;\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/bundler/devServer.ts",
    "content": "import { Server } from 'http';\n\n/**\n * interface for implementing dev servers.\n */\nexport interface DevServer {\n  /**\n   * attach to given port and start an http server\n   */\n  listen(port: number): Server | Promise<Server>;\n\n  /**\n   * display name of the dev-server.\n   */\n  displayName?: string;\n\n  /**\n   * icon of the dev-server.\n   */\n  icon?: string;\n\n  /**\n   * serialized config of the dev-server.\n   */\n  displayConfig?(): string;\n\n  /**\n   * path to the config in the filesystem.\n   */\n  configPath?: string;\n\n  /**\n   * id of the dev-server.\n   */\n  id: string;\n\n  /**\n   * return the dev-server version.\n   */\n  version?(): string;\n}\n"
  },
  {
    "path": "packages/aspect/src/bundler/devServerContext.ts",
    "content": "import { ExecutionContext } from '@aspect/envs';\n\nexport interface DevServerContext extends ExecutionContext {\n  /**\n   * array of files to include.\n   */\n  entry: string[];\n\n  /**\n   * public path.\n   */\n  publicPath: string;\n\n  /**\n   * root path of the workspace.\n   */\n  rootPath: string;\n\n  /**\n   * title of the page.\n   */\n  title?: string;\n\n  /**\n   * favicon of the page.\n   */\n  favicon?: string;\n}\n"
  },
  {
    "path": "packages/aspect/src/bundler/exceptions/bindError.ts",
    "content": "export class BindError extends Error {}\n"
  },
  {
    "path": "packages/aspect/src/bundler/exceptions/index.ts",
    "content": "export { BindError } from './bindError';\n"
  },
  {
    "path": "packages/aspect/src/bundler/getEntry.ts",
    "content": "import { ExecutionContext } from '@aspect/envs';\n\nimport { BrowserRuntimeSlot } from './bundler.main.runtime';\n\n/**\n * computes the bundler entry.\n */\nexport async function getEntry(\n  context: ExecutionContext,\n  runtimeSlot: BrowserRuntimeSlot\n): Promise<string[]> {\n  const slotEntries = await Promise.all(\n    runtimeSlot.values().map(async (browserRuntime) => browserRuntime.entry(context))\n  );\n\n  const slotPaths = slotEntries.reduce((acc, current) => {\n    acc = acc.concat(current);\n    return acc;\n  });\n\n  return slotPaths;\n}\n"
  },
  {
    "path": "packages/aspect/src/bundler/index.ts",
    "content": "import { BundlerAspect } from './bundler.aspect';\n\nexport default BundlerAspect;\nexport { BundlerAspect };\nexport { DevServer } from './devServer';\nexport type { BundlerMain } from './bundler.main.runtime';\nexport type { DevServerContext } from './devServerContext';\nexport { ComponentServer } from './componentServer';\n\nexport {\n  Bundler,\n  BundlerResult,\n  BundlerMode,\n  Asset,\n  Chunk,\n  ChunksAssetsMap,\n  EntriesAssetsMap,\n  EntryAssets,\n} from './bundler';\n\nexport {\n  BundlerContext,\n  Target,\n  ModuleTarget,\n  HtmlConfig as BundlerHtmlConfig,\n  EntryMap as BundlerEntryMap,\n  Entry as BundlerEntry,\n  MetaData as BundlerContextMetaData,\n} from './bundlerContext';\n"
  },
  {
    "path": "packages/aspect/src/component/component.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const ComponentAspect = Aspect.create({\n  id: 'arco.aspect/component',\n});\n\nexport default ComponentAspect;\n"
  },
  {
    "path": "packages/aspect/src/component/component.graphql.ts",
    "content": "import gql from 'graphql-tag';\nimport type { Component } from './component';\nimport { ComponentMain } from './component.main.runtime';\nimport { ComponentFactory } from './componentFactory';\n\nexport default function (componentExtension: ComponentMain) {\n  return {\n    typeDefs: gql`\n      type Component {\n        # id of the component.\n        id: String!\n\n        # display name of the component\n        name: String!\n\n        # labels of the component\n        labels: [String]!\n\n        # package name of the component\n        packageName: String!\n\n        # version of the component\n        version: String!\n\n        # author of the component\n        author: String!\n\n        # additional styles of the component\n        extraStyles: [ComponentExtraStyles]!\n      }\n\n      type ComponentExtraStyles {\n        title: String\n        href: String\n      }\n\n      type ComponentHost {\n        id: String!\n        name: String!\n\n        # load a component.\n        get(id: String!): Component\n\n        # list components\n        list(offset: Int, limit: Int): [Component]!\n      }\n\n      type Query {\n        getHost(id: String): ComponentHost\n      }\n    `,\n    resolvers: {\n      Component: {\n        id: (component: Component) => component.id,\n        name: (component: Component) => component.name,\n        labels: (component: Component) => component.labels,\n        version: (component: Component) => component.version,\n        packageName: (component: Component) => component.packageName,\n        author: (component: Component) => component.author,\n      },\n      ComponentHost: {\n        id: async (host: ComponentFactory) => {\n          return host.name;\n        },\n        name: async (host: ComponentFactory) => {\n          return host.name;\n        },\n        list: async (host: ComponentFactory) => {\n          return host.list();\n        },\n        get: async (host: ComponentFactory, { id }: { id: string }) => {\n          try {\n            const component = await host.get(id);\n            return component;\n          } catch (error: any) {\n            return null;\n          }\n        },\n      },\n      Query: {\n        getHost: () => {\n          return componentExtension.getHost();\n        },\n      },\n    },\n  };\n}\n"
  },
  {
    "path": "packages/aspect/src/component/component.main.runtime.ts",
    "content": "import { Slot, SlotRegistry } from '@arco-cli/stone';\nimport { MainRuntime } from '@arco-cli/core/dist/cli';\nimport { GraphqlAspect, GraphqlMain } from '@arco-cli/core/dist/graphql';\n\nimport ComponentAspect from './component.aspect';\nimport { ComponentFactory } from './componentFactory';\nimport { HostNotFoundError } from './exceptions';\nimport getComponentSchema from './component.graphql';\n\nexport type ComponentHostSlot = SlotRegistry<ComponentFactory>;\n\nexport class ComponentMain {\n  static runtime = MainRuntime;\n\n  static slots = [Slot.withType<ComponentFactory>()];\n\n  static dependencies = [GraphqlAspect];\n\n  static provider([graphql]: [GraphqlMain], _config, [hostSlot]: [ComponentHostSlot]) {\n    const componentMain = new ComponentMain(hostSlot);\n    graphql.register(getComponentSchema(componentMain));\n    return componentMain;\n  }\n\n  private _priorHost: ComponentFactory | undefined;\n\n  constructor(private hostSlot: ComponentHostSlot) {}\n\n  private getPriorHost() {\n    if (this._priorHost) return this._priorHost;\n    const hosts = this.hostSlot.values();\n    return hosts[0];\n  }\n\n  registerHost(host: ComponentFactory) {\n    this.hostSlot.register(host);\n    return this;\n  }\n\n  getHost(id?: string): ComponentFactory {\n    if (id) {\n      const host = this.hostSlot.get(id);\n      if (!host) throw new HostNotFoundError(id);\n      return host;\n    }\n\n    return this.getPriorHost();\n  }\n}\n\nComponentAspect.addRuntime(ComponentMain);\n"
  },
  {
    "path": "packages/aspect/src/component/component.ts",
    "content": "import fs from 'fs-extra';\nimport path from 'path';\nimport { SourceFile } from '@arco-cli/legacy/dist/workspace/component/sources';\nimport { ComponentInfo } from '@arco-cli/legacy/dist/workspace/componentInfo';\nimport { DEFAULT_ENV } from '@arco-cli/legacy/dist/constants';\nimport { ComponentNotFoundInPathError } from '@arco-cli/legacy/dist/workspace/component/exceptions';\n\nimport { ExtensionDataEntry, ExtensionDataList } from './extensionData';\n\nexport class Component {\n  public extensions: ExtensionDataList = new ExtensionDataList();\n\n  constructor(private info: ComponentInfo, public files: SourceFile[] = []) {}\n\n  get id() {\n    return this.info.id;\n  }\n\n  get name() {\n    return this.info.name;\n  }\n\n  get group() {\n    return this.info.group;\n  }\n\n  get author() {\n    return this.info.author;\n  }\n\n  get labels() {\n    return this.info.labels;\n  }\n\n  get env() {\n    return DEFAULT_ENV;\n  }\n\n  get language() {\n    return 'javascript';\n  }\n\n  get version() {\n    return this.info.version;\n  }\n\n  get packageName() {\n    return this.info.packageName;\n  }\n\n  get dependencies() {\n    return this.info.dependencies;\n  }\n\n  get devDependencies() {\n    return this.info.devDependencies;\n  }\n\n  get peerDependencies() {\n    return this.info.peerDependencies;\n  }\n\n  get rootDir() {\n    return this.info.rootDir;\n  }\n\n  get componentDir() {\n    return path.join(this.info.rootDir, this.entries.base);\n  }\n\n  get packageDir() {\n    return this.info.packageDir;\n  }\n\n  get packageDirAbs() {\n    return this.info.packageDirAbs;\n  }\n\n  get entries() {\n    return this.info.entries;\n  }\n\n  get repository() {\n    return this.info.repository;\n  }\n\n  get uiResource() {\n    return this.info.uiResource;\n  }\n\n  get extraStyles() {\n    return this.info.extraStyles;\n  }\n\n  get forkable() {\n    return this.info.forkable;\n  }\n\n  get rawConfig() {\n    return this.info.rawConfig;\n  }\n\n  async upsertExtensionData(extension: string, data: Record<string, any>) {\n    if (!data) return;\n    const existingExtension = this.extensions.findExtension(extension);\n    if (existingExtension) {\n      // Only merge top level of extension data\n      Object.assign(existingExtension.data, data);\n    } else {\n      this.extensions.push(await new ExtensionDataEntry(extension, undefined, data));\n    }\n  }\n\n  static async loadFromFileSystem(info: ComponentInfo, projectPath: string) {\n    const rootDirAbs = path.join(projectPath, info.rootDir);\n    if (!fs.existsSync(rootDirAbs)) throw new ComponentNotFoundInPathError(rootDirAbs);\n\n    const files = info.files.map((file) => {\n      const filePath = path.join(rootDirAbs, file.relativePath);\n      return SourceFile.load(filePath, rootDirAbs, projectPath, {\n        test: file.test,\n      });\n    });\n\n    return new Component(info, files);\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/component/componentFactory.ts",
    "content": "import { AspectDefinition } from '@arco-cli/core/dist/aspect-loader';\nimport { Component } from './component';\n\nexport interface ComponentFactory {\n  /**\n   * name of the component host.\n   */\n  name: string;\n\n  /**\n   * path to the component host.\n   */\n  path: string;\n\n  /**\n   * returns a component by id.\n   */\n  get(id: string): Promise<Component | undefined>;\n\n  /**\n   * returns many components by ids.\n   */\n  getMany(ids: string[]): Promise<Component[]>;\n\n  /**\n   * get component-ids matching the given pattern. a pattern can have multiple patterns separated by a comma.\n   * it uses multimatch (https://www.npmjs.com/package/multimatch) package for the matching algorithm, which supports\n   * (among others) negate character \"!\" to exclude ids. See the package page for more supported characters.\n   */\n  getManyByPattern(pattern: string, throwForNoMatch?: boolean): Promise<Component[]>;\n\n  /**\n   * list all components in the host.\n   */\n  list(): Promise<Component[]>;\n\n  /**\n   * resolve dirs for aspects\n   */\n  resolveAspects: (runtimeName?: string) => Promise<AspectDefinition[]>;\n}\n"
  },
  {
    "path": "packages/aspect/src/component/componentMap.ts",
    "content": "import { Component } from './component';\n\n/**\n * allows to index components -> values.\n */\nexport class ComponentMap<T> {\n  constructor(readonly hashMap: Map<string, [Component, T]>) {}\n\n  get components() {\n    return this.toArray().map(([component]) => component);\n  }\n\n  /**\n   * get a value for a component.\n   */\n  get(component: Component) {\n    return this.hashMap.get(component.id);\n  }\n\n  /**\n   * get a value by the component-id\n   */\n  getValueByComponentId(componentId: string): T | null {\n    const tuple = this.hashMap.get(componentId);\n    if (!tuple) return null;\n    return tuple[1];\n  }\n\n  /**\n   * returns an array.\n   */\n  toArray() {\n    return Array.from(this.hashMap.values());\n  }\n\n  /**\n   * map entries and return a new component map.\n   */\n  map<NewType>(predicate: (value: T, component: Component) => NewType): ComponentMap<NewType> {\n    const tuples: [string, [Component, NewType]][] = this.toArray().map(([component, value]) => {\n      const newValue = predicate(value, component);\n      return [component.id, [component, newValue]];\n    });\n\n    return new ComponentMap(new Map(tuples));\n  }\n\n  /**\n   * similar to Array.forEach, but here you get both, the value and the component.\n   */\n  forEach(predicate: (value: T, component: Component) => void): void {\n    this.toArray().forEach(([component, value]) => {\n      predicate(value, component);\n    });\n  }\n\n  /**\n   * flatten values of all components into a single array.\n   */\n  flattenValue(): T[] {\n    return this.toArray().reduce((acc: T[], [, value]) => {\n      acc = acc.concat(value);\n      return acc;\n    }, []);\n  }\n\n  /**\n   * filter all components with empty values and return a new map.\n   */\n  filter(predicate: (value: T) => boolean): ComponentMap<T> {\n    const tuples = this.toArray().filter(([, value]) => {\n      return predicate(value);\n    });\n\n    const asMap: [string, [Component, T]][] = tuples.map(([component, value]) => {\n      return [component.id, [component, value]];\n    });\n\n    return new ComponentMap(new Map(asMap));\n  }\n\n  /**\n   * get all component ids.\n   */\n  keys() {\n    return this.hashMap.keys();\n  }\n\n  static create<U>(rawMap: [Component, U][]) {\n    const newMap: [string, [Component, U]][] = rawMap.map(([component, data]) => {\n      return [component.id, [component, data]];\n    });\n    return new ComponentMap(new Map(newMap));\n  }\n\n  /**\n   * create a component map from components and a value predicate.\n   * @param components components to zip into the map.\n   * @param predicate predicate for returning desired value.\n   */\n  static as<U>(components: Component[], predicate: (component: Component) => U): ComponentMap<U> {\n    const tuples: [string, [Component, U]][] = components.map((component) => {\n      return [component.id, [component, predicate(component)]];\n    });\n\n    return new ComponentMap(new Map(tuples));\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/component/exceptions/hostNotFoundError.ts",
    "content": "export class HostNotFoundError extends Error {\n  constructor(private hostName: string) {\n    super();\n  }\n\n  toString() {\n    return `[component] error: host '${this.hostName}' was not found`;\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/component/exceptions/index.ts",
    "content": "export { HostNotFoundError } from './hostNotFoundError';\nexport { InvalidNameError } from './invalidNameError';\nexport { InvalidVersionError } from './invalidVersionError';\n"
  },
  {
    "path": "packages/aspect/src/component/exceptions/invalidNameError.ts",
    "content": "export class InvalidNameError extends Error {\n  componentName: string;\n\n  constructor(componentName: string) {\n    super(\n      `error: \"${componentName}\" is invalid, component names can only contain alphanumeric, lowercase characters, and the following [\"-\", \"_\", \"$\", \"!\", \"/\"]`\n    );\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/component/exceptions/invalidVersionError.ts",
    "content": "export class InvalidVersionError extends Error {\n  version: string | null | undefined;\n\n  constructor(version?: string | null) {\n    super(\n      `error: version ${\n        version || '(empty)'\n      } is not a valid semantic version. learn more: https://semver.org`\n    );\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/component/extensionData.ts",
    "content": "import { cloneDeep, compact, isEmpty } from 'lodash';\n\ntype RemoveExtensionSpecialSign = '-';\n\ntype ExtensionConfig = { [extName: string]: any } | RemoveExtensionSpecialSign;\n\ntype ConfigOnlyEntry = {\n  id: string;\n  config: ExtensionConfig;\n};\n\nexport const REMOVE_EXTENSION_SPECIAL_SIGN = '-';\n\nexport class ExtensionDataEntry {\n  constructor(\n    public extensionId?: string,\n    public rawConfig: ExtensionConfig = {},\n    public data: { [key: string]: any } = {}\n  ) {}\n\n  get config(): { [key: string]: any } {\n    if (this.rawConfig === REMOVE_EXTENSION_SPECIAL_SIGN) return {};\n    return this.rawConfig;\n  }\n\n  set config(val: { [key: string]: any }) {\n    this.rawConfig = val;\n  }\n\n  get isRemoved(): boolean {\n    return this.rawConfig === REMOVE_EXTENSION_SPECIAL_SIGN;\n  }\n\n  toObject() {\n    return {\n      extensionId: this.extensionId,\n      // Do not use raw config here\n      config: this.config,\n      data: this.data,\n    };\n  }\n\n  clone(): ExtensionDataEntry {\n    return new ExtensionDataEntry(\n      this.extensionId,\n      cloneDeep(this.rawConfig),\n      cloneDeep(this.data)\n    );\n  }\n}\n\nexport class ExtensionDataList extends Array<ExtensionDataEntry> {\n  static coreExtensionsNames: Map<string, string> = new Map();\n\n  static registerCoreExtensionName(name: string) {\n    ExtensionDataList.coreExtensionsNames.set(name, '');\n  }\n\n  static registerManyCoreExtensionNames(names: string[]) {\n    names.forEach((name) => {\n      ExtensionDataList.coreExtensionsNames.set(name, '');\n    });\n  }\n\n  get ids(): string[] {\n    return this.map((entry) => entry.extensionId);\n  }\n\n  findExtension(extensionId: string): ExtensionDataEntry | undefined {\n    return this.find((extEntry) => extEntry.extensionId === extensionId);\n  }\n\n  remove(id) {\n    return ExtensionDataList.fromArray(\n      this.filter((entry) => {\n        return entry.extensionId !== id;\n      })\n    );\n  }\n\n  toConfigObject() {\n    const res = {};\n    this.forEach((entry) => {\n      if (entry.rawConfig && !isEmpty(entry.rawConfig)) {\n        res[entry.extensionId] = entry.rawConfig;\n      }\n    });\n    return res;\n  }\n\n  toConfigArray(): ConfigOnlyEntry[] {\n    const arr = this.map((entry) => {\n      // Remove extensions without config\n      const clonedEntry = entry.clone();\n      if (clonedEntry.rawConfig && !isEmpty(clonedEntry.rawConfig)) {\n        return isEmpty(clonedEntry.rawConfig)\n          ? null\n          : { id: clonedEntry.extensionId, config: clonedEntry.config };\n      }\n      return null;\n    });\n    return compact(arr);\n  }\n\n  clone(): ExtensionDataList {\n    const extensionDataEntries = this.map((extensionData) => extensionData.clone());\n    return new ExtensionDataList(...extensionDataEntries);\n  }\n\n  static fromConfigObject(obj: { [extensionId: string]: any } = {}): ExtensionDataList {\n    const arr = Object.keys(obj).map((extensionId) => {\n      return new ExtensionDataEntry(extensionId, obj[extensionId]);\n    });\n    return this.fromArray(arr);\n  }\n\n  static fromArray(entries: ExtensionDataEntry[]): ExtensionDataList {\n    if (!entries || !entries.length) {\n      return new ExtensionDataList();\n    }\n    return new ExtensionDataList(...entries);\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/component/index.ts",
    "content": "import { ComponentAspect } from './component.aspect';\n\nexport default ComponentAspect;\nexport { ComponentAspect };\nexport { Component } from './component';\nexport type { ComponentMain } from './component.main.runtime';\nexport type { ComponentFactory } from './componentFactory';\nexport { ComponentMap } from './componentMap';\n"
  },
  {
    "path": "packages/aspect/src/component/type/custom.d.ts",
    "content": "declare module '*.module.css' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\ndeclare module '*.module.scss' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\ndeclare module '*.module.sass' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.module.less' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.less' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.css' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.sass' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.scss' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.mdx' {\n  const component: any;\n  export default component;\n}\n"
  },
  {
    "path": "packages/aspect/src/component/uiRuntime/component.module.scss",
    "content": ".container {\n}\n"
  },
  {
    "path": "packages/aspect/src/component/uiRuntime/component.tsx",
    "content": "import React, { useMemo, ReactNode, useEffect } from 'react';\n// eslint-disable-next-line import/no-extraneous-dependencies\nimport { RouteProps } from 'react-router-dom';\nimport { flatten } from 'lodash';\nimport { SlotRegistry } from '@arco-cli/stone';\n\nimport { SlotRouter } from '@aspect/react-router/uiRuntime';\n\nimport { ComponentProvider } from './componentContext';\nimport { ComponentModel } from './componentModel';\nimport { useComponentQuery } from './hooks/useComponentQuery';\nimport { getIdFromLocation } from './utils/getIdFromLocation';\n\nimport styles from './component.module.scss';\n\nexport type ComponentPageElement = {\n  type: 'before' | 'after';\n  content: ReactNode;\n};\n\nexport type ComponentPageSlot = SlotRegistry<ComponentPageElement[]>;\n\nexport type ComponentProps = {\n  host: string;\n  path?: string;\n  componentId: string;\n  routes: RouteProps[];\n  containerSlot?: ComponentPageSlot;\n  onComponentChange?: (activeComponent?: ComponentModel) => void;\n};\n\nexport function Component({\n  host,\n  path,\n  containerSlot,\n  routes,\n  componentId,\n  onComponentChange,\n}: ComponentProps) {\n  const idFromLocation = getIdFromLocation();\n  const resolvedComponentIdStr = path || idFromLocation;\n  const { component, error } = useComponentQuery(componentId || idFromLocation, host);\n\n  useEffect(() => onComponentChange?.(component), [component]);\n  // cleanup when unmounting component\n  useEffect(() => () => onComponentChange?.(undefined), []);\n\n  const pageItems = useMemo(() => flatten(containerSlot?.values()), [containerSlot]);\n  const before = useMemo(\n    () => pageItems.filter((x) => x.type === 'before').map((x) => x.content),\n    [pageItems]\n  );\n  const after = useMemo(\n    () => pageItems.filter((x) => x.type === 'after').map((x) => x.content),\n    [pageItems]\n  );\n\n  if (error) {\n    return error.renderError();\n  }\n\n  if (!component) {\n    return null;\n  }\n\n  return (\n    <ComponentProvider component={component}>\n      {before}\n      <div className={styles.container}>\n        {routes ? <SlotRouter parentPath={`${resolvedComponentIdStr}/*`} routes={routes} /> : null}\n      </div>\n      {after}\n    </ComponentProvider>\n  );\n}\n"
  },
  {
    "path": "packages/aspect/src/component/uiRuntime/component.ui.runtime.tsx",
    "content": "import React from 'react';\nimport type { RouteProps } from 'react-router-dom';\nimport { UIRuntime } from '@arco-cli/service/dist/ui/ui.aspect';\nimport { Slot, SlotRegistry } from '@arco-cli/stone';\n\nimport ComponentAspect from '../component.aspect';\nimport { Component, ComponentPageElement, ComponentPageSlot } from './component';\n\ntype RouteSlot = SlotRegistry<RouteProps>;\n\nexport class ComponentUI {\n  static runtime = UIRuntime;\n\n  static dependencies = [];\n\n  static slots = [Slot.withType<RouteProps>(), Slot.withType<ComponentPageElement[]>()];\n\n  static provider(_deps, _config, [routeSlot, pageItemSlot]: [RouteSlot, ComponentPageSlot]) {\n    const componentUI = new ComponentUI(routeSlot, pageItemSlot);\n    return componentUI;\n  }\n\n  constructor(private routeSlot: RouteSlot, private pageItemSlot: ComponentPageSlot) {}\n\n  readonly routePath = '/*';\n\n  registerRoute(routes: RouteProps) {\n    this.routeSlot.register(routes);\n    return this;\n  }\n\n  registerPageItem = (...items: ComponentPageElement[]) => {\n    this.pageItemSlot.register(items);\n    return this;\n  };\n\n  getComponentUI(host: string, componentId?: string) {\n    return (\n      <Component\n        host={host}\n        componentId={componentId}\n        routes={this.routeSlot.values()}\n        containerSlot={this.pageItemSlot}\n      />\n    );\n  }\n}\n\nComponentAspect.addRuntime(ComponentUI);\n"
  },
  {
    "path": "packages/aspect/src/component/uiRuntime/componentContext.tsx",
    "content": "import React, { createContext, PropsWithChildren } from 'react';\nimport { ComponentModel } from './componentModel';\n\nexport const ComponentContext: React.Context<ComponentModel> = createContext<ComponentModel>(\n  ComponentModel.empty()\n);\n\nexport function ComponentProvider({\n  component,\n  children,\n}: PropsWithChildren<{ component: ComponentModel }>) {\n  return <ComponentContext.Provider value={component}>{children}</ComponentContext.Provider>;\n}\n"
  },
  {
    "path": "packages/aspect/src/component/uiRuntime/componentError.tsx",
    "content": "import React from 'react';\nimport { NotFoundPage } from '@arco-cli/ui-foundation-react';\n\nexport class ComponentError {\n  constructor(\n    /**\n     * http status code of error\n     */\n    public readonly code: number,\n\n    /**\n     * error message of the error\n     */\n    public readonly message?: string\n  ) {}\n\n  renderError() {\n    return <NotFoundPage />;\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/component/uiRuntime/componentMeta/componentMeta.module.scss",
    "content": ".metadata {\n  .flexBetween {\n    display: flex;\n    justify-content: space-between;\n  }\n\n  .title {\n    margin: 0 0 12px;\n    padding: 0;\n    font-size: var(--preview-font-size-display-1);\n    font-weight: 600;\n    line-height: 1.3;\n    color: var(--preview-color-text-1);\n  }\n\n  .descriptions {\n    margin: 0 0 2px;\n    font-size: var(--preview-font-size-body-3);\n    line-height: 1.5;\n    color: var(--preview-color-text-2);\n  }\n\n  .bottomWrapper {\n    display: flex;\n    align-items: flex-end;\n    justify-content: space-between;\n  }\n\n  .labels {\n    display: flex;\n    align-items: center;\n    font-size: var(--preview-font-size-body-3);\n    color: var(--preview-color-text-3);\n\n    :global(.arco-icon) {\n      margin-right: 8px;\n    }\n  }\n\n  .rightWrapper {\n    display: flex;\n    justify-content: center;\n\n    > * {\n      margin-left: 12px;\n    }\n\n    .extraStyleSelect {\n      display: inline-flex;\n      width: auto;\n\n      :global(.arco-select-prefix) {\n        margin-right: 8px;\n      }\n\n      :global(.arco-select-suffix) {\n        margin-left: 8px;\n      }\n    }\n\n    .usage {\n      display: inline-flex;\n      align-items: center;\n      height: 32px;\n      padding: 0 12px;\n      border-radius: 2px;\n      background: var(--color-fill-2);\n      color: var(--color-text-1);\n    }\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/component/uiRuntime/componentMeta/componentMeta.tsx",
    "content": "import React, { useEffect } from 'react';\nimport { Typography, Select } from '@arco-design/web-react';\nimport { IconTag, IconSkin } from '@arco-design/web-react/icon';\nimport { ComponentModel } from '../componentModel';\n\nimport styles from './componentMeta.module.scss';\n\nexport interface ComponentMetaProps {\n  component: ComponentModel;\n  onComponentExtraStyleChange?: (href: string) => void;\n}\n\nexport function ComponentMeta({ component, onComponentExtraStyleChange }: ComponentMetaProps) {\n  const defaultExtraStyle = component.extraStyles?.[0]?.href;\n\n  useEffect(() => {\n    defaultExtraStyle && onComponentExtraStyleChange?.(defaultExtraStyle);\n  }, []);\n\n  return (\n    <div className={styles.metadata}>\n      <h1 className={styles.title}>{component.name}</h1>\n      <p className={styles.descriptions}>{component.description}</p>\n      <div className={styles.bottomWrapper}>\n        <div className={styles.labels}>\n          <IconTag />\n          {component.labels.join(' / ')}\n        </div>\n\n        <div className={styles.rightWrapper}>\n          {component.extraStyles?.length ? (\n            <Select\n              className={styles.extraStyleSelect}\n              allowClear\n              prefix={<IconSkin />}\n              placeholder=\"Choose a style\"\n              defaultValue={defaultExtraStyle}\n              options={component.extraStyles.map(({ title, href }) => ({\n                label: title,\n                value: href,\n              }))}\n              onChange={onComponentExtraStyleChange}\n            />\n          ) : null}\n\n          <div className={styles.usage}>\n            <Typography.Text copyable>npm install {component.packageName}</Typography.Text>\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "packages/aspect/src/component/uiRuntime/componentMeta/index.ts",
    "content": "export { ComponentMeta } from './componentMeta';\n"
  },
  {
    "path": "packages/aspect/src/component/uiRuntime/componentModel.ts",
    "content": "export type ComponentServer = {\n  env: string;\n  url: string;\n};\n\nexport type ComponentOutline = {\n  text: string;\n  depth: number;\n};\n\nexport type ComponentExtraDoc = {\n  title: string;\n  content: string;\n  type?: 'md';\n};\n\nexport type ComponentExtraStyle = {\n  title: string;\n  href: string;\n};\n\nexport type ComponentModelProps = {\n  id: string;\n  name: string;\n  packageName: string;\n  version: string;\n  author?: string;\n  description?: string;\n  labels?: string[];\n  host?: string;\n  server?: ComponentServer;\n  outline?: ComponentOutline[];\n  extraDocs?: ComponentExtraDoc[];\n  extraStyles?: ComponentExtraStyle[];\n};\n\nexport class ComponentModel {\n  constructor(\n    readonly id: string,\n    readonly name: string,\n    readonly packageName: string,\n    readonly version: string,\n    readonly author: string,\n    readonly host: string,\n    readonly server: ComponentServer | undefined,\n    readonly description = '',\n    readonly labels: string[] = [],\n    readonly outline: ComponentOutline[] = [],\n    readonly extraDocs: ComponentExtraDoc[] = [],\n    readonly extraStyles: ComponentExtraStyle[] = []\n  ) {}\n\n  static from({\n    id,\n    name,\n    packageName,\n    version,\n    author,\n    host,\n    server,\n    description,\n    labels,\n    outline,\n    extraDocs,\n    extraStyles,\n  }: ComponentModelProps) {\n    return new ComponentModel(\n      id,\n      name,\n      packageName,\n      version,\n      author,\n      host,\n      server,\n      description,\n      labels,\n      outline,\n      extraDocs,\n      extraStyles\n    );\n  }\n\n  static fromArray(componentsProps: ComponentModelProps[]) {\n    return componentsProps.map((rawComponent) => ComponentModel.from(rawComponent));\n  }\n\n  static empty() {\n    return new ComponentModel('', '', '', '', '', '', { env: '', url: '' });\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/component/uiRuntime/hooks/useComponentQuery.ts",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport { useMemo, useRef } from 'react';\nimport gql from 'graphql-tag';\nimport { useDataQuery } from '@arco-cli/ui-foundation-react';\n\nimport { ComponentModel } from '../componentModel';\nimport { ComponentError } from '../componentError';\n\nconst componentOverviewFields = gql`\n  fragment componentOverviewFields on Component {\n    id\n    name\n    description\n    labels\n    outline {\n      depth\n      text\n    }\n    server {\n      env\n      url\n    }\n    extraDocs {\n      title\n      content\n    }\n    extraStyles {\n      title\n      href\n    }\n  }\n`;\n\nconst componentFields = gql`\n  fragment componentFields on Component {\n    id\n    packageName\n    ...componentOverviewFields\n  }\n  ${componentOverviewFields}\n`;\n\nconst GET_COMPONENT = gql`\n  query Component($id: String!, $extensionId: String!) {\n    getHost(id: $extensionId) {\n      # used for GQL caching\n      id\n      get(id: $id) {\n        ...componentFields\n      }\n    }\n  }\n  ${componentFields}\n`;\n\n/**\n * provides data to component ui page, making sure both variables and return value are safely typed and memoized\n */\nexport function useComponentQuery(componentId: string, host: string, skip?: boolean) {\n  const refId = useRef(componentId);\n  refId.current = componentId;\n\n  const { data, error, loading } = useDataQuery(GET_COMPONENT, {\n    variables: { id: componentId, extensionId: host },\n    skip,\n  });\n  const rawComponent = data?.getHost?.get;\n\n  return useMemo(() => {\n    return {\n      component: rawComponent ? ComponentModel.from({ ...rawComponent, host }) : undefined,\n      error: error\n        ? new ComponentError(500, error.message)\n        : !rawComponent && !loading\n        ? new ComponentError(404)\n        : undefined,\n      loading,\n    };\n  }, [error, loading, rawComponent, host]);\n}\n"
  },
  {
    "path": "packages/aspect/src/component/uiRuntime/index.ts",
    "content": "export { ComponentAspect } from '../component.aspect';\nexport type { ComponentUI } from './component.ui.runtime';\nexport { ComponentModel, ComponentModelProps } from './componentModel';\nexport { ComponentContext } from './componentContext';\nexport { ComponentMeta } from './componentMeta';\n"
  },
  {
    "path": "packages/aspect/src/component/uiRuntime/utils/getIdFromLocation.ts",
    "content": "/**\n * this can match component is like package-name/component-name\n * or @scope/package-name/component-name\n */\nconst componentRegex = /^(@([^/]+)\\/)?([^/]+)\\/([^/]+)/;\n\nexport function getIdFromLocation(): string | undefined {\n  const splat = window.location.pathname.replace(/^\\//, '');\n  const match = componentRegex.exec(splat);\n  return match?.[0];\n}\n"
  },
  {
    "path": "packages/aspect/src/component/version/index.ts",
    "content": "export { Version, LATEST_VERSION, VERSION_DELIMITER } from './version';\nexport { versionParser } from './versionParser';\n"
  },
  {
    "path": "packages/aspect/src/component/version/version.ts",
    "content": "import semver from 'semver';\nimport { InvalidVersionError } from '../exceptions';\n\nexport const LATEST_VERSION = 'latest';\n\nexport const VERSION_DELIMITER = '@';\n\nexport class Version {\n  latest: boolean;\n\n  versionNum: string | null | undefined;\n\n  constructor(versionNum: string | null | undefined, latest: boolean) {\n    this.versionNum = versionNum;\n    this.latest = latest;\n  }\n\n  toString() {\n    if (!this.versionNum && this.latest) return 'latest';\n    if (this.versionNum && this.latest) return `*${this.versionNum}`;\n    if (this.versionNum && !this.latest) return this.versionNum.toString();\n    throw new InvalidVersionError(this.versionNum);\n  }\n\n  isLaterThan(otherVersion: Version): boolean {\n    if (!this.versionNum || this.versionNum === LATEST_VERSION) {\n      return true;\n    }\n    if (!otherVersion.versionNum || otherVersion.versionNum === LATEST_VERSION) {\n      return false;\n    }\n    return semver.gt(this.versionNum, otherVersion.versionNum);\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/component/version/versionParser.ts",
    "content": "import semver from 'semver';\nimport { InvalidVersionError } from '../exceptions';\nimport { Version, LATEST_VERSION } from './version';\n\nexport const LATEST_TESTED_MARK = '*';\n\nfunction isLatest(versionStr: string): boolean {\n  return versionStr === LATEST_VERSION;\n}\n\nfunction isLatestTested(versionStr: string) {\n  if (!versionStr.includes(LATEST_TESTED_MARK)) return false;\n  const splited = versionStr.split(LATEST_TESTED_MARK);\n  if (splited.length !== 2) return false;\n  const [, numberStr] = splited;\n  const version = isRegular(numberStr);\n  if (!version) return false;\n  return true;\n}\n\nfunction isRegular(versionStr: string) {\n  return semver.valid(versionStr);\n}\n\nfunction returnRegular(versionStr: string): Version {\n  return new Version(versionStr, false);\n}\n\nfunction returnLatestTestedVersion(versionStr: string): Version {\n  const [, numberStr] = versionStr.split(LATEST_TESTED_MARK);\n  return new Version(numberStr, true);\n}\n\nfunction returnLatest(): Version {\n  return new Version(null, true);\n}\n\nfunction convertToSemVer(versionStr: number) {\n  return returnRegular(`0.0.${versionStr}`);\n}\n\nexport function versionParser(versionStr: string | number | null | undefined): Version {\n  const isVersionStr = typeof versionStr === 'string';\n  if (!versionStr) return returnLatest();\n  if (isVersionStr && isLatest(versionStr)) return returnLatest();\n  if (isVersionStr && isLatestTested(versionStr)) return returnLatestTestedVersion(versionStr);\n  if (isVersionStr && isRegular(versionStr)) return returnRegular(versionStr);\n  if (!isVersionStr && Number.isInteger(versionStr)) return convertToSemVer(versionStr);\n  throw new InvalidVersionError(versionStr.toString());\n}\n"
  },
  {
    "path": "packages/aspect/src/docs/doc/doc.ts",
    "content": "import { DocPropList } from './docPropList';\nimport { SerializableMap } from './docProp';\nimport { DocOutline, DocSnippet } from '../type';\n\nexport class Doc {\n  constructor(readonly filePath: string, readonly props: DocPropList) {}\n\n  toObject() {\n    return {\n      filePath: this.filePath,\n      props: this.props.docProps,\n    };\n  }\n\n  get title(): string {\n    const value = this.props.get('title')?.value;\n    return (value as string) || '';\n  }\n\n  get description(): string {\n    const value = this.props.get('description')?.value;\n    return (value as string) || '';\n  }\n\n  get labels(): string[] {\n    const value = this.props.get('labels')?.value;\n    return (value as string[]) || [];\n  }\n\n  get outline(): DocOutline {\n    return this.props.get('outline')?.value as [];\n  }\n\n  get snippets(): DocSnippet[] {\n    return this.props.get('snippets')?.value as [];\n  }\n\n  static from(path: string, propObject: SerializableMap) {\n    return new Doc(path, DocPropList.from(propObject));\n  }\n\n  static mergeDocProperty(docProp, extendProp): typeof docProp {\n    if (Array.isArray(docProp) || Array.isArray(extendProp)) {\n      return [\n        ...(Array.isArray(docProp) ? docProp : []),\n        ...(Array.isArray(extendProp) ? extendProp : []),\n      ];\n    }\n\n    return extendProp || docProp;\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/docs/doc/docProp.ts",
    "content": "export type Serializable =\n  | string\n  | {\n      /**\n       * serialize the object into a string.\n       */\n      toString(): string;\n    };\n\nexport type SerializableMap = {\n  [key: string]: Serializable;\n};\n\nexport class DocProp {\n  constructor(\n    /**\n     * name of the doc property.\n     */\n    readonly name: string,\n\n    /**\n     * value of the doc property.\n     */\n    readonly value: Serializable\n  ) {}\n\n  getAs<T>() {\n    return this.value as T;\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/docs/doc/docPropList.ts",
    "content": "import { DocProp } from './docProp';\n\nexport class DocPropList {\n  constructor(readonly docProps: DocProp[]) {}\n\n  get(name: string) {\n    return this.docProps.find((docProp) => docProp.name === name);\n  }\n\n  static from(object: any): DocPropList {\n    const props = Object.keys(object)\n      .map((key) => {\n        if (!object[key]) return undefined;\n        return new DocProp(key, object[key]);\n      })\n      .filter((prop) => !!prop) as DocProp[];\n\n    return new DocPropList(props);\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/docs/doc/index.ts",
    "content": "export { Doc } from './doc';\nexport { DocProp } from './docProp';\nexport { DocPropList } from './docPropList';\n"
  },
  {
    "path": "packages/aspect/src/docs/docs.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const DocsAspect = Aspect.create({\n  id: 'arco.aspect/docs',\n});\n\nexport default DocsAspect;\n"
  },
  {
    "path": "packages/aspect/src/docs/docs.graphql.ts",
    "content": "import path from 'path';\nimport gql from 'graphql-tag';\n\nimport { Component } from '@aspect/component';\nimport { ComponentModel } from '@aspect/component/uiRuntime';\n\nimport { Doc } from './doc';\nimport { DocsMain } from './docs.main.runtime';\n\nexport default function (docs: DocsMain) {\n  return {\n    typeDefs: gql`\n      extend type Component {\n        description: String\n        labels: [String]\n        outline: [ComponentOutline]\n        extraDocs: [ExtraDocItem]\n      }\n\n      type ExtraDocItem {\n        title: String\n        content: String\n      }\n\n      type ComponentOutline {\n        depth: Int\n        text: String\n      }\n    `,\n    resolvers: {\n      Component: {\n        description: (component: Component): ComponentModel['description'] => {\n          const doc = docs.getDoc(component);\n          return doc?.description || '';\n        },\n\n        labels: (component: Component): ComponentModel['labels'] => {\n          const doc = docs.getDoc(component);\n          return Doc.mergeDocProperty(doc?.labels || [], component.labels);\n        },\n\n        outline: (component: Component): ComponentModel['outline'] => {\n          const doc = docs.getDoc(component);\n          return doc?.outline || [];\n        },\n\n        extraDocs: (component: Component): ComponentModel['extraDocs'] => {\n          const results = [];\n          component.entries.extraDocs.forEach(({ title, entry }) => {\n            const file = component.files.find(\n              (file) => file.relative === path.join(component.entries.base, entry)\n            );\n            if (file) {\n              results.push({ title, content: file.contents.toString() });\n            }\n          });\n          return results;\n        },\n      },\n    },\n  };\n}\n"
  },
  {
    "path": "packages/aspect/src/docs/docs.main.runtime.ts",
    "content": "import path from 'path';\nimport fs from 'fs-extra';\nimport { MainRuntime } from '@arco-cli/core/dist/cli';\nimport { LoggerAspect, LoggerMain, Logger } from '@arco-cli/core/dist/logger';\nimport { Slot, SlotRegistry } from '@arco-cli/stone';\nimport { PreviewAspect, PreviewMain } from '@arco-cli/service/dist/preview';\nimport { BuilderAspect, BuilderMain } from '@arco-cli/service/dist/builder';\nimport { GraphqlAspect, GraphqlMain } from '@arco-cli/core/dist/graphql';\nimport { AbstractVinyl } from '@arco-cli/legacy/dist/workspace/component/sources';\nimport { Doclet } from '@arco-cli/legacy/dist/types';\nimport { DIR_ARTIFACTS_DOCS } from '@arco-cli/legacy/dist/constants';\nimport { toComponentManifestFilename } from '@arco-cli/legacy/dist/workspace/componentIdTo';\n\nimport { Environment } from '@aspect/envs';\nimport { WorkspaceAspect, Workspace } from '@aspect/workspace';\nimport { Component, ComponentMap } from '@aspect/component';\n\nimport DocsAspect from './docs.aspect';\nimport getDocsSchema from './docs.graphql';\nimport { DocsPreviewDefinition } from './docs.previewDefinition';\nimport { DocReader } from './type';\nimport { FileExtensionNotSupportedError } from './exceptions';\nimport { Doc, DocPropList } from './doc';\nimport { ComponentManifest, DocsTask } from './docs.task';\n\ntype DocReaderSlot = SlotRegistry<DocReader>;\n\nexport class DocsMain {\n  static runtime = MainRuntime;\n\n  static dependencies = [\n    PreviewAspect,\n    GraphqlAspect,\n    WorkspaceAspect,\n    LoggerAspect,\n    BuilderAspect,\n  ];\n\n  static slots = [Slot.withType<DocReader>()];\n\n  static provider(\n    [preview, graphql, workspace, loggerMain, builder]: [\n      PreviewMain,\n      GraphqlMain,\n      Workspace,\n      LoggerMain,\n      BuilderMain\n    ],\n    _config,\n    [docReaderSlot]: [DocReaderSlot]\n  ) {\n    const logger = loggerMain.createLogger(DocsAspect.id);\n    const docsMain = new DocsMain(logger, docReaderSlot);\n\n    preview.registerDefinition(new DocsPreviewDefinition(docsMain));\n    graphql.register(getDocsSchema(docsMain));\n\n    if (workspace) {\n      workspace.registerOnComponentLoad(async (component) => {\n        const doc = await docsMain.computeDoc(component);\n        return {\n          doc: doc?.toObject(),\n        };\n      });\n    }\n\n    builder.registerBuildTasks([new DocsTask(docsMain)]);\n\n    return docsMain;\n  }\n\n  constructor(private logger: Logger, private docReaderSlot: DocReaderSlot) {}\n\n  private getDocFiles({ entries, files }: Component): {\n    previews: AbstractVinyl[];\n    previewContextProvider: AbstractVinyl | null;\n  } {\n    const previewEntry = path.join(entries.base, entries.preview);\n    const previewContextProviderEntry = path.join(entries.base, entries.previewContextProvider);\n    return {\n      previews: files.filter((file) => previewEntry === file.relative),\n      previewContextProvider:\n        files.find((file) => previewContextProviderEntry === file.relative) || null,\n    };\n  }\n\n  private getDocReader(extension: string) {\n    return this.docReaderSlot.values().find((docReader) => docReader.isFormatSupported(extension));\n  }\n\n  /**\n   * register a new doc reader. this allows to support further\n   * documentation file formats.\n   */\n  registerDocReader(docReader: DocReader) {\n    this.docReaderSlot.register(docReader);\n    return this;\n  }\n\n  async getTemplate(env: Environment): Promise<string> {\n    return env.getDocsTemplate?.();\n  }\n\n  /**\n   * returns an array of doc file paths for a set of components.\n   */\n  getDocsMap(components: Component[]) {\n    return ComponentMap.as(components, (component) => this.getDocFiles(component));\n  }\n\n  /**\n   * return any component metadata generate by env\n   * like component property tables\n   */\n  getMetadata(components: Component[], env: Environment) {\n    return ComponentMap.as<{ doclets: Doclet[]; apiPlaceholderElementId?: string }>(\n      components,\n      (component) => {\n        let jsdocEntryFiles = [];\n\n        if (component.entries.jsdoc) {\n          jsdocEntryFiles = (\n            Array.isArray(component.entries.jsdoc)\n              ? component.entries.jsdoc\n              : [component.entries.jsdoc]\n          )\n            .map((jsdocEntry) => {\n              return jsdocEntry\n                ? component.files.find(\n                    (file) => file.relative === path.join(component.entries.base, jsdocEntry)\n                  )\n                : null;\n            })\n            .filter(Boolean);\n        }\n\n        const doc = this.getDoc(component);\n\n        return {\n          doclets: env.getDocsMetadata?.(jsdocEntryFiles),\n          apiPlaceholderElementId:\n            doc.props.get('apiPlaceholderElementId')?.value?.toString() || '',\n        };\n      }\n    );\n  }\n\n  /**\n   * return the doc properties parsed from raw document file\n   * like description / labels\n   */\n  getDoc(component: Component) {\n    const docData = component.extensions.findExtension(DocsAspect.id)?.data?.doc || {\n      filePath: '',\n      props: [],\n    };\n    return new Doc(docData.filePath, new DocPropList(docData.props));\n  }\n\n  /**\n   * compute a doc for a component.\n   */\n  async computeDoc(component: Component) {\n    const docFiles = this.getDocFiles(component).previews;\n    if (docFiles.length) {\n      // currently taking the first docs file found with an abstract. (we support only one)\n      const docFile = docFiles[0];\n\n      try {\n        const docReader = this.getDocReader(docFile.extname);\n        if (!docReader) throw new FileExtensionNotSupportedError(docFile.relative, docFile.extname);\n        const doc = await docReader.read(docFile.path, docFile.contents, component);\n        return doc;\n      } catch (err: any) {\n        // it's ok to fail here.\n        this.logger.debug(`docs.main.runtime.computeDoc caught an error: ${err.message}`);\n        return null;\n      }\n    }\n\n    return null;\n  }\n\n  /**\n   * get manifest info from doc artifact\n   */\n  async getDocsManifestFromArtifact(component: Component): Promise<ComponentManifest> {\n    const artifactManifestPathAbs = path.join(\n      component.packageDirAbs,\n      DIR_ARTIFACTS_DOCS,\n      toComponentManifestFilename(component.id)\n    );\n    const emptyResult: ComponentManifest = { doclets: [], snippets: [], extraDocs: [] };\n\n    if (fs.existsSync(artifactManifestPathAbs)) {\n      try {\n        const manifest: ComponentManifest = await fs.readJSON(artifactManifestPathAbs);\n        return manifest || emptyResult;\n      } catch (err) {}\n    }\n\n    return emptyResult;\n  }\n}\n\nDocsAspect.addRuntime(DocsMain);\n"
  },
  {
    "path": "packages/aspect/src/docs/docs.previewDefinition.ts",
    "content": "import type { PreviewDefinition } from '@arco-cli/service/dist/preview';\n\nimport type { Component } from '@aspect/component';\nimport type { Environment } from '@aspect/envs';\n\nimport { DocsMain } from './docs.main.runtime';\n\nexport class DocsPreviewDefinition implements PreviewDefinition {\n  readonly prefix = 'overview';\n\n  readonly include = ['compositions'];\n\n  readonly includePeers = true;\n\n  constructor(\n    /**\n     * docs extension.\n     */\n    private docs: DocsMain\n  ) {}\n\n  /**\n   * application root\n   */\n  async renderTemplatePath(env: Environment): Promise<string> {\n    return this.docs.getTemplate(env);\n  }\n\n  /**\n   * files to load.\n   */\n  async getModuleMap(components: Component[]) {\n    return this.docs.getDocsMap(components);\n  }\n\n  /**\n   * metadata to collect\n   */\n  async getMetadataMap(components: Component[], env: Environment) {\n    return this.docs.getMetadata(components, env);\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/docs/docs.task.ts",
    "content": "import path from 'path';\nimport fs from 'fs-extra';\nimport { toFsCompatible } from '@arco-cli/legacy/dist/utils';\nimport { BuildContext, BuildTask, BuildTaskResult } from '@arco-cli/service/dist/builder';\nimport { BUILD_TASK_NAME_DOCS, DIR_ARTIFACTS_DOCS } from '@arco-cli/legacy/dist/constants';\nimport { toComponentManifestFilename } from '@arco-cli/legacy/dist/workspace/componentIdTo';\nimport { ComponentResult } from '@arco-cli/legacy/dist/workspace/componentResult';\nimport type { Doclet } from '@arco-cli/legacy/dist/types';\n\nimport { Component } from '@aspect/component';\n\nimport DocsAspect from './docs.aspect';\nimport type { DocsMain } from './docs.main.runtime';\nimport type { DocSnippet } from '../docs/type';\n\nexport type ComponentManifest = {\n  doclets: Doclet[];\n  snippets: DocSnippet[];\n  extraDocs: Component['entries']['extraDocs'];\n};\n\nexport class DocsTask implements BuildTask {\n  readonly aspectId = DocsAspect.id;\n\n  readonly name = BUILD_TASK_NAME_DOCS;\n\n  constructor(\n    /**\n     * docs extension.\n     */\n    private docsMain: DocsMain\n  ) {}\n\n  async execute(context: BuildContext): Promise<BuildTaskResult> {\n    const results: ComponentResult[] = [];\n    // { artifactDirPath: { componentId: { ... } } }\n    const packageManifestMap: Map<Component, ComponentManifest> = new Map();\n\n    // remove docs artifacts dir at first\n    await Promise.all(\n      [...new Set(context.components.map(({ packageDirAbs }) => packageDirAbs))].map(\n        async (packagePathAbs) => {\n          await fs.remove(path.join(packagePathAbs, DIR_ARTIFACTS_DOCS));\n        }\n      )\n    );\n\n    // collect component doclets and snippets\n    const componentMetadataMap = this.docsMain.getMetadata(\n      context.components,\n      context.envRuntime.env\n    );\n\n    // 从 context.env 获取 component metadata\n    await Promise.all(\n      context.components.map(async (component) => {\n        const componentResult: ComponentResult = { id: component.id, errors: [] };\n        let manifest: ComponentManifest = packageManifestMap.get(component);\n        if (!manifest) {\n          manifest = { doclets: [], snippets: [], extraDocs: [] };\n          packageManifestMap.set(component, manifest);\n        }\n\n        // handle snippets/doclets bellow\n        try {\n          const doclets = componentMetadataMap.getValueByComponentId(component.id).doclets;\n          const doc = this.docsMain.getDoc(component);\n          manifest.doclets.push(...doclets);\n          manifest.snippets.push(...doc.snippets);\n        } catch (err) {\n          componentResult.errors.push(err);\n        }\n\n        // handle extraDocs bellow\n        await Promise.all(\n          component.entries.extraDocs.map(async ({ title, entry }) => {\n            const extraDoc = component.files.find(\n              (file) =>\n                file.relative === path.relative('./', path.join(component.entries.base, entry))\n            );\n            if (extraDoc) {\n              const targetFilename = `${toFsCompatible(component.id)}-${extraDoc.path\n                .split(path.sep)\n                .pop()}`;\n\n              try {\n                const targetDirAbs = path.join(component.packageDirAbs, DIR_ARTIFACTS_DOCS);\n                await fs.ensureDir(targetDirAbs);\n                await fs.copyFile(extraDoc.path, path.join(targetDirAbs, targetFilename));\n                const targetFileRelativePath = path.join(DIR_ARTIFACTS_DOCS, targetFilename);\n                manifest.extraDocs.push({\n                  title,\n                  entry: targetFileRelativePath,\n                });\n              } catch (err) {\n                componentResult.errors.push(err);\n              }\n            }\n          })\n        );\n      })\n    );\n\n    await Promise.all(\n      [...packageManifestMap.entries()].map(async ([component, manifest]) => {\n        const targetDir = path.join(component.packageDirAbs, DIR_ARTIFACTS_DOCS);\n        const manifestFilename = toComponentManifestFilename(component.id);\n        await fs.ensureDir(targetDir);\n        await fs.writeJSON(path.join(targetDir, manifestFilename), manifest, { spaces: 2 });\n      })\n    );\n\n    return { componentsResults: results };\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/docs/exceptions/fileExtensionNotSupportedError.ts",
    "content": "export class FileExtensionNotSupportedError extends Error {\n  constructor(filePath: string, extension: string) {\n    super(\n      `failed reading doc file: ${filePath} as file extension ${extension} is not supported by any of registered component doc readers.`\n    );\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/docs/exceptions/index.ts",
    "content": "export { FileExtensionNotSupportedError } from './fileExtensionNotSupportedError';\n"
  },
  {
    "path": "packages/aspect/src/docs/index.ts",
    "content": "import { DocsAspect } from './docs.aspect';\n\nexport default DocsAspect;\nexport { DocsAspect };\nexport type { DocsMain } from './docs.main.runtime';\nexport { Doc } from './doc';\nexport type { DocReader, DocOutline, DocSnippet } from './type';\n"
  },
  {
    "path": "packages/aspect/src/docs/previewRuntime/docs.preview.runtime.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport { ComponentType } from 'react';\nimport type { Doclet } from '@arco-cli/legacy/dist/types';\nimport type { RenderingContext, PreviewModule } from '@arco-cli/service/dist/preview';\nimport {\n  PreviewAspect,\n  PreviewPreview,\n  PreviewRuntime,\n} from '@arco-cli/service/dist/preview/previewRuntime';\n\nimport { DocsAspect } from '../docs.aspect';\n\nexport type DocsRootProps = {\n  componentId: string;\n  doc: ComponentType | undefined;\n  docContextProvider: ComponentType | undefined;\n  context: RenderingContext;\n  metadata: {\n    doclets: Doclet[];\n    apiPlaceholderElementId?: string;\n  };\n};\n\nexport class DocsPreview {\n  static runtime = PreviewRuntime;\n\n  static dependencies = [PreviewAspect];\n\n  static async provider([preview]: [PreviewPreview]) {\n    const docsPreview = new DocsPreview();\n\n    preview.registerPreview({\n      name: 'overview',\n      render: docsPreview.render.bind(docsPreview),\n      selectPreviewModel: docsPreview.selectPreviewModel.bind(docsPreview),\n    });\n\n    return docsPreview;\n  }\n\n  constructor() {}\n\n  selectPreviewModel(componentId: string, modules: PreviewModule) {\n    const relevant = modules.componentMap[componentId];\n    // only one doc file is supported.\n    return relevant?.[0];\n  }\n\n  render = async (\n    componentId: string,\n    modules: PreviewModule,\n    _include,\n    context: RenderingContext\n  ) => {\n    let doc = null;\n    let docContextProvider = null;\n\n    // import document preview module\n    const dynamicImportModule = this.selectPreviewModel(componentId, modules);\n    if (typeof dynamicImportModule === 'function') {\n      doc = (await dynamicImportModule()).default;\n    }\n\n    // import context-provider for component preview\n    const dynamicImportContextProvider = modules.componentContextProviderMap[componentId];\n    if (typeof dynamicImportContextProvider === 'function') {\n      docContextProvider = (await dynamicImportContextProvider()).default;\n    }\n\n    const metadata: any = modules.componentMetadataMap[componentId] || {};\n    const docsProps: DocsRootProps = {\n      context,\n      componentId,\n      doc,\n      metadata,\n      docContextProvider,\n    };\n\n    modules.mainModule.default(docsProps);\n  };\n}\n\nDocsAspect.addRuntime(DocsPreview);\n"
  },
  {
    "path": "packages/aspect/src/docs/previewRuntime/index.ts",
    "content": "export { DocsRootProps } from './docs.preview.runtime';\n"
  },
  {
    "path": "packages/aspect/src/docs/type/custom.d.ts",
    "content": "declare module '*.module.css' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\ndeclare module '*.module.scss' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\ndeclare module '*.module.sass' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.module.less' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.less' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.css' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.sass' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.scss' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.mdx' {\n  const component: any;\n  export default component;\n}\n"
  },
  {
    "path": "packages/aspect/src/docs/type/docOutline.ts",
    "content": "export type DocOutline = Array<{ depth: number; text: string }>;\n"
  },
  {
    "path": "packages/aspect/src/docs/type/docReader.ts",
    "content": "import type { Component } from '@aspect/component';\n\nexport interface DocReader {\n  /**\n   * read a component doc.\n   */\n  read(path: string, contents: Buffer, component: Component): Promise<any>;\n\n  /**\n   * determine which file formats are supported by the doc reader.\n   */\n  isFormatSupported(ext: string): boolean;\n}\n"
  },
  {
    "path": "packages/aspect/src/docs/type/docSnippet.ts",
    "content": "export type DocSnippet = { language: string; code: string };\n"
  },
  {
    "path": "packages/aspect/src/docs/type/index.ts",
    "content": "export { DocReader } from './docReader';\nexport { DocOutline } from './docOutline';\nexport { DocSnippet } from './docSnippet';\n"
  },
  {
    "path": "packages/aspect/src/docs/uiRuntime/docs.ui.runtime.tsx",
    "content": "import React from 'react';\nimport { UIRuntime } from '@arco-cli/service/dist/ui/uiRuntime';\n\nimport { ComponentAspect, ComponentUI } from '@aspect/component/uiRuntime';\n\nimport DocsAspect from '../docs.aspect';\nimport { Overview } from './overview';\n\nexport class DocsUI {\n  static runtime = UIRuntime;\n\n  static dependencies = [ComponentAspect];\n\n  static slots = [];\n\n  static provider([component]: [ComponentUI]) {\n    component.registerRoute({\n      index: true,\n      element: <Overview />,\n    });\n    const docUI = new DocsUI();\n    return docUI;\n  }\n\n  constructor() {}\n}\n\nDocsAspect.addRuntime(DocsUI);\n"
  },
  {
    "path": "packages/aspect/src/docs/uiRuntime/index.tsx",
    "content": "export { DocsAspect } from '../docs.aspect';\nexport type { DocsUI } from './docs.ui.runtime';\n"
  },
  {
    "path": "packages/aspect/src/docs/uiRuntime/overview.module.scss",
    "content": ".overview {\n  padding: 0 20px;\n\n  .divider {\n    margin: 40px 0 24px;\n    border: none;\n    border-bottom: 1px solid var(--preview-color-border);\n  }\n\n  :global(.arco-tabs-header-nav-rounded .arco-tabs-header-title) {\n    margin: 12px 0;\n\n    &:not(:first-child) {\n      margin-left: 12px;\n    }\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/docs/uiRuntime/overview.tsx",
    "content": "import React, { useContext, useState } from 'react';\nimport { WorkspaceContext } from '@arco-cli/ui-foundation-react';\nimport { ComponentPreview } from '@arco-cli/service/dist/preview/uiRuntime';\nimport { Tabs } from '@arco-cli/ui-foundation-react/dist/tabs';\nimport { MarkdownLive } from '@arco-cli/ui-foundation-react/dist/markdown/live';\n\nimport { ComponentContext, ComponentMeta } from '@aspect/component/uiRuntime';\n\nimport '@arco-cli/ui-foundation-react/dist/markdown/style/markdown.css';\nimport styles from './overview.module.scss';\n\nexport function Overview() {\n  const { darkMode } = useContext(WorkspaceContext);\n  const component = useContext(ComponentContext);\n  const [extraStyle, setExtraStyle] = useState<string>(null);\n\n  const titleComponentPreview = 'Preview';\n  const eleComponentPreview = (\n    <ComponentPreview\n      component={component}\n      previewName=\"overview\"\n      viewport={null}\n      extraStyle={extraStyle}\n      darkMode={darkMode}\n    />\n  );\n\n  return (\n    <div className={styles.overview}>\n      <ComponentMeta component={component} onComponentExtraStyleChange={setExtraStyle} />\n\n      <hr className={styles.divider} />\n\n      {component.extraDocs?.length ? (\n        <Tabs type=\"rounded\">\n          <Tabs.TabPane key={titleComponentPreview} title={titleComponentPreview}>\n            {eleComponentPreview}\n          </Tabs.TabPane>\n\n          {component.extraDocs.map(({ title, content }) => {\n            return (\n              <Tabs.TabPane key={title} title={title}>\n                <MarkdownLive children={content} />\n              </Tabs.TabPane>\n            );\n          })}\n        </Tabs>\n      ) : (\n        eleComponentPreview\n      )}\n    </div>\n  );\n}\n"
  },
  {
    "path": "packages/aspect/src/envs/envDefinition.ts",
    "content": "import { Environment } from './environment';\n\n/**\n * API for component development environment.\n */\nexport class EnvDefinition {\n  constructor(readonly id: string, readonly env: Environment) {}\n\n  get name() {\n    return this.env.name;\n  }\n\n  get description() {\n    return this.env.description;\n  }\n\n  toObject() {\n    return {\n      id: this.id,\n      description: this.description,\n      name: this.name,\n    };\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/envs/envService.ts",
    "content": "import type { ReactElement } from 'react';\nimport { Environment } from './environment';\nimport { ExecutionContext } from './executionContext';\n\nexport interface EnvServiceExecutionResult {\n  errors?: Error[];\n}\n\n/**\n * services allows to reuse and standardize services for development environments.\n * examples for services can be: `linting`, `compilation`, `build`, and others which offer\n * standard services to environments such as `react`, `angular` and `vue` and different compositions of each for\n * more concrete needs.\n *\n * `TData` - type of data returned by the service handler.\n * `TOpts` is the type of options passed to the environment through execution.\n * `TExecResponse` is the execution result of the service.\n */\nexport interface EnvService<\n  TExecResponse extends EnvServiceExecutionResult,\n  TData = Record<string, any>,\n  TOpts = Record<string, any>\n> {\n  /**\n   * name of the service. (e.g. `compile`, `test`, etc.)\n   */\n  name?: string;\n\n  /**\n   * description of the env.\n   */\n  description?: string;\n\n  /**\n   * create a string to describe to service in the env cli.\n   */\n  render?(env: Environment): ReactElement | Promise<ReactElement>;\n\n  /**\n   * get service data from an environment.\n   */\n  getDescriptor?(env: Environment): TData | undefined | Promise<TData | undefined>;\n\n  /**\n   * executes a service on a subset of components.\n   */\n  run?(context: ExecutionContext, options?: TOpts): Promise<TExecResponse>;\n\n  /**\n   * run the service only once.\n   */\n  runOnce?(context: ExecutionContext[], options?: TOpts): Promise<any>;\n}\n"
  },
  {
    "path": "packages/aspect/src/envs/environment.ts",
    "content": "import { EnvPreviewConfig } from '@arco-cli/service/dist/preview';\nimport type { SourceFile } from '@arco-cli/legacy/dist/workspace/component/sources';\n\nimport { Bundler, BundlerContext } from '@aspect/bundler';\n\n/**\n * add a custom type and include all properties from within the environment.\n */\nexport interface Environment {\n  // :TODO need to define an abstract type for service handlers (now using any)\n  [key: string]: any;\n\n  /**\n   * name of the environment.\n   */\n  name?: string;\n\n  /**\n   * description of the environment.\n   */\n  description?: string;\n\n  /**\n   * Returns the Environment descriptor\n   * Required for any task\n   */\n  __getDescriptor?: () => Promise<{ type: string }>;\n\n  /**\n   * Returns the dev patterns to match doc files\n   */\n  getDocsDevPatterns?: () => string[];\n\n  /**\n   * Returns additional dev patterns for the component.\n   * Patterns that were provided by getDocsDevPatterns, getTestsDevPatterns will be considered as dev files as well, without need to add them here.\n   */\n  getDevPatterns?: () => string[];\n}\n\nexport interface TesterEnv<T = any> extends Environment {\n  /**\n   * Returns a tester\n   */\n  getTester?: (path: string, tester: any) => T;\n\n  /**\n   * Returns the dev patterns to match test files\n   */\n  getTestsDevPatterns?: () => string[];\n}\n\nexport interface PreviewEnv extends Environment {\n  /**\n   * Returns a path to a docs template.\n   * Required for `arco start` & `arco build`\n   */\n  getDocsTemplate?: () => string;\n\n  /**\n   * Return metadata of current component document, like properties info\n   */\n  getDocsMetadata?: (files: SourceFile[]) => unknown;\n\n  /**\n   * Returns a bundler for the preview.\n   */\n  getBundler?: (context: BundlerContext, transformers: any[]) => Promise<Bundler>;\n\n  /**\n   * Returns preview config like the strategy name to use when bundling the components for the preview\n   */\n  getPreviewConfig?: () => EnvPreviewConfig;\n}\n"
  },
  {
    "path": "packages/aspect/src/envs/envs.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const EnvsAspect = Aspect.create({\n  id: 'arco.aspect/envs',\n});\n\nexport default EnvsAspect;\n"
  },
  {
    "path": "packages/aspect/src/envs/envs.main.runtime.ts",
    "content": "import { Slot, SlotRegistry } from '@arco-cli/stone';\nimport { MainRuntime } from '@arco-cli/core/dist/cli';\nimport { Logger, LoggerAspect, LoggerMain } from '@arco-cli/core/dist/logger';\nimport { DEFAULT_ENV } from '@arco-cli/legacy/dist/constants';\n\nimport { Component } from '@aspect/component';\n\nimport { EnvRuntime, Runtime } from './runtime';\nimport { EnvsAspect } from './envs.aspect';\nimport { Environment } from './environment';\nimport { EnvDefinition } from './envDefinition';\nimport { EnvNotFoundError } from './exceptions/envNotFoundError';\nimport { EnvService } from './envService';\n\ntype EnvsSlot = SlotRegistry<Environment>;\ntype ServiceSlot = SlotRegistry<EnvService<any>>;\n\nexport type EnvTransformer = (env: Environment) => Environment;\n\nexport class EnvsMain {\n  static runtime = MainRuntime;\n\n  static dependencies = [LoggerAspect];\n\n  static slots = [Slot.withType<Environment>(), Slot.withType<EnvService<any>>()];\n\n  static provider(\n    [loggerMain]: [LoggerMain],\n    _config,\n    [envSlot, serviceSlot]: [EnvsSlot, ServiceSlot]\n  ) {\n    const logger = loggerMain.createLogger(EnvsAspect.id);\n    return new EnvsMain(logger, envSlot, serviceSlot);\n  }\n\n  constructor(\n    private logger: Logger,\n    private envSlot: EnvsSlot,\n    private serviceSlot: ServiceSlot\n  ) {}\n\n  private async aggregateByDefs(components: Component[]): Promise<EnvRuntime[]> {\n    const envsMap = {};\n    components.forEach((component: Component) => {\n      const envDef = this.getEnv(component);\n      const envId = envDef.id;\n      const env = envDef.env;\n      // handle config as well when aggregating envs.\n      if (envsMap[envId]) {\n        envsMap[envId].components.push(component);\n      } else\n        envsMap[envId] = {\n          components: [component],\n          env,\n        };\n    });\n\n    return Promise.all(\n      Object.keys(envsMap).map(async (key) => {\n        return new EnvRuntime(key, envsMap[key].env, envsMap[key].components);\n      })\n    );\n  }\n\n  /**\n   * compose a new environment from a list of environment transformers.\n   */\n  compose(targetEnv: Environment, envTransformers: EnvTransformer[]) {\n    return envTransformers.reduce((acc, transformer) => {\n      acc = transformer(acc);\n      return acc;\n    }, targetEnv);\n  }\n\n  /**\n   * create an env transformer which overrides specific env properties.\n   */\n  override(propsToOverride: Environment): EnvTransformer {\n    return (env: Environment) => {\n      return this.merge(propsToOverride, env);\n    };\n  }\n\n  /**\n   * compose two environments into one.\n   */\n  merge<T extends Environment, S extends Environment>(\n    targetEnv: Environment,\n    sourceEnv: Environment\n  ): T & S {\n    const allNames = new Set<string>();\n    const keys = ['name', 'description'];\n\n    for (let o = sourceEnv; o !== Object.prototype; o = Object.getPrototypeOf(o)) {\n      for (const name of Object.getOwnPropertyNames(o)) {\n        allNames.add(name);\n      }\n    }\n\n    allNames.forEach((key: string) => {\n      const sourceFn = sourceEnv[key];\n      if (targetEnv[key]) return;\n\n      if (keys.includes(key)) {\n        targetEnv[key] = sourceFn;\n      } else if (sourceFn?.bind) {\n        targetEnv[key] = sourceFn.bind(sourceEnv);\n      }\n    });\n\n    return targetEnv as T & S;\n  }\n\n  getEnv(component: Component): EnvDefinition {\n    const envId = component.env;\n    const env = this.envSlot.get(component.env);\n    if (env) {\n      return new EnvDefinition(envId, env as Environment);\n    }\n    throw new EnvNotFoundError(envId);\n  }\n\n  getDefaultEnv(): EnvDefinition {\n    const defaultEnv = this.envSlot.get(DEFAULT_ENV);\n    if (!defaultEnv) throw new Error('default env must be set.');\n    return new EnvDefinition(DEFAULT_ENV, defaultEnv);\n  }\n\n  registerEnv(env: Environment) {\n    return this.envSlot.register(env);\n  }\n\n  registerService(envService: EnvService<any>) {\n    this.serviceSlot.register(envService);\n    return this;\n  }\n\n  isEnvRegistered(id: string) {\n    return Boolean(this.envSlot.get(id));\n  }\n\n  getAllRegisteredEnvs(): string[] {\n    return this.envSlot.toArray().map((envData) => envData[0]);\n  }\n\n  async createEnvironment(components: Component[]): Promise<Runtime> {\n    const envRuntimes = await this.aggregateByDefs(components);\n    return new Runtime(envRuntimes, this.logger);\n  }\n}\n\nEnvsAspect.addRuntime(EnvsMain);\n"
  },
  {
    "path": "packages/aspect/src/envs/exceptions/envNotFoundError.ts",
    "content": "import ArcoError from '@arco-cli/legacy/dist/error/arcoError';\n\nexport class EnvNotFoundError extends ArcoError {\n  constructor(id: string) {\n    super(`environment with ID: ${id} was not found`);\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/envs/executionContext.ts",
    "content": "import { EnvDefinition } from './envDefinition';\nimport { Environment } from './environment';\nimport { EnvRuntime, Runtime } from './runtime';\n\nexport class ExecutionContext {\n  constructor(\n    /**\n     * upper scope of all environment contexts.\n     */\n    readonly upper: Runtime,\n\n    /**\n     * runtime instance of the environment.\n     */\n    readonly envRuntime: EnvRuntime,\n\n    /**\n     * components applied in the execution context.\n     */\n    public components = envRuntime.components\n  ) {}\n\n  relatedContexts: string[] = [];\n\n  /**\n   * extension ID of the environment\n   */\n  get id() {\n    return this.envRuntime.id;\n  }\n\n  /**\n   * environment instance.\n   */\n  get env(): Environment {\n    return this.envRuntime.env;\n  }\n\n  get envDefinition(): EnvDefinition {\n    return new EnvDefinition(this.id, this.env);\n  }\n\n  apply<T>(name: string, args: any[]): T {\n    if (!this.env[name]) {\n      throw new Error(`method ${name} not implemented`);\n    }\n\n    return this.env[name].apply(this.env, ...args);\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/envs/index.ts",
    "content": "import { EnvsAspect } from './envs.aspect';\n\nexport default EnvsAspect;\nexport { EnvsAspect };\nexport type { EnvsMain, EnvTransformer } from './envs.main.runtime';\nexport { EnvService } from './envService';\nexport { EnvDefinition } from './envDefinition';\nexport { ExecutionContext } from './executionContext';\nexport { EnvsExecutionResult } from './runtime';\nexport * from './environment';\n"
  },
  {
    "path": "packages/aspect/src/envs/runtime/envRuntime.ts",
    "content": "import { Component } from '@aspect/component';\n\nimport { Environment } from '../environment';\n\nexport class EnvRuntime {\n  constructor(\n    /**\n     * ID of the wrapping extension.\n     */\n    readonly id: string,\n\n    /**\n     * Environment\n     */\n    readonly env: Environment,\n\n    /**\n     * components to be loaded in the environment\n     */\n    readonly components: Component[]\n  ) {}\n}\n"
  },
  {
    "path": "packages/aspect/src/envs/runtime/envsExecutionResult.ts",
    "content": "import { flatten } from 'lodash';\nimport { EnvResult } from './runtime';\nimport { EnvServiceExecutionResult } from '../envService';\n\nexport class EnvsExecutionResult<T extends EnvServiceExecutionResult> {\n  constructor(readonly results: EnvResult<T>[]) {}\n\n  hasErrors() {\n    return Boolean(this.errors.length);\n  }\n\n  get errors(): Error[] {\n    return flatten(this.results.map((envResult) => this.getErrorsOfEnv(envResult)));\n  }\n\n  getErrorsOfEnv(envResult: EnvResult<T>): Error[] {\n    const execError = envResult.error;\n    const errors = envResult.data ? envResult.data.errors || [] : [];\n    if (execError) errors.push(execError);\n    return errors;\n  }\n\n  /**\n   * if only one error is found, throw it. otherwise, summarize the errors per env and throw the\n   * output\n   */\n  throwErrorsIfExist() {\n    if (!this.errors || !this.errors.length) return;\n    if (this.errors.length === 1 && this.errors[0] instanceof Error) throw this.errors[0];\n    const errorsPerEnvs = this.results.map((envResult) => this.getEnvErrorsAsString(envResult));\n    const errorOutput = errorsPerEnvs.join('\\n\\n');\n    throw new Error(errorOutput);\n  }\n\n  getEnvErrorsAsString(envResult: EnvResult<T>): string {\n    const errors = this.getErrorsOfEnv(envResult);\n    if (!errors.length) return '';\n    const title = `found ${errors.length} error(s) for ${envResult.env.id}`;\n    const errorsStr = errors.map((error) => `${error.message}\\n${error.stack}`).join('\\n');\n    return `${title}\\n${errorsStr}`;\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/envs/runtime/index.ts",
    "content": "export { Runtime } from './runtime';\nexport { EnvRuntime } from './envRuntime';\nexport { EnvsExecutionResult } from './envsExecutionResult';\n"
  },
  {
    "path": "packages/aspect/src/envs/runtime/runtime.ts",
    "content": "import { Logger } from '@arco-cli/core/dist/logger';\nimport mapSeries from 'p-map-series';\nimport { ExecutionContext } from '../executionContext';\nimport { EnvService, EnvServiceExecutionResult } from '../envService';\nimport { EnvRuntime } from './envRuntime';\nimport { EnvsExecutionResult } from './envsExecutionResult';\n\nexport interface EnvResult<T extends EnvServiceExecutionResult> {\n  env: EnvRuntime;\n  data?: T;\n  error?: Error;\n}\n\nexport class Runtime {\n  constructor(\n    /**\n     * runtime instances of the environments.\n     */\n    readonly runtimeEnvs: EnvRuntime[],\n\n    private logger: Logger\n  ) {}\n\n  getEnvExecutionContext(): ExecutionContext[] {\n    return this.runtimeEnvs.map((env) => new ExecutionContext(this, env));\n  }\n\n  /**\n   * execute a service once for all environments.\n   */\n  async runOnce<T>(service: EnvService<T>, options?: { [key: string]: any }): Promise<any> {\n    if (!service.runOnce)\n      throw new Error('a service must implement `runOnce()` in order to be executed');\n    const envsExecutionContext = this.getEnvExecutionContext();\n    const serviceResult = await service.runOnce(envsExecutionContext, options);\n    return serviceResult;\n  }\n\n  /**\n   * execute a service on each one of the environments.\n   */\n  async run<T>(\n    /**\n     * environment service to execute.\n     */\n    service: EnvService<T>,\n\n    /**\n     * options to proxy to the service upon execution.\n     */\n    options?: { [key: string]: any }\n  ): Promise<EnvsExecutionResult<T>> {\n    if (!service.run) throw new Error('a service must implement `run()` in order to be executed');\n\n    const contexts: EnvResult<T>[] = await mapSeries(this.runtimeEnvs, async (env) => {\n      try {\n        const serviceResult = await service.run(new ExecutionContext(this, env), options);\n        return {\n          env,\n          data: serviceResult,\n        };\n      } catch (err) {\n        this.logger.error(err.message, err);\n        this.logger.consoleFailure(\n          `service \"${service.name}\" of env \"${env.id}\" has failed. error: ${err.message}`\n        );\n        return {\n          env,\n          error: err,\n        };\n      }\n    });\n\n    return new EnvsExecutionResult(contexts);\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/envs/types.ts",
    "content": "import type { StyleCompilerOptions } from '@arco-cli/service/dist/compiler';\n\nimport type { WebpackConfigTransformer } from '../webpack';\nimport type { TsConfigTransformer } from '../typescript';\n\n/**\n * env config transformers allow user to extend\n */\nexport type ArcoEnvConfig = {\n  /**\n   * extend config of Jest\n   */\n  jest?: {\n    /**\n     * specify the path of Jest config file\n     */\n    jestConfigPath?: string;\n    /**\n     * specify the path Jest module for testing\n     */\n    jestModulePath?: string;\n  };\n  /**\n   * extend config of Webpack bundler\n   */\n  webpack?: {\n    /**\n     * extend the webpack config for component preview product\n     */\n    previewConfig?: WebpackConfigTransformer[];\n    /**\n     * extend the webpack config for component development\n     */\n    devServerConfig?: WebpackConfigTransformer[];\n  };\n  /**\n   * extend config of TypeScript compiler\n   */\n  typescript?: {\n    /**\n     * specify the module of TypeScript for building\n     */\n    tsModule?: any;\n    /**\n     * extend build config for TypeScript\n     */\n    buildConfig?: TsConfigTransformer[];\n  };\n  /**\n   * extend config of Less compiler\n   */\n  less?: {\n    /**\n     * option for less.render function. visit https://lesscss.org/usage/#programmatic-usage\n     */\n    lessOptions?: Record<string, any>;\n    /**\n     * whether to combine all raw style files to one\n     */\n    combine?: StyleCompilerOptions['combine'];\n    /**\n     * compile\n     */\n    compile?: StyleCompilerOptions['compile'];\n  };\n  /**\n   * extend config of Sass compiler\n   */\n  sass?: {\n    /**\n     * option for sass.compile function. visit https://sass-lang.com/documentation/js-api/modules#compile\n     */\n    sassOptions?: Record<string, any>;\n    /**\n     * whether to combine all raw style files to one\n     */\n    combine?: StyleCompilerOptions['combine'];\n    /**\n     * compile\n     */\n    compile?: StyleCompilerOptions['compile'];\n  };\n  /**\n   * extend config for ts-document, which parse API docs from TypeScript declaration\n   */\n  tsDocument?: {\n    /**\n     * Receive all generation configs for ts-document. visit https://www.npmjs.com/package/ts-document\n     */\n    tsDocumentOptions?: Record<string, any>;\n  };\n};\n"
  },
  {
    "path": "packages/aspect/src/index.ts",
    "content": "// don't write any content here\n// we create this file to make require.resolve() can find path of this package\n"
  },
  {
    "path": "packages/aspect/src/jest/exceptions/index.ts",
    "content": "export { JestError } from './jestError';\n"
  },
  {
    "path": "packages/aspect/src/jest/exceptions/jestError.ts",
    "content": "export class JestError extends Error {\n  constructor(\n    message: string,\n    private _stack?: string | null,\n    public readonly code?: unknown,\n    public readonly type?: string\n  ) {\n    super(message);\n  }\n\n  get stack() {\n    return this._stack;\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/jest/index.ts",
    "content": "import { JestAspect } from './jest.aspect';\n\nexport default JestAspect;\nexport { JestAspect };\nexport type { JestMain } from './jest.main.runtime';\n"
  },
  {
    "path": "packages/aspect/src/jest/jest.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const JestAspect = Aspect.create({\n  id: 'arco.aspect/jest',\n});\n\nexport default JestAspect;\n"
  },
  {
    "path": "packages/aspect/src/jest/jest.main.runtime.ts",
    "content": "import { MainRuntime } from '@arco-cli/core/dist/cli';\nimport { JestAspect } from './jest.aspect';\nimport { JestTester, JestTesterOptions } from './jest.tester';\n\nexport class JestMain {\n  static runtime = MainRuntime;\n\n  static dependencies = [];\n\n  static slots = [];\n\n  static provider() {\n    return new JestMain();\n  }\n\n  constructor() {}\n\n  createTester(jestConfig: any, jestModulePath?: string, opts?: JestTesterOptions) {\n    jestModulePath = jestModulePath || require.resolve('jest');\n    return new JestTester(JestAspect.id, jestConfig, jestModulePath, opts);\n  }\n}\n\nJestAspect.addRuntime(JestMain);\n"
  },
  {
    "path": "packages/aspect/src/jest/jest.tester.ts",
    "content": "import path from 'path';\nimport type jest from 'jest';\nimport { readFileSync } from 'fs-extra';\nimport { TestResult as JestTestResult } from '@jest/test-result';\nimport { Tester, TesterContext, Tests } from '@arco-cli/service/dist/tester';\nimport { parseCliRawArgs } from '@arco-cli/core/dist/cli/utils';\nimport { ComponentResult } from '@arco-cli/legacy/dist/workspace/componentResult';\nimport { ComponentMap } from '@aspect/component';\n\nimport { JestError } from './exceptions';\n\nexport type JestTesterOptions = {\n  /**\n   * add more root paths to look for tests.\n   */\n  roots?: string[];\n};\n\nexport class JestTester implements Tester {\n  displayName = 'Jest';\n\n  private readonly jestModule: typeof jest;\n\n  constructor(\n    readonly id: string,\n    readonly jestConfigPath: string,\n    private jestModulePath: string,\n    _opts: JestTesterOptions = {}\n  ) {\n    this.jestModule = require(this.jestModulePath);\n  }\n\n  private convertJestCliOptions(option): typeof option {\n    // jest cli options with alias\n    // https://jestjs.io/docs/29.3/cli\n    const jestOptionAliasMap = {\n      b: 'bail',\n      c: 'config',\n      collectCoverage: 'coverage',\n      e: 'expand',\n      w: 'maxWorkers',\n      o: 'onlyChanged',\n      i: 'runInBand',\n      t: 'testNamePattern',\n      u: 'updateSnapshot',\n      v: 'version',\n    };\n\n    const { _: args, ...optionsWithAlias } = option;\n    const result = { ...optionsWithAlias };\n\n    if (args?.length) {\n      const regexForTestFiles = args[0];\n      if (/\\.(js|jsx|ts|tsx)$/.test(regexForTestFiles)) {\n        result.testMatch = [regexForTestFiles];\n      } else {\n        result.testNamePattern = regexForTestFiles;\n      }\n    }\n\n    // convert 'true' | 'false' to boolean\n    Object.entries(result).forEach(([key, value]) => {\n      if (value === 'true') {\n        result[key] = true;\n      } else if (value === 'false') {\n        result[key] = false;\n      }\n    });\n\n    Object.entries(jestOptionAliasMap).forEach(([alias, optionName]) => {\n      if (alias in result) {\n        result[optionName] = result[alias];\n        delete result[alias];\n      }\n    });\n\n    return result;\n  }\n\n  displayConfig(): string {\n    return readFileSync(this.jestConfigPath, 'utf8');\n  }\n\n  version(): string {\n    return this.jestModule.getVersion();\n  }\n\n  private getErrors(testResult: JestTestResult[]): JestError[] {\n    return testResult.reduce((errors: JestError[], test) => {\n      if (test.testExecError) {\n        const { message, stack, code, type } = test.testExecError;\n        errors.push(new JestError(message, stack, code, type));\n      } else if (test.failureMessage) {\n        errors.push(new JestError(test.failureMessage));\n      }\n      return errors;\n    }, []);\n  }\n\n  private attachTestsToComponent(testerContext: TesterContext, testResults: JestTestResult[]) {\n    return ComponentMap.as(testerContext.components, (component) => {\n      return testResults.filter((test) => {\n        const componentDirAbs = path.join(testerContext.rootPath, component.componentDir);\n        return test.testFilePath.startsWith(componentDirAbs);\n      });\n    });\n  }\n\n  private buildTestsObj(\n    componentTestMap: ComponentMap<JestTestResult[] | undefined>\n  ): ComponentResult[] {\n    return componentTestMap\n      .toArray()\n      .map(([component, testsFiles]) => {\n        return testsFiles?.length\n          ? {\n              id: component.id,\n              errors: this.getErrors(testsFiles),\n            }\n          : null;\n      })\n      .filter(Boolean);\n  }\n\n  async test(context: TesterContext): Promise<Tests> {\n    const config: jest.Config = {\n      rootDir: context.rootPath,\n      roots: [context.rootPath],\n    };\n\n    if (context.watch) {\n      config.watchAll = true;\n      config.cache = false;\n    }\n\n    if (context.components) {\n      const testMatch: string[] = [];\n      const collectCoverageFrom: string[] = [];\n\n      context.components.forEach(({ rootDir, componentDir, entries }) => {\n        // rootDir is the entry of package source files\n        // find test files from rootDir if no component pattern is specified\n        const includeDir = context.pattern ? componentDir : rootDir;\n        testMatch.push(\n          ...entries.testFilePatterns.map((testFilePattern) =>\n            path.join('**', includeDir, testFilePattern)\n          )\n        );\n        collectCoverageFrom.push(\n          ...[\n            path.join('**', includeDir, '**/*.[jt]s?(x)'),\n            path.join('!**', includeDir, '**/{style,__docs__}/*'),\n          ]\n        );\n      });\n\n      // unique pattern strings\n      config.testMatch = [...new Set(testMatch)];\n      config.collectCoverageFrom = [...new Set(collectCoverageFrom)];\n    }\n\n    // eslint-disable-next-line @typescript-eslint/no-var-requires\n    const jestConfig = require(this.jestConfigPath);\n    const jestConfigWithSpecs = Object.assign(jestConfig, config);\n    const { parsed: jestCliOptions } = parseCliRawArgs('jest', context.rawTesterArgs);\n    const testsOutput = await this.jestModule.runCLI(\n      { ...jestConfigWithSpecs, ...this.convertJestCliOptions(jestCliOptions) },\n      [this.jestConfigPath]\n    );\n\n    const testResults = testsOutput.results.testResults;\n    const componentsWithTests = this.attachTestsToComponent(context, testResults);\n    const componentTestResults = this.buildTestsObj(componentsWithTests);\n\n    return new Tests(componentTestResults);\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/less/compilerOptions.ts",
    "content": "import type { CompilerOptions, StyleCompilerOptions } from '@arco-cli/service/dist/compiler';\n\nexport type LessCompilerOptions = {\n  /**\n   * option for less.render function\n   */\n  lessOptions?: Record<string, any>;\n} & StyleCompilerOptions &\n  Partial<CompilerOptions>;\n"
  },
  {
    "path": "packages/aspect/src/less/index.ts",
    "content": "import { LessAspect } from './less.aspect';\n\nexport default LessAspect;\nexport { LessAspect };\nexport type { LessMain } from './less.main.runtime';\nexport type { LessCompilerOptions } from './compilerOptions';\n"
  },
  {
    "path": "packages/aspect/src/less/less.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const LessAspect = Aspect.create({\n  id: 'arco.aspect/less',\n});\n\nexport default LessAspect;\n"
  },
  {
    "path": "packages/aspect/src/less/less.compiler.ts",
    "content": "import path from 'path';\nimport minimatch from 'minimatch';\nimport { render, version } from 'less';\nimport type { ComponentResult } from '@arco-cli/legacy/dist/workspace/componentResult';\nimport type { BuildContext, BuildTaskResult } from '@arco-cli/service/dist/builder';\nimport type { Compiler } from '@arco-cli/service/dist/compiler';\nimport { compileStyle } from '@arco-cli/service/dist/compiler/utils/compileStyle';\nimport {\n  DEFAULT_DIST_DIRNAME,\n  DEFAULT_BUILD_IGNORE_PATTERNS,\n} from '@arco-cli/legacy/dist/constants';\n\nimport type { LessCompilerOptions } from './compilerOptions';\n\nexport class LessCompiler implements Compiler {\n  readonly displayName = 'Less';\n\n  distDir: string;\n\n  shouldCopySourceFiles = true;\n\n  ignorePatterns = DEFAULT_BUILD_IGNORE_PATTERNS;\n\n  lessOptions: LessCompilerOptions['lessOptions'];\n\n  combine: LessCompilerOptions['combine'];\n\n  userCustomCompileFn: LessCompilerOptions['compile'];\n\n  constructor(readonly id: string, options: LessCompilerOptions) {\n    this.distDir = options.distDir || DEFAULT_DIST_DIRNAME;\n    this.lessOptions = options.lessOptions || {};\n    this.combine = options.combine || false;\n    this.userCustomCompileFn = options.compile;\n  }\n\n  getDistPathBySrcPath(srcPath: string): string {\n    return srcPath.replace('.less', '.css');\n  }\n\n  isFileSupported(filePath: string): boolean {\n    return filePath.endsWith('.less');\n  }\n\n  version(): string {\n    return version.join('.');\n  }\n\n  getDistDir() {\n    return this.distDir;\n  }\n\n  async build(context: BuildContext): Promise<BuildTaskResult> {\n    const workspaceNodeModulePath = path.resolve(context.workspace.path, 'node_modules');\n    const results: ComponentResult[] = [];\n\n    for (const component of context.components) {\n      const packageNodeModulePath = path.resolve(component.packageDirAbs, 'node_modules');\n      // eslint-disable-next-line no-await-in-loop\n      const componentResult = await compileStyle({\n        component,\n        distDir: this.distDir,\n        shouldCopySourceFiles: this.shouldCopySourceFiles,\n        rawFileExt: 'less',\n        combine: this.combine,\n        compile: async ({ pathSource, getContents }) => {\n          const { css } = await render(getContents(), {\n            javascriptEnabled: true,\n            ...this.lessOptions,\n            paths: [\n              path.dirname(pathSource),\n              packageNodeModulePath,\n              workspaceNodeModulePath,\n              ...(this.lessOptions?.paths || []),\n            ],\n          });\n          return css;\n        },\n        userCustomCompileFn: this.userCustomCompileFn,\n        filter: (file) => {\n          for (const pattern of this.ignorePatterns) {\n            if (minimatch(file.path, pattern)) {\n              return false;\n            }\n          }\n          return this.isFileSupported(file.path);\n        },\n      });\n\n      results.push(componentResult);\n    }\n\n    return {\n      componentsResults: results,\n    };\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/less/less.main.runtime.ts",
    "content": "import { MainRuntime } from '@arco-cli/core/dist/cli';\n\nimport { LessAspect } from './less.aspect';\nimport { LessCompiler } from './less.compiler';\nimport type { LessCompilerOptions } from './compilerOptions';\n\nexport class LessMain {\n  static runtime = MainRuntime;\n\n  static dependencies = [];\n\n  static slots = [];\n\n  static async provider() {\n    return new LessMain();\n  }\n\n  constructor() {}\n\n  createCompiler(options: LessCompilerOptions = {}) {\n    return new LessCompiler(LessAspect.id, options);\n  }\n}\n\nLessAspect.addRuntime(LessMain);\n"
  },
  {
    "path": "packages/aspect/src/mdx/index.ts",
    "content": "import { MDXAspect } from './mdx.aspect';\n\nexport default MDXAspect;\nexport { MDXAspect };\nexport type { MDXMain } from './mdx.main.runtime';\n"
  },
  {
    "path": "packages/aspect/src/mdx/loader/compileOutput.ts",
    "content": "import { VFile } from 'vfile';\n\nimport type { DocOutline, DocSnippet } from '@aspect/docs';\n\nimport { ImportSpecifier } from './importSpecifier';\n\nexport class CompileOutput {\n  constructor(readonly file: VFile, private _renderer: string) {}\n\n  get renderer() {\n    return this._renderer;\n  }\n\n  changeRenderer(renderer: string) {\n    this._renderer = renderer;\n  }\n\n  /**\n   * get the mdx file metadata.\n   */\n  getMetadata(): Record<string, any> {\n    return (this.file.data as any).frontmatter;\n  }\n\n  /**\n   * get headings of markdown.\n   */\n  getOutline(): DocOutline {\n    return (this.file.data as any).headings;\n  }\n\n  /**\n   * get all snippets of doc\n   */\n  getSnippets(): DocSnippet[] {\n    return (this.file.data as any).snippets || [];\n  }\n\n  /**\n   * get all import specifiers.\n   */\n  getImportSpecifiers(): ImportSpecifier[] {\n    const data: any = this.file.data;\n    return data.imports;\n  }\n\n  /**\n   * get the mdx file contents. including the renderer.\n   */\n  get contents() {\n    return `${this.renderer}\\n${this.file.contents}`;\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/mdx/loader/importSpecifier.ts",
    "content": "export type ImportSpecifier = {\n  /**\n   * relative/absolute or module name. e.g. the `y` in the example of `import x from 'y';`\n   */\n  fromModule: string;\n\n  /**\n   * is default import (e.g. `import x from 'y';`)\n   */\n  isDefault?: boolean;\n\n  /**\n   * the name used to identify the module, e.g. the `x` in the example of `import x from 'y';`\n   */\n  identifier?: string;\n};\n"
  },
  {
    "path": "packages/aspect/src/mdx/loader/index.ts",
    "content": "import { mdxLoader } from './mdxLoader';\nimport { compile, compileSync } from './mdxCompiler';\n\nexport default mdxLoader;\nexport { mdxLoader };\nexport { compile, compileSync };\n"
  },
  {
    "path": "packages/aspect/src/mdx/loader/mdxCompiler.ts",
    "content": "import vfile from 'vfile';\nimport mdx from '@mdx-js/mdx';\nimport detectFrontmatter from 'remark-frontmatter';\nimport remarkNotes from 'remark-admonitions';\n\nimport {\n  extractComponentDemos,\n  extractHeadings,\n  extractImports,\n  extractMetadata,\n} from './remarkPlugins';\nimport { CompileOutput } from './compileOutput';\n\nexport type MDXCompilerOptions = {\n  remarkPlugins: any[];\n  rehypePlugins: any[];\n  compilers: any[];\n  filePath?: string;\n  renderer: string;\n  arcoFlavour: boolean;\n  extractSnippets?: boolean;\n};\n\n// these components name come from @arco-cli/ui-foundation-react/dist/markdown/components\n// can not import from package above, because that's a pure ESM package\nconst COMPONENT_NAME_DEMO_VIEW = 'ArcoDemoView';\n\nconst DEFAULT_RENDERER = `\n// @ts-nocheck\nimport React from 'react'\nimport { mdx } from '@mdx-js/react'\n\n/* @jsxRuntime classic */\n/* @jsx mdx */\n`;\n\nconst DEFAULT_OPTIONS: Partial<MDXCompilerOptions> = {\n  remarkPlugins: [remarkNotes],\n  compilers: [],\n  renderer: DEFAULT_RENDERER,\n  arcoFlavour: true,\n  extractSnippets: false,\n};\n\n/**\n * compile a mdx file with frontmatter formatted (yaml) metadata.\n * example:\n * ```\n * ---\n * title: Something\n * labels: ['some', 'labels']\n * ---\n * ```\n */\nexport function compile(\n  content: string,\n  options: Partial<MDXCompilerOptions> = {}\n): Promise<CompileOutput> {\n  const contentFile = getFile(content, options.filePath);\n  return new Promise((resolve, reject) => {\n    const mdxCompiler = createCompiler(options);\n    mdxCompiler.process(contentFile, (err: Error | undefined, file: any) => {\n      if (err) return reject(err);\n      const output = new CompileOutput(file, DEFAULT_RENDERER);\n      return resolve(output);\n    });\n  });\n}\n\n/**\n * sync compilation of mdx content.\n */\nexport function compileSync(\n  mdxContent: string,\n  options: Partial<MDXCompilerOptions> = {}\n): CompileOutput {\n  const contentFile = getFile(mdxContent, options.filePath);\n  const mdxCompiler = createCompiler(options);\n  const file = mdxCompiler.processSync(contentFile);\n  return new CompileOutput(file, DEFAULT_RENDERER);\n}\n\nfunction getFile(contents: string, path?: string) {\n  return path ? vfile({ contents, path }) : vfile(contents);\n}\n\nfunction createCompiler(opts: Partial<MDXCompilerOptions>) {\n  const options = {\n    ...DEFAULT_OPTIONS,\n    ...opts,\n  };\n  const mustPlugins = options.arcoFlavour\n    ? [\n        [detectFrontmatter, ['yaml']],\n        extractMetadata,\n        extractImports,\n        extractHeadings.bind(null),\n        extractComponentDemos.bind(null, COMPONENT_NAME_DEMO_VIEW, options.extractSnippets),\n      ]\n    : [extractImports];\n  const mustRehypePlugins = [];\n\n  const compilerOpts = Object.assign(options, {\n    remarkPlugins: options.remarkPlugins ? mustPlugins.concat(options.remarkPlugins) : mustPlugins,\n    rehypePlugins: options.rehypePlugins\n      ? mustRehypePlugins.concat(options.rehypePlugins)\n      : mustRehypePlugins,\n  });\n\n  return mdx.createCompiler(compilerOpts);\n}\n"
  },
  {
    "path": "packages/aspect/src/mdx/loader/mdxLoader.ts",
    "content": "import { compile, MDXCompilerOptions } from './mdxCompiler';\n\nexport type MDXLoaderOptions = {\n  preProcessFile?: (file: { content: string; path: string }) => string;\n} & Partial<MDXCompilerOptions>;\n\n/**\n * arco mdx webpack loader.\n * this loader allows compilation of Arco flavoured MDX in webpack.\n */\nexport async function mdxLoader(content: string) {\n  const callback = this.async();\n  const filePath = this.resourcePath;\n  const { preProcessFile, ...compileOptions }: MDXLoaderOptions = {\n    ...this.getOptions(),\n  };\n\n  if (typeof preProcessFile === 'function') {\n    content = preProcessFile({ content, path: filePath }) ?? content;\n  }\n\n  try {\n    const output = await compile(content, { ...compileOptions, filePath });\n    return callback(null, output.contents);\n  } catch (err: any) {\n    return callback(err, null);\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/mdx/loader/remarkPlugins/extractComponentDemos.ts",
    "content": "// TODO try to solve it: demo file content updating won't trigger mdx compiling, then code-text won't update\nimport visit from 'unist-util-visit';\nimport path from 'path';\nimport glob from 'glob';\nimport fs from 'fs-extra';\n\nimport type { DocSnippet } from '@aspect/docs/type';\n\nexport function extractComponentDemos(demoViewComponentName: string, extractSnippets = false) {\n  return function transformer(tree, file) {\n    const imports = file.data.imports || [];\n    const snippets: DocSnippet[] = [];\n\n    if (!demoViewComponentName) return;\n\n    // this will visit div like below\n    // <div data-arco-demo=\"BasicDemo\">...anything from user</div>\n    visit(tree, 'jsx', (node: any) => {\n      if (/^<div/i.test(node.value)) {\n        const [, attribute] = node.value.match(/^<div([^>]*)>/i) || [];\n        const metadata: { demo?: string } = {};\n\n        (attribute || '').replace(/data-arco-(\\w+)=\"([^\"]+)\"/i, (_, key, value) => {\n          metadata[key] = value;\n          return '';\n        });\n\n        let demoCode = '';\n        let demoExtname = '';\n        for (const { identifier, fromModule } of imports) {\n          if (identifier === metadata.demo) {\n            let demoPath = path.join(file.dirname, fromModule);\n            if (!/\\.[jt]sx?$/.test(demoPath)) {\n              const [globPath] = glob.sync(`${demoPath}{.*,/index.*}`);\n              demoPath = globPath || demoPath;\n            }\n\n            demoExtname = demoPath.split('.').pop();\n\n            try {\n              demoCode = fs.readFileSync(demoPath).toString();\n            } catch (e) {}\n\n            break;\n          }\n        }\n\n        if (metadata.demo) {\n          if (extractSnippets) {\n            snippets.push({\n              code: demoCode,\n              language: demoExtname,\n            });\n          }\n\n          const encoder = new TextEncoder();\n          node.value = `<${demoViewComponentName} children={${\n            node.value\n          }}  code={{ needDecode: true, value: '${encoder.encode(\n            demoCode\n          )}' }} language=\"${demoExtname}\" />`;\n        }\n\n        file.data.snippets = snippets;\n      }\n    });\n  };\n}\n"
  },
  {
    "path": "packages/aspect/src/mdx/loader/remarkPlugins/extractHeadings.ts",
    "content": "import visit from 'unist-util-visit';\n\nexport function extractHeadings() {\n  const headings = [];\n  const getHeadingText = (node, text = '') => {\n    const nodeTypeHasTextValue = ['inlineCode', 'text'];\n    if (Array.isArray(node.children)) {\n      for (const c of node.children) {\n        text += getHeadingText(c);\n      }\n    } else if (nodeTypeHasTextValue.indexOf(node.type) > -1) {\n      text += node.value;\n    }\n    return text;\n  };\n\n  return function transformer(tree, file) {\n    visit(tree, 'heading', (node: any) => {\n      const text = getHeadingText(node);\n      const heading = {\n        text,\n        depth: node.depth,\n      };\n      headings.push(heading);\n    });\n\n    file.data.headings = headings;\n  };\n}\n"
  },
  {
    "path": "packages/aspect/src/mdx/loader/remarkPlugins/extractImports.ts",
    "content": "import visit from 'unist-util-visit';\nimport { detectiveEs6 } from '@arco-cli/legacy/dist/workspace/component/dependencies/detectives';\n\nimport type { ImportSpecifier } from '../importSpecifier';\n\nexport function extractImports() {\n  return function transformer(tree, file) {\n    visit(tree, 'import', (node: any) => {\n      const es6Import = detectiveEs6(node.value);\n      const imports: ImportSpecifier[] = Object.keys(es6Import).flatMap((dep) => {\n        if (!es6Import[dep].importSpecifiers) {\n          return {\n            fromModule: dep,\n          };\n        }\n        return es6Import[dep].importSpecifiers.map((importSpecifier) => ({\n          fromModule: dep,\n          identifier: importSpecifier.name,\n          isDefault: importSpecifier.isDefault,\n        }));\n      });\n      (file.data.imports ||= []).push(...imports);\n    });\n  };\n}\n"
  },
  {
    "path": "packages/aspect/src/mdx/loader/remarkPlugins/extractMetadata.ts",
    "content": "import yaml from 'yaml';\nimport visit from 'unist-util-visit';\nimport remove from 'unist-util-remove';\n\nexport function extractMetadata() {\n  return function transformer(tree, file) {\n    visit(tree, 'yaml', (node: any) => {\n      try {\n        file.data.frontmatter = yaml.parse(node.value, { prettyErrors: true });\n      } catch (err: any) {\n        throw new Error(\n          `failed extracting metadata/front-matter using Yaml lib, due to an error (please disregard the line/column): ${err.message}`\n        );\n      }\n    });\n\n    remove(tree, 'yaml');\n  };\n}\n"
  },
  {
    "path": "packages/aspect/src/mdx/loader/remarkPlugins/index.ts",
    "content": "export { extractComponentDemos } from './extractComponentDemos';\nexport { extractHeadings } from './extractHeadings';\nexport { extractImports } from './extractImports';\nexport { extractMetadata } from './extractMetadata';\n"
  },
  {
    "path": "packages/aspect/src/mdx/mdx.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const MDXAspect = Aspect.create({\n  id: 'arco.aspect/mdx',\n});\n\nexport default MDXAspect;\n"
  },
  {
    "path": "packages/aspect/src/mdx/mdx.docReader.ts",
    "content": "import { DocReader, Doc } from '@aspect/docs';\n\nimport { compile } from './loader';\n\nexport class MDXDocReader implements DocReader {\n  constructor(private extensions: string[]) {}\n\n  async read(path: string, contents: Buffer) {\n    const output = await compile(contents.toString('utf-8'), {\n      filePath: path,\n      extractSnippets: true,\n    });\n    const metadata = output.getMetadata();\n    const outline = output.getOutline();\n    const snippets = output.getSnippets();\n\n    return Doc.from(path, { ...metadata, outline, snippets });\n  }\n\n  isFormatSupported(format: string) {\n    return this.extensions.includes(format);\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/mdx/mdx.main.runtime.ts",
    "content": "import { MainRuntime } from '@arco-cli/core/dist/cli';\n\nimport { DocsAspect, DocsMain } from '@aspect/docs';\n\nimport MDXAspect from './mdx.aspect';\nimport { MDXDocReader } from './mdx.docReader';\n\nexport type MDXConfig = {\n  /**\n   * list of file extensions to consider as MDX files.\n   */\n  extensions: string[];\n};\n\nexport class MDXMain {\n  static runtime = MainRuntime;\n\n  static dependencies = [DocsAspect];\n\n  static slots = [];\n\n  static defaultConfig = {\n    extensions: ['.md', '.mdx'],\n  };\n\n  static provider([docs]: [DocsMain], config: MDXConfig) {\n    const mdxMain = new MDXMain();\n    docs.registerDocReader(new MDXDocReader(config.extensions));\n    return mdxMain;\n  }\n\n  constructor() {}\n}\n\nMDXAspect.addRuntime(MDXMain);\n"
  },
  {
    "path": "packages/aspect/src/multi-compiler/index.ts",
    "content": "import { MultiCompilerAspect } from './multiCompiler.aspect';\n\nexport default MultiCompilerAspect;\nexport { MultiCompilerAspect };\nexport type { MultiCompilerMain } from './multiCompiler.main.runtime';\nexport type { MultiCompiler } from './multiCompiler.compiler';\n"
  },
  {
    "path": "packages/aspect/src/multi-compiler/multiCompiler.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const MultiCompilerAspect = Aspect.create({\n  id: 'arco.aspect/multi-compiler',\n});\n\nexport default MultiCompilerAspect;\n"
  },
  {
    "path": "packages/aspect/src/multi-compiler/multiCompiler.compiler.ts",
    "content": "import { join } from 'path';\nimport pMapSeries from 'p-map-series';\nimport { Component } from '@arco-cli/aspect/dist/component';\nimport {\n  DEFAULT_DIST_DIRNAME,\n  DEFAULT_BUILD_IGNORE_PATTERNS,\n} from '@arco-cli/legacy/dist/constants';\nimport {\n  BuildContext,\n  BuildTaskResult,\n  mergeComponentResults,\n  TaskResultsList,\n} from '@arco-cli/service/dist/builder';\nimport { Compiler, CompilerOptions } from '@arco-cli/service/dist/compiler';\n\nexport class MultiCompiler implements Compiler {\n  displayName = 'Multi compiler';\n\n  distDir: string;\n\n  ignorePatterns = DEFAULT_BUILD_IGNORE_PATTERNS;\n\n  constructor(\n    readonly id: string,\n    readonly compilers: Compiler[],\n    readonly compilerOptions: Partial<CompilerOptions> = {}\n  ) {\n    this.distDir = compilerOptions.distDir || DEFAULT_DIST_DIRNAME;\n  }\n\n  private firstMatchedCompiler(filePath: string): Compiler | undefined {\n    return this.compilers.find((compiler) => compiler.isFileSupported(filePath));\n  }\n\n  version(): string {\n    return this.compilers\n      .map((compiler) => {\n        return `${compiler.displayName}@${compiler.version()}`;\n      })\n      .join('\\n');\n  }\n\n  displayConfig() {\n    return this.compilers\n      .map((compiler) => {\n        return `${compiler.displayName}\\n${compiler.displayConfig}\\n`;\n      })\n      .join('\\n');\n  }\n\n  isFileSupported(filePath: string): boolean {\n    return !!this.firstMatchedCompiler(filePath);\n  }\n\n  getDistDir() {\n    return this.distDir;\n  }\n\n  getPreviewComponentRootPath(component: Component): string {\n    const matchedCompiler = this.compilers.find(\n      (compiler) => typeof compiler.getPreviewComponentRootPath !== 'undefined'\n    );\n    return matchedCompiler?.getPreviewComponentRootPath?.(component) || '';\n  }\n\n  /**\n   * given a source file, return its parallel in the dists. e.g. \"index.ts\" => \"dist/index.js\"\n   * both, the return path and the given path are relative paths.\n   */\n  getDistPathBySrcPath(srcPath: string): string {\n    const matchedCompiler = this.firstMatchedCompiler(srcPath);\n    if (!matchedCompiler) {\n      return join(this.distDir, srcPath);\n    }\n\n    return matchedCompiler.getDistPathBySrcPath(srcPath);\n  }\n\n  async preBuild(context: BuildContext) {\n    await Promise.all(\n      this.compilers.map(async (compiler) => {\n        if (!compiler.preBuild) return;\n        await compiler.preBuild(context);\n      })\n    );\n  }\n\n  async postBuild(context: BuildContext, taskResults: TaskResultsList) {\n    await Promise.all(\n      this.compilers.map(async (compiler) => {\n        if (!compiler.postBuild) return;\n        await compiler.postBuild(context, taskResults);\n      })\n    );\n  }\n\n  async build(context: BuildContext): Promise<BuildTaskResult> {\n    const builds = await pMapSeries(this.compilers, async (compiler) => {\n      const buildResult = await compiler.build(context);\n      return buildResult.componentsResults;\n    });\n\n    return {\n      componentsResults: mergeComponentResults(builds),\n    };\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/multi-compiler/multiCompiler.main.runtime.ts",
    "content": "import { MainRuntime } from '@arco-cli/core/dist/cli';\nimport { Compiler, CompilerOptions } from '@arco-cli/service/dist/compiler';\n\nimport { MultiCompilerAspect } from './multiCompiler.aspect';\nimport { MultiCompiler } from './multiCompiler.compiler';\n\nexport class MultiCompilerMain {\n  static runtime = MainRuntime;\n\n  static async provider() {\n    return new MultiCompilerMain();\n  }\n\n  /**\n   * create a multi-compiler `Compiler` instance.\n   */\n  createCompiler(compilers: Compiler[], options: Partial<CompilerOptions> = {}) {\n    compilers.forEach((compiler) => {\n      if (options.distDir) {\n        compiler.distDir = options.distDir;\n      }\n    });\n    return new MultiCompiler(MultiCompilerAspect.id, compilers, options);\n  }\n}\n\nMultiCompilerAspect.addRuntime(MultiCompilerMain);\n"
  },
  {
    "path": "packages/aspect/src/pubsub/events/activeTabEvent.ts",
    "content": "import { ArcoBaseEvent } from './arcoBaseEvent';\n\nexport type ActiveTabEventType = {\n  activeTab: string;\n};\n\nexport class ActiveTabEvent extends ArcoBaseEvent<ActiveTabEventType> {\n  static readonly TYPE = 'preview-active-tab';\n\n  constructor(event: ActiveTabEventType) {\n    super(ActiveTabEvent.TYPE, '0.0.1', new Date().getTime(), event);\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/pubsub/events/arcoBaseEvent.ts",
    "content": "export class ArcoBaseEvent<T> {\n  constructor(\n    readonly type: string,\n    readonly version: string,\n    readonly timestamp: number,\n    readonly data: T\n  ) {}\n}\n"
  },
  {
    "path": "packages/aspect/src/pubsub/events/index.ts",
    "content": "export { ArcoBaseEvent } from './arcoBaseEvent';\nexport { SizeEvent, SizeEventType } from './sizeEvent';\nexport { LocationHashEvent, LocationHashEventType } from './locationHashEvent';\nexport { ActiveTabEvent, ActiveTabEventType } from './activeTabEvent';\n"
  },
  {
    "path": "packages/aspect/src/pubsub/events/locationHashEvent.ts",
    "content": "import { ArcoBaseEvent } from './arcoBaseEvent';\n\nexport type LocationHashEventType = {\n  hash: string;\n};\n\nexport class LocationHashEvent extends ArcoBaseEvent<LocationHashEventType> {\n  static readonly TYPE = 'preview-location-hash';\n\n  constructor(event: LocationHashEventType) {\n    super(LocationHashEvent.TYPE, '0.0.1', new Date().getTime(), event);\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/pubsub/events/sizeEvent.ts",
    "content": "import { ArcoBaseEvent } from './arcoBaseEvent';\n\nexport type SizeEventType = {\n  height: number;\n  width: number;\n};\n\nexport class SizeEvent extends ArcoBaseEvent<SizeEventType> {\n  static readonly TYPE = 'preview-size';\n\n  constructor(sizeEvent: SizeEventType) {\n    super(SizeEvent.TYPE, '0.0.1', new Date().getTime(), sizeEvent);\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/pubsub/exceptions/index.ts",
    "content": "export { PubsubNoParentError } from './noParentError';\n"
  },
  {
    "path": "packages/aspect/src/pubsub/exceptions/noParentError.ts",
    "content": "export class PubsubNoParentError extends Error {\n  constructor() {\n    super('could not connect to parent window');\n    this.name = 'PubsubNoParentError';\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/pubsub/index.ts",
    "content": "import { PubsubAspect } from './pubsub.aspect';\n\nexport default PubsubAspect;\nexport { PubsubAspect };\nexport type { PubsubMain } from './pubsub.main.runtime';\nexport type { PubsubUI } from './pubsub.ui.runtime';\nexport { ArcoBaseEvent, SizeEvent } from './events';\nexport { usePubsub, PubsubRegistry, usePubsubIframe } from './pubsubContext';\n"
  },
  {
    "path": "packages/aspect/src/pubsub/previewRuntime/index.ts",
    "content": "import { PubsubAspect } from '../pubsub.aspect';\n\nexport default PubsubAspect;\nexport { PubsubAspect };\nexport { Pubsub } from './pubsub';\nexport { PubsubPreview } from './pubsub.preview.runtime';\nexport { ArcoBaseEvent, SizeEvent } from '../events';\n"
  },
  {
    "path": "packages/aspect/src/pubsub/previewRuntime/pubsub.preview.runtime.ts",
    "content": "/**\n * Please Notice: This file will run in the preview iframe.\n */\n\nimport { PreviewRuntime } from '@arco-cli/service/dist/preview/previewRuntime';\n\nimport { Pubsub } from './pubsub';\nimport { PubsubAspect } from '../pubsub.aspect';\n\nexport class PubsubPreview extends Pubsub {\n  static runtime = PreviewRuntime;\n\n  static async provider(): Promise<PubsubPreview> {\n    return new PubsubPreview();\n  }\n}\n\nPubsubAspect.addRuntime(PubsubPreview);\n"
  },
  {
    "path": "packages/aspect/src/pubsub/previewRuntime/pubsub.ts",
    "content": "import { EventEmitter2 } from 'eventemitter2';\nimport { connectToParent, ErrorCode } from 'penpal';\n\nimport { PubsubNoParentError } from '../exceptions';\nimport {\n  ArcoBaseEvent,\n  SizeEvent,\n  LocationHashEvent,\n  SizeEventType,\n  LocationHashEventType,\n  ActiveTabEventType,\n  ActiveTabEvent,\n} from '../events';\n\ntype Callback = (event: ArcoBaseEvent<any>) => void;\n\ntype ParentMethods = {\n  pub: (topic: string, event: ArcoBaseEvent<any>) => Promise<any>;\n};\n\nexport class Pubsub {\n  private events = new EventEmitter2();\n\n  private parentPubsub?: ParentMethods;\n\n  constructor() {\n    if (this.inIframe()) {\n      this.connectToParentPubSub().catch((err) => {\n        // parent window is not required to accept connections\n        if (err instanceof PubsubNoParentError) return;\n        console.error('[Pubsub]', err);\n      });\n    }\n  }\n\n  private inIframe() {\n    try {\n      return typeof window !== 'undefined' && window.self !== window.top;\n    } catch (e) {\n      return false;\n    }\n  }\n\n  private handleMessageFromParent = (topic: string, message: ArcoBaseEvent<any>) => {\n    this.events.emit(topic, message);\n  };\n\n  private async connectToParentPubSub(retries = 10): Promise<ParentMethods | undefined> {\n    if (retries <= 0) throw new PubsubNoParentError();\n\n    try {\n      this.parentPubsub = await connectToParent<ParentMethods>({\n        timeout: 300,\n        methods: {\n          pub: this.handleMessageFromParent,\n        },\n      }).promise;\n\n      return this.parentPubsub;\n    } catch (e) {\n      if (e.code !== ErrorCode.ConnectionTimeout) throw e;\n      return this.connectToParentPubSub(retries - 1);\n    }\n  }\n\n  sub(topic: string, callback: Callback) {\n    const emitter = this.events;\n    emitter.on(topic, callback);\n\n    const unSub = () => {\n      emitter.off(topic, callback);\n    };\n    return unSub;\n  }\n\n  pub(topic: string, event: ArcoBaseEvent<any>) {\n    this.events.emit(topic, event);\n    this.parentPubsub?.pub(topic, event).catch((err) => {\n      console.error('[Pubsub.preview]', err);\n    });\n  }\n\n  reportSize(topic: string, data: SizeEventType) {\n    this.pub(topic, new SizeEvent(data));\n  }\n\n  reportLocationHash(topic: string, data: LocationHashEventType) {\n    this.pub(topic, new LocationHashEvent(data));\n  }\n\n  reportActiveTab(topic: string, data: ActiveTabEventType) {\n    this.pub(topic, new ActiveTabEvent(data));\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/pubsub/pubsub.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const PubsubAspect = Aspect.create({\n  id: 'arco.aspect/pubsub',\n});\n\nexport default PubsubAspect;\n"
  },
  {
    "path": "packages/aspect/src/pubsub/pubsub.main.runtime.ts",
    "content": "import { MainRuntime } from '@arco-cli/core/dist/cli';\n\nimport { ArcoBaseEvent } from './events';\nimport { PubsubAspect } from './pubsub.aspect';\n\nexport class PubsubMain {\n  private topicMap = {};\n\n  private createOrGetTopic = (topicUUID) => {\n    this.topicMap[topicUUID] = this.topicMap[topicUUID] || [];\n  };\n\n  public sub(topicUUID, callback) {\n    this.createOrGetTopic(topicUUID);\n    this.topicMap[topicUUID].push(callback);\n  }\n\n  public pub(topicUUID, event: ArcoBaseEvent<any>) {\n    this.createOrGetTopic(topicUUID);\n    this.topicMap[topicUUID].forEach((callback) => callback(event));\n  }\n\n  unsubscribeAll(topicId: string) {\n    delete this.topicMap[topicId];\n  }\n\n  static runtime = MainRuntime;\n\n  static async provider() {\n    return new PubsubMain();\n  }\n}\n\nPubsubAspect.addRuntime(PubsubMain);\n"
  },
  {
    "path": "packages/aspect/src/pubsub/pubsub.ui.runtime.ts",
    "content": "import { EventEmitter2 } from 'eventemitter2';\nimport { connectToChild } from 'penpal';\nimport type { AsyncMethodReturns } from 'penpal/lib/types';\nimport { UIRuntime } from '@arco-cli/service/dist/ui/ui.aspect';\n\nimport { ArcoBaseEvent } from './events';\nimport { PubsubAspect } from './pubsub.aspect';\nimport { createProvider } from './pubsubContext';\n\ntype Callback = (event: ArcoBaseEvent<any>) => void;\n\ntype PubOptions = {\n  /** forward the event to adjacent windows (including the preview iframe)  */\n  propagate?: boolean;\n};\n\ntype ChildMethods = {\n  pub: (topic: string, event: ArcoBaseEvent<any>) => any;\n};\n\nexport class PubsubUI {\n  static runtime = UIRuntime;\n\n  static dependencies = [];\n\n  static async provider() {\n    const pubsubUI = new PubsubUI();\n    return pubsubUI;\n  }\n\n  constructor() {}\n\n  private childApi?: AsyncMethodReturns<ChildMethods>;\n\n  private events = new EventEmitter2();\n\n  /**\n   * publish event to all subscribers in this window\n   */\n  private emitEvent = (topic: string, event: ArcoBaseEvent<any>) => {\n    this.events.emit(topic, event);\n  };\n\n  /**\n   * publish event to nested iframes\n   */\n  private pubToChild = (topic: string, event: ArcoBaseEvent<any>) => {\n    return this.childApi?.pub(topic, event);\n  };\n\n  private connectToIframe = (iframe: HTMLIFrameElement) => {\n    const connection = connectToChild<ChildMethods>({\n      iframe,\n      methods: {\n        pub: this.emitEvent,\n      },\n    });\n\n    connection.promise\n      .then((childConnection) => {\n        this.childApi = childConnection;\n      })\n      .catch((err) => {\n        console.error('[Pubsub.ui]', 'failed connecting to child iframe:', err);\n      });\n\n    const destroy = () => {\n      connection && connection.destroy();\n    };\n    return destroy;\n  };\n\n  sub = (topic: string, callback: Callback) => {\n    const events = this.events;\n    events.on(topic, callback);\n\n    const unSub = () => {\n      events.off(topic, callback);\n    };\n\n    return unSub;\n  };\n\n  /**\n   * publish event to all subscribers, including nested iframes.\n   */\n  pub = (topic: string, event: ArcoBaseEvent<any>, { propagate }: PubOptions = {}) => {\n    this.emitEvent(topic, event);\n\n    // opt-in to forward to iframe, as we would not want 'private' messages automatically passing to iframe\n    if (propagate) {\n      this.pubToChild(topic, event);\n    }\n  };\n\n  getPubsubContext() {\n    return createProvider({\n      connect: this.connectToIframe,\n    });\n  }\n}\n\nPubsubAspect.addRuntime(PubsubUI);\n"
  },
  {
    "path": "packages/aspect/src/pubsub/pubsubContext.tsx",
    "content": "import React, { createContext, useContext, useEffect, RefObject, ReactNode } from 'react';\n\nexport interface PubsubRegistry {\n  /**\n   * starts a connection to an iframe child.\n   * Returns a destroy function that will break the connection.\n   */\n  connect(ref: HTMLIFrameElement): () => void;\n}\n\nexport const PubsubContext = createContext<PubsubRegistry | undefined>(undefined);\n\nexport function createProvider(pubSubContext: PubsubRegistry) {\n  return function PubsubProvider({ children }: { children: ReactNode }) {\n    return <PubsubContext.Provider value={pubSubContext}>{children}</PubsubContext.Provider>;\n  };\n}\n\nexport function usePubsub() {\n  return useContext(PubsubContext);\n}\n\nexport function usePubsubIframe(ref?: RefObject<HTMLIFrameElement>) {\n  const pubSub = usePubsub();\n\n  useEffect(() => {\n    if (!ref?.current || !pubSub) return () => {};\n\n    const destroyConnection = pubSub.connect(ref.current);\n    return () => destroyConnection();\n  }, [ref?.current, pubSub]);\n}\n"
  },
  {
    "path": "packages/aspect/src/react-router/index.ts",
    "content": "import { ReactRouterAspect } from './reactRouter.aspect';\n\nexport { ReactRouterAspect };\nexport default ReactRouterAspect;\n"
  },
  {
    "path": "packages/aspect/src/react-router/reactRouter.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const ReactRouterAspect = Aspect.create({\n  id: 'arco.aspect/react-router',\n});\n\nexport default ReactRouterAspect;\n"
  },
  {
    "path": "packages/aspect/src/react-router/uiRuntime/hooks/useQuery.ts",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport { useLocation } from 'react-router-dom';\n\n/**\n * hook for using a query string.\n */\nexport function useQuery() {\n  const { search } = useLocation() || { search: '/' };\n  return new URLSearchParams(search);\n}\n"
  },
  {
    "path": "packages/aspect/src/react-router/uiRuntime/index.ts",
    "content": "export { ReactRouterAspect } from '../reactRouter.aspect';\nexport { useQuery } from './hooks/useQuery';\nexport { SlotRouter, SlotRouterProps } from './slotRouter';\nexport type { ReactRouterUI, RouteSlot } from './reactRouter.ui.runtime';\n"
  },
  {
    "path": "packages/aspect/src/react-router/uiRuntime/reactRouter.ui.runtime.tsx",
    "content": "import React from 'react';\n// eslint-disable-next-line import/no-extraneous-dependencies\nimport { NavigateFunction } from 'react-router-dom';\nimport type { Location, NavigationType, RouteProps } from 'react-router-dom';\nimport { Slot, SlotRegistry } from '@arco-cli/stone';\nimport { UIRuntime } from '@arco-cli/service/dist/ui/ui.aspect';\n\nimport { SlotRouter } from './slotRouter';\nimport { ReactRouterAspect } from '../reactRouter.aspect';\n\nexport type RouteSlot = SlotRegistry<RouteProps>;\n\nexport class ReactRouterUI {\n  static runtime = UIRuntime;\n\n  static slots = [Slot.withType<RouteProps>()];\n\n  static async provider(_deps, _config, [routeSlot]: [RouteSlot]) {\n    return new ReactRouterUI(routeSlot);\n  }\n\n  constructor(\n    /**\n     * route slot.\n     */\n    private routeSlot: RouteSlot\n  ) {}\n\n  private navigate?: NavigateFunction = undefined;\n\n  renderRoutes(routes: RouteProps[]) {\n    return <SlotRouter routes={this.routeSlot.values()} rootRoutes={routes} />;\n  }\n\n  /**\n   * register a new route.\n   */\n  register(route: RouteProps) {\n    this.routeSlot.register(route);\n    return this;\n  }\n\n  navigateTo = (\n    /** destination */\n    path: Location | string,\n    /** history action to execute (pop / push / replace) */\n    action?: NavigationType\n  ) => {\n    const state = typeof path !== 'string' ? path.state : undefined;\n\n    switch (action) {\n      case 'POP':\n        return; // TBD;\n      case 'REPLACE':\n        this.navigate?.(path, { replace: true, state });\n        return;\n      case 'PUSH':\n      default:\n        this.navigate?.(path, { state });\n    }\n  };\n}\n\nReactRouterAspect.addRuntime(ReactRouterUI);\n"
  },
  {
    "path": "packages/aspect/src/react-router/uiRuntime/slotRouter.tsx",
    "content": "import React, { PropsWithChildren } from 'react';\n// eslint-disable-next-line import/no-extraneous-dependencies\nimport { Routes, Route, RouteProps } from 'react-router-dom';\n\nexport type SlotRouterProps = PropsWithChildren<{\n  routes?: RouteProps[];\n  rootRoutes?: RouteProps[];\n  parentPath?: string;\n}>;\n\nfunction toKey(route: RouteProps) {\n  if (route.path) return route.path;\n  if (route.index) return '/';\n  return '.';\n}\n\nexport function SlotRouter({\n  routes: routesFromProps,\n  rootRoutes,\n  children,\n  parentPath,\n}: SlotRouterProps) {\n  const routes = routesFromProps || [];\n  const withRoot = routes.concat(rootRoutes || []);\n  const jsxRoutes = withRoot.map((route) => <Route key={toKey(route)} {...route} />);\n\n  if (parentPath) {\n    return (\n      <Routes>\n        <Route path={parentPath}>\n          {jsxRoutes}\n          {children}\n        </Route>\n      </Routes>\n    );\n  }\n\n  return (\n    <Routes>\n      {jsxRoutes}\n      {children}\n    </Routes>\n  );\n}\n"
  },
  {
    "path": "packages/aspect/src/sass/compilerOptions.ts",
    "content": "import { CompilerOptions, StyleCompilerOptions } from '@arco-cli/service/dist/compiler';\n\nexport type SassCompilerOptions = {\n  /**\n   * option for sass.compile function\n   */\n  sassOptions?: Record<string, any>;\n} & StyleCompilerOptions &\n  Partial<CompilerOptions>;\n"
  },
  {
    "path": "packages/aspect/src/sass/index.ts",
    "content": "import { SassAspect } from './sass.aspect';\n\nexport default SassAspect;\nexport { SassAspect };\nexport type { SassMain } from './sass.main.runtime';\nexport type { SassCompilerOptions } from './compilerOptions';\n"
  },
  {
    "path": "packages/aspect/src/sass/sass.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const SassAspect = Aspect.create({\n  id: 'arco.aspect/sass',\n});\n\nexport default SassAspect;\n"
  },
  {
    "path": "packages/aspect/src/sass/sass.compiler.ts",
    "content": "import path from 'path';\nimport minimatch from 'minimatch';\nimport { compile } from 'sass';\nimport type { Compiler } from '@arco-cli/service/dist/compiler';\nimport type { BuildContext, BuildTaskResult } from '@arco-cli/service/dist/builder';\nimport type { ComponentResult } from '@arco-cli/legacy/dist/workspace/componentResult';\nimport {\n  DEFAULT_BUILD_IGNORE_PATTERNS,\n  DEFAULT_DIST_DIRNAME,\n} from '@arco-cli/legacy/dist/constants';\nimport { compileStyle } from '@arco-cli/service/dist/compiler/utils/compileStyle';\n\nimport type { SassCompilerOptions } from './compilerOptions';\n\nexport class SassCompiler implements Compiler {\n  readonly displayName = 'Sass';\n\n  distDir: string;\n\n  shouldCopySourceFiles = true;\n\n  ignorePatterns = DEFAULT_BUILD_IGNORE_PATTERNS;\n\n  sassOptions: SassCompilerOptions['sassOptions'];\n\n  combine: SassCompilerOptions['combine'];\n\n  userCustomCompileFn: SassCompilerOptions['compile'];\n\n  constructor(readonly id: string, options: SassCompilerOptions) {\n    this.distDir = options.distDir || DEFAULT_DIST_DIRNAME;\n    this.sassOptions = options.sassOptions || {};\n    this.combine = options.combine || false;\n    this.userCustomCompileFn = options.compile;\n  }\n\n  getDistPathBySrcPath(srcPath: string): string {\n    return srcPath.replace('.scss', '.css');\n  }\n\n  isFileSupported(filePath: string): boolean {\n    return filePath.endsWith('.scss');\n  }\n\n  version(): string {\n    return '';\n  }\n\n  getDistDir() {\n    return this.distDir;\n  }\n\n  async build(context: BuildContext): Promise<BuildTaskResult> {\n    const workspaceNodeModulePath = path.resolve(context.workspace.path, 'node_modules');\n    const results: ComponentResult[] = [];\n\n    for (const component of context.components) {\n      const packageNodeModulePath = path.resolve(component.packageDirAbs, 'node_modules');\n      // eslint-disable-next-line no-await-in-loop\n      const componentResult = await compileStyle({\n        component,\n        distDir: this.distDir,\n        shouldCopySourceFiles: this.shouldCopySourceFiles,\n        rawFileExt: 'sass',\n        combine: this.combine,\n        compile: async ({ pathSource }) => {\n          return compile(pathSource, {\n            ...this.sassOptions,\n            loadPaths: [\n              path.dirname(pathSource),\n              packageNodeModulePath,\n              workspaceNodeModulePath,\n              ...(this.sassOptions?.loadPaths || []),\n            ],\n          }).css;\n        },\n        userCustomCompileFn: this.userCustomCompileFn,\n        filter: (file) => {\n          for (const pattern of this.ignorePatterns) {\n            if (minimatch(file.path, pattern)) {\n              return false;\n            }\n          }\n          return this.isFileSupported(file.path);\n        },\n      });\n\n      results.push(componentResult);\n    }\n\n    return {\n      componentsResults: results,\n    };\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/sass/sass.main.runtime.ts",
    "content": "import { MainRuntime } from '@arco-cli/core/dist/cli';\n\nimport { SassAspect } from './sass.aspect';\nimport { SassCompiler } from './sass.compiler';\nimport { SassCompilerOptions } from './compilerOptions';\n\nexport class SassMain {\n  static runtime = MainRuntime;\n\n  static dependencies = [];\n\n  static slots = [];\n\n  static async provider() {\n    return new SassMain();\n  }\n\n  constructor() {}\n\n  createCompiler(option: SassCompilerOptions = {}) {\n    return new SassCompiler(SassAspect.id, option);\n  }\n}\n\nSassAspect.addRuntime(SassMain);\n"
  },
  {
    "path": "packages/aspect/src/typescript/compilerOptions.ts",
    "content": "import type { CompilerOptions } from '@arco-cli/service/dist/compiler';\n\nexport type TypescriptCompilerOptions = {\n  /**\n   * tsconfig to use during compilation.\n   */\n  tsconfig: Record<string, any>;\n\n  /**\n   * path for .d.ts files to include during build.\n   */\n  types: string[];\n\n  /**\n   * Run the compiler for .js files. this will only affect whether to run the compiler on the files\n   * or not. It won't change the tsconfig to support or not support js files.\n   */\n  compileJs?: boolean;\n\n  /**\n   * Run the compiler for .jsx files. this will only affect whether to run the compiler on the files\n   * or not. It won't change the tsconfig to support or not support jsx files.\n   */\n  compileJsx?: boolean;\n\n  /**\n   * extend compile function\n   */\n  compile?: (\n    project: { configFilePath: string; compilerOptions: Record<string, any> },\n    originCompileFn: () => void\n  ) => void | Promise<void>;\n} & Partial<CompilerOptions>;\n"
  },
  {
    "path": "packages/aspect/src/typescript/index.ts",
    "content": "import { TypescriptAspect } from './typescript.aspect';\n\nexport default TypescriptAspect;\nexport { TypescriptAspect };\nexport { TypescriptConfigMutator } from './typescriptConfigMutator';\nexport type { TypescriptCompilerOptions } from './compilerOptions';\nexport type {\n  TypescriptMain,\n  TsConfigTransformer,\n  TsConfigTransformContext,\n} from './typescript.main.runtime';\n"
  },
  {
    "path": "packages/aspect/src/typescript/typescript.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const TypescriptAspect = Aspect.create({\n  id: 'arco.aspect/typescript',\n});\n\nexport default TypescriptAspect;\n"
  },
  {
    "path": "packages/aspect/src/typescript/typescript.compiler.ts",
    "content": "import path from 'path';\nimport fs from 'fs-extra';\nimport ts from 'typescript';\nimport { mergeWith, cloneDeep, get, set } from 'lodash';\nimport { Logger } from '@arco-cli/core/dist/logger';\nimport { Compiler } from '@arco-cli/service/dist/compiler';\nimport ArcoError from '@arco-cli/legacy/dist/error/arcoError';\nimport { BuildContext, BuildTaskResult } from '@arco-cli/service/dist/builder';\nimport { ComponentResult } from '@arco-cli/legacy/dist/workspace/componentResult';\nimport {\n  DEFAULT_DIST_DIRNAME,\n  DEFAULT_BUILD_IGNORE_PATTERNS,\n} from '@arco-cli/legacy/dist/constants';\nimport { toFsCompatible } from '@arco-cli/legacy/dist/utils';\n\nimport { TypescriptCompilerOptions } from './compilerOptions';\nimport TypescriptAspect from './typescript.aspect';\nimport { tsconfigMergeCustomizer } from './typescriptConfigMutator';\nimport { flatTSConfig } from './utils/flatTSConfig';\n\nconst FILENAME_TSCONFIG = 'tsconfig.json';\nconst FILENAME_TSCONFIG_BUILD = 'tsconfig.build.json';\n\nexport class TypescriptCompiler implements Compiler {\n  displayName = 'TypeScript';\n\n  deleteDistDir = false;\n\n  distDir: string;\n\n  artifactName: string;\n\n  ignorePatterns = DEFAULT_BUILD_IGNORE_PATTERNS;\n\n  private componentTsConfigMap: Record<string, string> = {};\n\n  constructor(\n    readonly id: string,\n    private options: TypescriptCompilerOptions,\n    private tsModule: typeof ts,\n    private logger: Logger\n  ) {\n    this.distDir = options.distDir || DEFAULT_DIST_DIRNAME;\n    this.artifactName = options.artifactName || DEFAULT_DIST_DIRNAME;\n    this.options.tsconfig ||= {};\n    this.options.tsconfig.compilerOptions ||= {};\n  }\n\n  private stringifyTsconfig(tsconfig) {\n    return JSON.stringify(tsconfig, undefined, 2);\n  }\n\n  private replaceFileExtToJs(filePath: string): string {\n    if (!this.isFileSupported(filePath)) return filePath;\n    const fileExtension = path.extname(filePath);\n    return filePath.replace(new RegExp(`${fileExtension}$`), '.js');\n  }\n\n  private getCacheDir(context: BuildContext) {\n    return context.workspace.getCacheDir(TypescriptAspect.id);\n  }\n\n  private async writeComponentTsConfig(context: BuildContext) {\n    const workspacePath = context.workspace.path;\n    await Promise.all(\n      context.components.map(async ({ id: componentId, rootDir, packageDirAbs }) => {\n        const rootDirAbs = path.join(workspacePath, rootDir);\n        const outDirAbs = path.join(packageDirAbs, this.distDir);\n        const tsconfig: Record<string, any> = cloneDeep(this.options.tsconfig);\n\n        // try to merge tsconfig.json from component package\n        // we will find file named tsconfig.json/tsconfig.build.json from package dir\n        try {\n          const tsconfigPathFromPackage = [FILENAME_TSCONFIG, FILENAME_TSCONFIG_BUILD]\n            .map((filename) => path.join(packageDirAbs, filename))\n            .find((filePathAbs) => fs.existsSync(filePathAbs));\n          if (tsconfigPathFromPackage) {\n            const tsconfigFromPackage = flatTSConfig(tsconfigPathFromPackage);\n            // TSCompilerCJS will compile source files to CommonJS modules\n            // we don't allow package tsconfig to overwrite its module configuration\n            if (\n              tsconfig.compilerOptions.module?.toLowerCase() === 'commonjs' &&\n              tsconfigFromPackage?.compilerOptions?.module\n            ) {\n              delete tsconfigFromPackage.compilerOptions.module;\n            }\n            mergeWith(tsconfig, tsconfigFromPackage, tsconfigMergeCustomizer);\n          }\n        } catch (err) {\n          this.logger.consoleFailure(err.toString());\n        }\n\n        // avoid change this.options.config directly\n        // different components might have different ts configs\n        mergeWith(\n          tsconfig,\n          {\n            include: [rootDirAbs],\n            exclude: this.ignorePatterns,\n            compilerOptions: {\n              outDir: outDirAbs,\n              rootDir: rootDirAbs,\n            },\n          },\n          tsconfigMergeCustomizer\n        );\n\n        // this func will change original object directly\n        const convertRelativePathsToAbs = (\n          obj: Record<string, any>,\n          keysToConvert: string[],\n          relativePathChecker?: (str) => boolean\n        ) => {\n          relativePathChecker ||= (str) => !path.isAbsolute(str);\n\n          for (const key of keysToConvert) {\n            const value = get(obj, key);\n            if (typeof value === 'string') {\n              set(\n                obj,\n                key,\n                relativePathChecker(value) ? path.resolve(packageDirAbs, value) : value\n              );\n            } else if (Array.isArray(value)) {\n              set(\n                obj,\n                key,\n                value.map((filePath) =>\n                  relativePathChecker(filePath) ? path.resolve(packageDirAbs, filePath) : filePath\n                )\n              );\n            } else if (typeof value === 'object' && value !== null) {\n              convertRelativePathsToAbs(value, Object.keys(value), relativePathChecker);\n            }\n          }\n        };\n\n        // convert tsconfig relative paths to absolute path\n        // don't convert compilerOptions.paths to absolute, because they are relative to compilerOption.baseUrl\n        convertRelativePathsToAbs(tsconfig, [\n          'include',\n          'exclude',\n          'files',\n          'compilerOptions.baseUrl',\n          'compilerOptions.typeRoots',\n        ]);\n\n        const tsconfigPath = path.join(\n          this.getCacheDir(context),\n          toFsCompatible(componentId),\n          `${this.distDir}.${FILENAME_TSCONFIG}`\n        );\n        await fs.ensureFile(tsconfigPath);\n        await fs.writeFile(tsconfigPath, this.stringifyTsconfig(tsconfig));\n        this.componentTsConfigMap[componentId] = tsconfigPath;\n      })\n    );\n  }\n\n  private async writeProjectReferencesTsConfig(context): Promise<string> {\n    const cacheDir = this.getCacheDir(context);\n    const references = context.components.map((com) => {\n      return { path: this.componentTsConfigMap[com.id] || com.packageDirAbs };\n    });\n    const tsconfig = { files: [], references };\n    const tsconfigStr = this.stringifyTsconfig(tsconfig);\n    await fs.writeFile(path.join(cacheDir, FILENAME_TSCONFIG), tsconfigStr);\n    return cacheDir;\n  }\n\n  private async runTscBuild(context: BuildContext): Promise<ComponentResult[]> {\n    const { components } = context;\n\n    if (!components.length) {\n      return [];\n    }\n\n    const componentsResults: ComponentResult[] = [];\n    const formatHost = {\n      getCanonicalFileName: (p) => p,\n      getCurrentDirectory: () => '', // it helps to get the files with absolute paths\n      getNewLine: () => this.tsModule.sys.newLine,\n    };\n\n    let currentComponentResult: Partial<ComponentResult> = { errors: [] };\n    const reportDiagnostic = (diagnostic: ts.Diagnostic) => {\n      const errorStr = process.stdout.isTTY\n        ? this.tsModule.formatDiagnosticsWithColorAndContext([diagnostic], formatHost)\n        : this.tsModule.formatDiagnostic(diagnostic, formatHost);\n      if (!diagnostic.file) {\n        // the error is general and not related to a specific file. e.g. tsconfig is missing.\n        throw new ArcoError(errorStr);\n      }\n      this.logger.consoleFailure(errorStr);\n      if (!currentComponentResult.id || !currentComponentResult.errors) {\n        throw new Error(`currentComponentResult is not defined yet for ${diagnostic.file}`);\n      }\n      currentComponentResult.errors.push(errorStr);\n    };\n\n    // this only works when `verbose` is `true` in the `ts.createSolutionBuilder` function.\n    const reportSolutionBuilderStatus = (diag: ts.Diagnostic) => {\n      const msg = diag.messageText as string;\n      this.logger.debug(msg);\n    };\n    const errorCounter = (errorCount: number) => {\n      this.logger.info(`total error found: ${errorCount}`);\n    };\n    const host = this.tsModule.createSolutionBuilderHost(\n      undefined,\n      undefined,\n      reportDiagnostic,\n      reportSolutionBuilderStatus,\n      errorCounter\n    );\n\n    const rootDir = await this.writeProjectReferencesTsConfig(context);\n    const solutionBuilder = this.tsModule.createSolutionBuilder(host, [rootDir], {\n      verbose: true,\n    });\n    const longProcessLogger = this.logger.createLongProcessLogger(\n      'compile typescript components',\n      components.length\n    );\n\n    let nextProject;\n    // eslint-disable-next-line no-cond-assign\n    while ((nextProject = solutionBuilder.getNextInvalidatedProject())) {\n      // nextProject is path of its tsconfig.json\n      const projectPath = path.dirname(nextProject.project);\n      const component = components.find((com) => {\n        // tsconfig.json for component building will be generated in cache dir named component_id\n        // find target component of this tsconfig.json\n        return path.basename(projectPath) === toFsCompatible(com.id);\n      });\n      if (!component) throw new Error(`unable to find component for ${projectPath}`);\n\n      longProcessLogger.logProgress(component.id);\n      currentComponentResult.id = component.id;\n      currentComponentResult.startTime = Date.now();\n\n      if (typeof this.options.compile === 'function') {\n        // eslint-disable-next-line no-await-in-loop\n        await this.options.compile(\n          {\n            configFilePath: nextProject.project,\n            compilerOptions: nextProject.getCompilerOptions(),\n          },\n          nextProject.done\n        );\n      } else {\n        nextProject.done();\n      }\n\n      currentComponentResult.endTime = Date.now();\n      componentsResults.push({ ...currentComponentResult } as ComponentResult);\n      currentComponentResult = { errors: [] };\n    }\n\n    longProcessLogger.end();\n    return componentsResults;\n  }\n\n  version() {\n    return this.tsModule.version;\n  }\n\n  displayConfig() {\n    return this.stringifyTsconfig(this.options.tsconfig);\n  }\n\n  getDistDir() {\n    return this.distDir;\n  }\n\n  getDistPathBySrcPath(srcPath: string) {\n    const fileWithJSExtIfNeeded = this.replaceFileExtToJs(srcPath);\n    return path.join(this.distDir, fileWithJSExtIfNeeded);\n  }\n\n  isFileSupported(filePath: string): boolean {\n    const isJsAndCompile = !!this.options.compileJs && filePath.endsWith('.js');\n    const isJsxAndCompile = !!this.options.compileJsx && filePath.endsWith('.jsx');\n    return (\n      (filePath.endsWith('.ts') ||\n        filePath.endsWith('.tsx') ||\n        isJsAndCompile ||\n        isJsxAndCompile) &&\n      !filePath.endsWith('.d.ts')\n    );\n  }\n\n  async preBuild(context: BuildContext) {\n    await this.writeComponentTsConfig(context);\n  }\n\n  async build(context: BuildContext): Promise<BuildTaskResult> {\n    const componentsResults = await this.runTscBuild(context);\n    return {\n      componentsResults,\n    };\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/typescript/typescript.main.runtime.ts",
    "content": "import ts from 'typescript';\nimport { MainRuntime } from '@arco-cli/core/dist/cli';\nimport { Compiler } from '@arco-cli/service/dist/compiler';\nimport { LoggerAspect, LoggerMain } from '@arco-cli/core/dist/logger';\nimport { TypescriptAspect } from './typescript.aspect';\nimport { TypescriptCompiler } from './typescript.compiler';\nimport { TypescriptCompilerOptions } from './compilerOptions';\nimport { TypescriptConfigMutator } from './typescriptConfigMutator';\n\nexport type TsConfigTransformContext = {\n  // mode: TsMode;\n};\n\nexport type TsConfigTransformer = (\n  config: TypescriptConfigMutator,\n  context: TsConfigTransformContext\n) => TypescriptConfigMutator;\n\nfunction runTransformersWithContext(\n  config: TypescriptConfigMutator,\n  context: TsConfigTransformContext,\n  transformers: TsConfigTransformer[] = []\n): TypescriptConfigMutator {\n  if (!Array.isArray(transformers)) return config;\n  const newConfig = transformers.reduce((acc, transformer) => {\n    return transformer(acc, context);\n  }, config);\n  return newConfig;\n}\n\nexport class TypescriptMain {\n  static runtime = MainRuntime;\n\n  static dependencies = [LoggerAspect];\n\n  static slots = [];\n\n  static provider([loggerMain]: [LoggerMain]) {\n    const logger = loggerMain.createLogger(TypescriptAspect.id);\n    return new TypescriptMain(logger);\n  }\n\n  constructor(private logger) {}\n\n  /**\n   * Create a transformer that change the ts module to CommonJS\n   */\n  getCjsTransformer(): TsConfigTransformer {\n    return (config: TypescriptConfigMutator) => {\n      config.setModule('CommonJS');\n      return config;\n    };\n  }\n\n  /**\n   * Create a transformer that change the ts module to ES2020\n   */\n  getEsmTransformer(): TsConfigTransformer {\n    return (config: TypescriptConfigMutator) => {\n      config.setModule('ES2020');\n      return config;\n    };\n  }\n\n  /**\n   * create a new compiler.\n   */\n  createCompiler(\n    options: TypescriptCompilerOptions,\n    transformers: TsConfigTransformer[] = [],\n    tsModule = ts\n  ): Compiler {\n    const configMutator = new TypescriptConfigMutator(options);\n    const transformerContext: TsConfigTransformContext = {};\n    const afterMutation = runTransformersWithContext(\n      configMutator.clone(),\n      transformerContext,\n      transformers\n    );\n    return new TypescriptCompiler(TypescriptAspect.id, afterMutation.raw, tsModule, this.logger);\n  }\n\n  /**\n   * Create a compiler instance and run the cjs transformer for it\n   */\n  createCjsCompiler(\n    options: TypescriptCompilerOptions,\n    transformers: TsConfigTransformer[] = [],\n    tsModule = ts\n  ) {\n    return this.createCompiler(options, [...transformers, this.getCjsTransformer()], tsModule);\n  }\n\n  /**\n   * Create a compiler instance and run the esm transformer for it\n   */\n  createEsmCompiler(\n    options: TypescriptCompilerOptions,\n    transformers: TsConfigTransformer[] = [],\n    tsModule = ts\n  ) {\n    return this.createCompiler(options, [...transformers, this.getEsmTransformer()], tsModule);\n  }\n}\n\nTypescriptAspect.addRuntime(TypescriptMain);\n"
  },
  {
    "path": "packages/aspect/src/typescript/typescriptConfigMutator.ts",
    "content": "import { cloneDeep, mergeWith, isArray } from 'lodash';\nimport { CompilerOptions } from 'typescript';\nimport { TypescriptCompilerOptions } from './compilerOptions';\n\nexport type Target =\n  | 'ES3'\n  | 'ES5'\n  | 'ES2015'\n  | 'ES2016'\n  | 'ES2017'\n  | 'ES2018'\n  | 'ES2019'\n  | 'ES2020'\n  | 'ESNext';\n\n// eslint-disable-next-line consistent-return\nexport function tsconfigMergeCustomizer(objValue, extendValue, key) {\n  // only concat array for tsconfig.include/exclude\n  if (['include', 'exclude'].indexOf(key) > -1 && isArray(objValue)) {\n    return objValue.concat(extendValue);\n  }\n}\n\nexport class TypescriptConfigMutator {\n  constructor(public raw: TypescriptCompilerOptions) {}\n\n  clone(): TypescriptConfigMutator {\n    return new TypescriptConfigMutator(cloneDeep(this.raw));\n  }\n\n  artifactName?: string;\n\n  setName(name: string) {\n    this.raw.name = name;\n    return this;\n  }\n\n  setArtifactName(artifactName: string) {\n    this.raw.artifactName = artifactName;\n    return this;\n  }\n\n  addTypes(typesPaths: string[]): TypescriptConfigMutator {\n    this.raw.types.push(...typesPaths);\n    return this;\n  }\n\n  setExperimentalDecorators(value: boolean): TypescriptConfigMutator {\n    this.raw.tsconfig.compilerOptions.experimentalDecorators = value;\n    return this;\n  }\n\n  /**\n   * Set ts compiler target option - https://www.typescriptlang.org/tsconfig#target\n   */\n  setTarget(target: Target): TypescriptConfigMutator {\n    this.raw.tsconfig.compilerOptions.target = target;\n    return this;\n  }\n\n  /**\n   * Set ts compiler module option - https://www.typescriptlang.org/tsconfig#module\n   */\n  setModule(module: string): TypescriptConfigMutator {\n    this.raw.tsconfig.compilerOptions.module = module;\n    return this;\n  }\n\n  /**\n   * This will change the dist dir for all relevant places:\n   * 1. the dist dir of the compiler instance\n   * 2. add exclude for the dist dir in the tsconfig\n   * 3. set the outDir of the tsconfig\n   */\n  setDistDir(distDir: string): TypescriptConfigMutator {\n    this.raw.distDir = distDir;\n    this.addExclude([distDir]);\n    this.setOutDir(distDir);\n    return this;\n  }\n\n  setOutDir(outDir: string): TypescriptConfigMutator {\n    this.raw.tsconfig.compilerOptions.outDir = outDir;\n    return this;\n  }\n\n  setCompilerOptions(options: CompilerOptions): TypescriptConfigMutator {\n    this.raw.tsconfig.compilerOptions = options;\n    return this;\n  }\n\n  setTsConfig(config: Record<string, any>): TypescriptConfigMutator {\n    this.raw.tsconfig = config;\n    return this;\n  }\n\n  mergeTsConfig(config: Record<string, any>): TypescriptConfigMutator {\n    this.raw.tsconfig = mergeWith({}, this.raw.tsconfig, config, tsconfigMergeCustomizer);\n    return this;\n  }\n\n  addExclude(exclusions: string[]): TypescriptConfigMutator {\n    this.raw.tsconfig.exclude.push(...exclusions);\n    return this;\n  }\n\n  /**\n   * Run the compiler for .js files. this will only affect whether to run the compiler on the files\n   * or not. It won't change the tsconfig to support or not support js files.\n   */\n  setCompileJs(compileJs: boolean) {\n    this.raw.compileJs = compileJs;\n    return this;\n  }\n\n  /**\n   * Run the compiler for .js files. this will only affect whether to run the compiler on the files\n   * or not. It won't change the tsconfig to support or not support jsx files.\n   */\n  setCompileJsx(compileJsx: boolean) {\n    this.raw.compileJsx = compileJsx;\n    return this;\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/typescript/utils/flatTSConfig.ts",
    "content": "import path from 'path';\nimport fs from 'fs-extra';\nimport type { CompilerOptions } from 'typescript';\n\ntype TSConfig = {\n  extends?: string;\n  include?: string[];\n  exclude?: string[];\n  compilerOptions: CompilerOptions;\n};\n\n/**\n * load compilerOptions from tsconfig.json, and handle extends\n */\nexport function flatTSConfig(filePath: string) {\n  const tsconfig = fs.readJsonSync(filePath) as TSConfig;\n  return _loadTSConfig(tsconfig, path.dirname(filePath));\n}\n\nfunction _loadTSConfig(tsconfig: TSConfig, cwd: string, stack: string[] = []): TSConfig {\n  const { extends: extendsPath, compilerOptions = {}, ...restTSConfig } = tsconfig;\n\n  if (!extendsPath) {\n    return tsconfig;\n  }\n\n  const extendPathAbs = path.resolve(cwd, extendsPath);\n  if (stack.indexOf(extendPathAbs) > -1) {\n    throw new Error(\n      `Load TypeScript config failed. Circular dependency detected: ${stack.join(' -> ')}`\n    );\n  }\n\n  const parentTsconfig = fs.readJsonSync(extendPathAbs) as TSConfig;\n\n  return _loadTSConfig(\n    {\n      ...parentTsconfig,\n      ...restTSConfig,\n      compilerOptions: {\n        ...parentTsconfig.compilerOptions,\n        ...compilerOptions,\n      },\n    },\n    path.dirname(extendPathAbs),\n    [...stack, extendPathAbs]\n  );\n}\n"
  },
  {
    "path": "packages/aspect/src/webpack/config/html.ts",
    "content": "/** html template for Previews (docs, compositions, etc) */\nexport function html(title: string) {\n  return () => `\n  <!DOCTYPE html>\n  <html lang=\"en\">\n    <head>\n      <meta charset=\"utf-8\">\n      <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n      <title>${title}</title>\n      <script>\n      // Allow to use react dev-tools inside the examples\n      try { window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__; } catch {}\n      </script>\n      <style> body { margin: 0; } </style>\n    </head>\n    <body>\n      <div id=\"root\"></div>\n    </body>\n  </html>\n  `;\n}\n// <!-- minimal css resets -->\n// <style> html { height: 100%; } body { margin: 0; height: 100%; } #root { height: 100%; } </style>\n"
  },
  {
    "path": "packages/aspect/src/webpack/config/index.ts",
    "content": "export { fallbacks } from './webpackFallbacks';\nexport { fallbacksAliases } from './webpackFallbacksAliases';\nexport { fallbacksProvidePluginConfig } from './webpackFallbacksProvidePluginConfig';\n"
  },
  {
    "path": "packages/aspect/src/webpack/config/webpack.config.ts",
    "content": "import { sep } from 'path';\nimport webpack, { Configuration } from 'webpack';\nimport { isUndefined, omitBy } from 'lodash';\nimport HtmlWebpackPlugin from 'html-webpack-plugin';\nimport WebpackAssetsManifest from 'webpack-assets-manifest';\nimport CompressionPlugin from 'compression-webpack-plugin';\n\nimport type { BundlerContext, BundlerHtmlConfig, Target } from '@aspect/bundler';\n\nimport { fallbacks } from './webpackFallbacks';\nimport { fallbacksProvidePluginConfig } from './webpackFallbacksProvidePluginConfig';\nimport { fallbacksAliases } from './webpackFallbacksAliases';\n\nexport default function configFactory(target: Target, context: BundlerContext): Configuration {\n  let truthyEntries =\n    Array.isArray(target.entries) && target.entries.length\n      ? target.entries.filter(Boolean)\n      : target.entries || {};\n  if (Array.isArray(truthyEntries) && !truthyEntries.length) {\n    truthyEntries = {};\n  }\n\n  const dev = Boolean(context.development);\n  const htmlConfig = target.html ?? context.html;\n  const compress = target.compress ?? context.compress;\n  const htmlPlugins = htmlConfig ? generateHtmlPlugins(htmlConfig) : undefined;\n  const splitChunks = target.chunking?.splitChunks;\n\n  const config: Configuration = {\n    mode: dev ? 'development' : 'production',\n    // Stop compilation early in production\n    bail: true,\n    // These are the \"entry points\" to our application.\n    // This means they will be the \"root\" imports that are included in JS bundle.\n    // @ts-ignore\n    entry: truthyEntries,\n\n    infrastructureLogging: {\n      level: 'error',\n    },\n\n    output: {\n      // The build folder.\n      path: `${target.outputPath}${sep}public`,\n    },\n    stats: {\n      errorDetails: true,\n    },\n\n    resolve: {\n      alias: fallbacksAliases,\n      fallback: fallbacks,\n    },\n\n    plugins: [new webpack.ProvidePlugin(fallbacksProvidePluginConfig), getAssetManifestPlugin()],\n  };\n\n  if (target.filename) {\n    config.output = config.output || {};\n    config.output.filename = target.filename;\n  }\n\n  if (target.chunkFilename) {\n    config.output = config.output || {};\n    config.output.chunkFilename = target.chunkFilename;\n  }\n\n  if (target.runtimeChunkName) {\n    config.optimization = config.optimization || {};\n    config.optimization.runtimeChunk = {\n      name: target.runtimeChunkName,\n    };\n  }\n\n  if (splitChunks) {\n    config.optimization = config.optimization || {};\n    config.optimization.splitChunks = {\n      chunks: 'all',\n      name: false,\n    };\n  }\n\n  if (htmlPlugins && htmlPlugins.length) {\n    if (!config.plugins) {\n      config.plugins = [];\n    }\n    config.plugins = config.plugins.concat(htmlPlugins);\n  }\n  if (compress) {\n    if (!config.plugins) {\n      config.plugins = [];\n    }\n    config.plugins = config.plugins.concat(new CompressionPlugin());\n  }\n  return config;\n}\n\nfunction getAssetManifestPlugin() {\n  return new WebpackAssetsManifest({ entrypoints: true });\n}\n\nfunction generateHtmlPlugins(configs: BundlerHtmlConfig[]) {\n  return configs.map((config) => generateHtmlPlugin(config));\n}\n\nfunction generateHtmlPlugin(config: BundlerHtmlConfig) {\n  const baseConfig: HtmlWebpackPlugin.Options = {\n    filename: config.filename,\n    chunks: config.chunks,\n    chunksSortMode: config.chunkOrder,\n    title: config.title,\n    templateContent: config.templateContent,\n    minify: config.minify,\n    cache: false,\n    favicon: config.favicon,\n  };\n\n  const filteredConfig = omitBy(baseConfig, isUndefined);\n  return new HtmlWebpackPlugin(filteredConfig);\n}\n"
  },
  {
    "path": "packages/aspect/src/webpack/config/webpack.dev.config.ts",
    "content": "import path, { join } from 'path';\nimport webpack from 'webpack';\nimport HtmlWebpackPlugin from 'html-webpack-plugin';\nimport errorOverlayMiddleware from 'react-dev-utils/errorOverlayMiddleware';\nimport evalSourceMapMiddleware from 'react-dev-utils/evalSourceMapMiddleware';\nimport noopServiceWorkerMiddleware from 'react-dev-utils/noopServiceWorkerMiddleware';\nimport redirectServedPath from 'react-dev-utils/redirectServedPathMiddleware';\nimport getPublicUrlOrPath from 'react-dev-utils/getPublicUrlOrPath';\nimport { pathNormalizeToLinux } from '@arco-cli/legacy/dist/utils/path';\nimport { WebpackConfigWithDevServer } from '../webpack.devServer';\nimport { fallbacks } from './webpackFallbacks';\n\nimport { html } from './html';\n\nimport { fallbacksProvidePluginConfig } from './webpackFallbacksProvidePluginConfig';\nimport { fallbacksAliases } from './webpackFallbacksAliases';\n\nconst publicUrlOrPath = getPublicUrlOrPath(process.env.NODE_ENV === 'development', '/', `/public`);\n\nexport default function configFactory(\n  _devServerID: string,\n  workspaceDir: string,\n  entryFiles: string[],\n  publicRoot: string,\n  publicPath: string,\n  title?: string,\n  favicon?: string\n): WebpackConfigWithDevServer {\n  const resolveWorkspacePath = (relativePath) => path.resolve(workspaceDir, relativePath);\n\n  // Required for babel-preset-react-app\n  process.env.NODE_ENV = 'development';\n\n  const publicDirectory = `${publicRoot}/${publicPath}`;\n\n  return {\n    // Environment mode\n    mode: 'development',\n\n    devtool: 'cheap-source-map',\n\n    // Entry point of app\n    entry: entryFiles.map((filePath) => resolveWorkspacePath(filePath)),\n\n    output: {\n      // Development filename output\n      filename: 'static/js/[name].bundle.js',\n\n      pathinfo: false,\n\n      path: resolveWorkspacePath(publicDirectory),\n\n      chunkFilename: 'static/js/[name].chunk.js',\n\n      // point sourcemap entries to original disk locations (format as URL on Windows)\n      devtoolModuleFilenameTemplate: (info) =>\n        pathNormalizeToLinux(path.resolve(info.absoluteResourcePath)),\n    },\n\n    infrastructureLogging: {\n      level: 'error',\n    },\n\n    stats: {\n      errorDetails: true,\n    },\n\n    devServer: {\n      allowedHosts: 'all',\n\n      static: [\n        {\n          directory: resolveWorkspacePath(publicDirectory),\n          staticOptions: {},\n          // Don't be confused with `dev.publicPath`, it is `publicPath` for static directory\n          // Can be:\n          // publicPath: ['/static-public-path-one/', '/static-public-path-two/'],\n          publicPath: publicDirectory,\n          // Can be:\n          // serveIndex: {} (options for the `serveIndex` option you can find https://github.com/expressjs/serve-index)\n          serveIndex: true,\n          // Can be:\n          // watch: {} (options for the `watch` option you can find https://github.com/paulmillr/chokidar)\n          watch: true,\n        },\n      ],\n\n      // Enable compression\n      compress: true,\n\n      // Enable hot reloading\n      hot: true,\n\n      historyApiFallback: {\n        disableDotRule: true,\n        index: publicUrlOrPath,\n      },\n\n      client: {\n        overlay: false,\n      },\n\n      setupMiddlewares: (middlewares, devServer) => {\n        middlewares.unshift(\n          // Keep `evalSourceMapMiddleware` and `errorOverlayMiddleware`\n          // middlewares before `redirectServedPath` otherwise will not have any effect\n          // This lets us fetch source contents from webpack for the error overlay\n          // @ts-ignore @types/wds mismatch\n          evalSourceMapMiddleware(devServer),\n          // This lets us open files from the runtime error overlay.\n          errorOverlayMiddleware()\n        );\n\n        middlewares.push(\n          // Redirect to `PUBLIC_URL` or `homepage` from `package.json` if url not match\n          redirectServedPath(publicUrlOrPath),\n          // This service worker file is effectively a 'no-op' that will reset any\n          // previous service worker registered for the same host:port combination.\n          // We do this in development to avoid hitting the production cache if\n          // it used the same host and port.\n          // https://github.com/facebook/create-react-app/issues/2272#issuecomment-302832432\n          noopServiceWorkerMiddleware(publicUrlOrPath)\n        );\n\n        return middlewares;\n      },\n\n      devMiddleware: {\n        // forward static files\n        publicPath: join('/', publicRoot),\n      },\n    },\n\n    resolve: {\n      alias: fallbacksAliases,\n      fallback: fallbacks,\n    },\n\n    plugins: [\n      new HtmlWebpackPlugin({\n        templateContent: html(title || 'Component preview'),\n        filename: 'index.html',\n        favicon,\n      }),\n      new webpack.ProvidePlugin(fallbacksProvidePluginConfig),\n    ],\n  };\n}\n"
  },
  {
    "path": "packages/aspect/src/webpack/config/webpackFallbacks.ts",
    "content": "// based on https://github1s.com/vercel/next.js/blob/canary/packages/next/build/webpack-config.ts\n// Full list of old polyfills is accessible here:\n// https://github.com/webpack/webpack/blob/2a0536cf510768111a3a6dceeb14cb79b9f59273/lib/ModuleNotFoundError.js#L13-L42\nconst assertFallbackPath = require.resolve('assert/');\nconst bufferFallbackPath = require.resolve('buffer/');\nconst constantsFallbackPath = require.resolve('constants-browserify');\nconst cryptoFallbackPath = require.resolve('crypto-browserify');\nconst domainFallbackPath = require.resolve('domain-browser');\nconst httpFallbackPath = require.resolve('stream-http');\nconst httpsFallbackPath = require.resolve('https-browserify');\nconst osFallbackPath = require.resolve('os-browserify/browser');\nconst pathFallbackPath = require.resolve('path-browserify');\nconst punycodeFallbackPath = require.resolve('punycode/');\nconst processFallbackPath = require.resolve('process/browser');\n// Handled in separate alias\nconst querystringFallbackPath = require.resolve('querystring-es3');\nconst streamFallbackPath = require.resolve('stream-browserify');\n// eslint-disable-next-line camelcase\nconst string_decoderFallbackPath = require.resolve('string_decoder/');\nconst sysFallbackPath = require.resolve('util/');\nconst timersFallbackPath = require.resolve('timers-browserify');\nconst ttyFallbackPath = require.resolve('tty-browserify');\n// Handled in separate alias\nconst urlFallbackPath = require.resolve('url/');\nconst utilFallbackPath = require.resolve('util/');\nconst vmFallbackPath = require.resolve('vm-browserify');\nconst zlibFallbackPath = require.resolve('browserify-zlib');\n\nexport const fallbacks = {\n  assert: assertFallbackPath,\n  buffer: bufferFallbackPath,\n  constants: constantsFallbackPath,\n  crypto: cryptoFallbackPath,\n  domain: domainFallbackPath,\n  http: httpFallbackPath,\n  https: httpsFallbackPath,\n  os: osFallbackPath,\n  path: pathFallbackPath,\n  punycode: punycodeFallbackPath,\n  process: processFallbackPath,\n  querystring: querystringFallbackPath,\n  stream: streamFallbackPath,\n  // eslint-disable-next-line camelcase\n  string_decoder: string_decoderFallbackPath,\n  sys: sysFallbackPath,\n  timers: timersFallbackPath,\n  tty: ttyFallbackPath,\n  url: urlFallbackPath,\n  util: utilFallbackPath,\n  vm: vmFallbackPath,\n  zlib: zlibFallbackPath,\n  fs: false,\n  net: false,\n  tls: false,\n  child_process: false,\n  // file: false,\n  // module: false,\n  // pnpapi: false,\n  // readline: false,\n  // worker_threads: false,\n} as const;\n"
  },
  {
    "path": "packages/aspect/src/webpack/config/webpackFallbacksAliases.ts",
    "content": "export const fallbacksAliases = {\n  process: require.resolve('process/browser'),\n  buffer: require.resolve('buffer/'),\n};\n"
  },
  {
    "path": "packages/aspect/src/webpack/config/webpackFallbacksProvidePluginConfig.ts",
    "content": "export const fallbacksProvidePluginConfig = {\n  process: require.resolve('process/browser'),\n  Buffer: [require.resolve('buffer/'), 'Buffer'],\n};\n"
  },
  {
    "path": "packages/aspect/src/webpack/events/index.ts",
    "content": "export * from './webpackCompilationDoneEvent';\nexport * from './webpackCompilationStartedEvent';\n"
  },
  {
    "path": "packages/aspect/src/webpack/events/webpackCompilationDoneEvent.ts",
    "content": "import type { Stats } from 'webpack';\nimport { ArcoBaseEvent } from '@aspect/pubsub';\n\nclass WebpackCompilationDoneEventData {\n  constructor(readonly stats: Stats, readonly devServerID: string) {}\n}\n\nexport class WebpackCompilationDoneEvent extends ArcoBaseEvent<WebpackCompilationDoneEventData> {\n  static readonly TYPE = 'webpack-compilation-done';\n\n  constructor(readonly timestamp: number, readonly stats: Stats, readonly devServerID: string) {\n    super(\n      WebpackCompilationDoneEvent.TYPE,\n      '0.0.1',\n      timestamp,\n      new WebpackCompilationDoneEventData(stats, devServerID)\n    );\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/webpack/events/webpackCompilationStartedEvent.ts",
    "content": "import { ArcoBaseEvent } from '@aspect/pubsub';\n\ntype Params = {\n  devServerID: string;\n};\n\nexport class WebpackCompilationStartedEvent extends ArcoBaseEvent<Params> {\n  static readonly TYPE = 'webpack-compilation-started';\n\n  constructor(readonly timestamp, readonly params: Params) {\n    super(WebpackCompilationStartedEvent.TYPE, '0.0.1', timestamp, params);\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/webpack/generateStyleLoader.ts",
    "content": "export type GenerateStyleLoadersOptions = {\n  /** the loader injecting the css to the html. style-loader / mini-css-extract-plugin */\n  injectingLoader: any;\n  cssLoaderPath: string;\n  cssLoaderOpts: any;\n  preProcessLoaderPath?: string;\n  preProcessLoaderOpts?: any;\n};\n\nexport function generateStyleLoaders(options: GenerateStyleLoadersOptions) {\n  const loaders = [\n    {\n      loader: options.injectingLoader,\n    },\n    {\n      loader: options.cssLoaderPath,\n      options: options.cssLoaderOpts,\n    },\n  ];\n\n  if (options.preProcessLoaderPath) {\n    loaders.push({\n      loader: options.preProcessLoaderPath,\n      options: options.preProcessLoaderOpts,\n    });\n  }\n\n  return loaders;\n}\n"
  },
  {
    "path": "packages/aspect/src/webpack/index.ts",
    "content": "import { WebpackAspect } from './webpack.aspect';\n\nexport default WebpackAspect;\nexport { WebpackAspect };\nexport { WebpackDevServer } from './webpack.devServer';\nexport type { WebpackConfigWithDevServer } from './webpack.devServer';\nexport type {\n  WebpackMain,\n  WebpackConfigTransformer,\n  WebpackConfigTransformContext,\n  GlobalWebpackConfigTransformContext,\n} from './webpack.main.runtime';\nexport { generateStyleLoaders, GenerateStyleLoadersOptions } from './generateStyleLoader';\nexport * from './events';\n"
  },
  {
    "path": "packages/aspect/src/webpack/webpack.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const WebpackAspect = Aspect.create({\n  id: 'arco.aspect/webpack',\n});\n\nexport default WebpackAspect;\n"
  },
  {
    "path": "packages/aspect/src/webpack/webpack.bundler.ts",
    "content": "import { sep } from 'path';\nimport ArcoError from '@arco-cli/legacy/dist/error/arcoError';\nimport type { Logger } from '@arco-cli/core/dist/logger';\nimport { compact, isEmpty } from 'lodash';\nimport mapSeries from 'p-map-series';\nimport type { Compiler, Configuration, StatsCompilation, StatsAsset } from 'webpack';\n\nimport type {\n  Bundler,\n  BundlerResult,\n  Asset,\n  Target,\n  EntriesAssetsMap,\n  BundlerContextMetaData,\n} from '@aspect/bundler';\n\ntype AssetsMap = { [assetId: string]: Asset };\nexport class WebpackBundler implements Bundler {\n  constructor(\n    /**\n     * targets to bundle\n     */\n    private targets: Target[],\n\n    /**\n     * webpack configuration\n     */\n    private configs: Configuration[],\n\n    private logger: Logger,\n\n    private webpack,\n\n    private metaData?: BundlerContextMetaData | undefined\n  ) {}\n\n  async run(): Promise<BundlerResult[]> {\n    const startTime = Date.now();\n    const compilers = this.configs.map((config: any) => this.webpack(config));\n    const initiator = this.metaData?.initiator;\n    const envId = this.metaData?.envId;\n    const initiatorMessage = initiator ? `process initiated by: ${initiator}.` : '';\n    const envIdMessage = envId ? `config created by env: ${envId}.` : '';\n\n    const longProcessLogger = this.logger.createLongProcessLogger(\n      'running Webpack bundler',\n      compilers.length\n    );\n    const componentOutput = await mapSeries(compilers, (compiler: Compiler) => {\n      const components = this.getComponents(compiler.outputPath);\n      const componentsLengthMessage = `running on ${components.length} components`;\n      const fullMessage = `${initiatorMessage} ${envIdMessage} ${componentsLengthMessage}`;\n      const ids = components.map((component) => component.id.toString()).join(', ');\n      longProcessLogger.logProgress(`${fullMessage}`);\n      this.logger.debug(`${fullMessage}\\ncomponents ids: ${ids}`);\n      return new Promise((resolve) => {\n        // TODO: split to multiple processes to reduce time and configure concurrent builds.\n        // @see https://github.com/trivago/parallel-webpack\n        // eslint-disable-next-line no-promise-executor-return\n        return compiler.run((err, stats) => {\n          if (err) {\n            this.logger.error('get error from webpack compiler, full error:', err);\n\n            return resolve({\n              errors: [`${err.toString()}\\n${err.stack}`],\n              components,\n            });\n          }\n          if (!stats) throw new ArcoError('unknown build error');\n          // const info = stats.toJson();\n\n          const info = stats.toJson({\n            all: false,\n            entrypoints: true,\n            warnings: true,\n            errors: true,\n            assets: true,\n            chunks: true,\n            chunkGroupAuxiliary: true,\n            relatedAssets: true,\n            cachedAssets: true,\n          });\n          const assetsMap = this.getAssets(info);\n          const entriesAssetsMap = this.getEntriesAssetsMap(info, assetsMap);\n\n          return resolve({\n            chunks: info.chunks,\n            assets: Object.values(assetsMap),\n            assetsByChunkName: info.assetsByChunkName,\n            entriesAssetsMap,\n            errors: this.getErrors(info),\n            outputPath: stats.compilation.outputOptions.path,\n            components,\n            warnings: info.warnings,\n            startTime,\n            endTime: Date.now(),\n          });\n        });\n      });\n    });\n    longProcessLogger.end();\n    return componentOutput as BundlerResult[];\n  }\n\n  private getErrors(stats: StatsCompilation): Error[] {\n    if (!stats.errors) return [];\n    const fieldsToShow = ['message', 'moduleId', 'moduleName', 'moduleIdentifier', 'loc'];\n    return stats.errors.map((webpackError) => {\n      const lines = fieldsToShow.map((fieldName) => {\n        if (webpackError[fieldName]) {\n          return `${fieldName}: ${webpackError[fieldName]}`;\n        }\n        return undefined;\n      });\n      const errorMessage = compact(lines).join('\\n');\n      return new ArcoError(errorMessage);\n    });\n  }\n\n  private getAssets(stats: StatsCompilation): AssetsMap {\n    if (!stats.assets) return {};\n    return stats.assets.reduce((acc, asset) => {\n      acc[asset.name] = {\n        name: asset.name,\n        size: asset.size,\n        compressedSize: this.getCompressedSize(asset),\n      };\n      return acc;\n    }, {});\n  }\n\n  private getEntriesAssetsMap(stats: StatsCompilation, assetsMap: AssetsMap): EntriesAssetsMap {\n    const entriesMap = stats.entrypoints;\n    if (!entriesMap || !Object.keys(assetsMap).length) return {};\n    Object.entries(entriesMap).forEach(([, entryVal]) => {\n      let compressedAssetsSize = 0;\n      let compressedAuxiliaryAssetsSize = 0;\n      entryVal.assets?.forEach((asset) => {\n        const compressedSize = assetsMap[asset.name]?.compressedSize;\n        if (compressedSize) {\n          // @ts-ignore\n          asset.compressedSize = compressedSize;\n          compressedAssetsSize += compressedSize;\n        }\n      });\n      entryVal.auxiliaryAssets?.forEach((asset) => {\n        const compressedSize = assetsMap[asset.name]?.compressedSize;\n        if (compressedSize) {\n          // @ts-ignore\n          asset.compressedSize = compressedSize;\n          compressedAuxiliaryAssetsSize += compressedSize;\n        }\n      });\n      entryVal.compressedAssetsSize = compressedAssetsSize;\n      entryVal.compressedAuxiliaryAssetsSize = compressedAuxiliaryAssetsSize;\n    });\n    return entriesMap as any as EntriesAssetsMap;\n  }\n\n  private getCompressedSize(asset: StatsAsset): number | undefined {\n    if (!asset.related || isEmpty(asset.related)) return undefined;\n    const gzipped = asset.related.find((relatedAsset) => {\n      return relatedAsset.type === 'gzipped';\n    });\n    if (!gzipped) return undefined;\n    return gzipped.size;\n  }\n\n  private getComponents(outputPath: string) {\n    const path = outputPath.substring(0, outputPath.lastIndexOf(sep));\n    const target = this.targets.find((targetCandidate) => path === targetCandidate.outputPath);\n\n    if (!target) throw new Error(`Could not find component id for path \"${path}\"`);\n    return target.components;\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/webpack/webpack.devServer.ts",
    "content": "import type { Server } from 'http';\nimport { inspect } from 'util';\nimport type { webpack as webpackCompiler, Configuration } from 'webpack';\nimport type * as WDS from 'webpack-dev-server';\n\nimport type { DevServer } from '@aspect/bundler';\n\nimport { WebpackAspect } from './webpack.aspect';\n\nexport interface WebpackConfigWithDevServer extends Configuration {\n  devServer: WDS.Configuration;\n  favicon?: string;\n}\nexport class WebpackDevServer implements DevServer {\n  constructor(\n    private config: WebpackConfigWithDevServer,\n    private webpack: typeof webpackCompiler,\n    private WsDevServer: WDS\n  ) {}\n\n  private getCompiler(): any {\n    return this.webpack(this.config);\n  }\n\n  id = WebpackAspect.id;\n\n  displayName = 'Webpack dev server';\n\n  displayConfig(): string {\n    return inspect(this.config, { depth: 10 });\n  }\n\n  async listen(port: number): Promise<Server> {\n    if (!this.config.devServer) {\n      throw new Error('Missing devServer configuration for webpack');\n    }\n    // Prevent different port between the config port and the listen arg port\n    this.config.devServer.port = port;\n\n    // Adding signal listeners to make sure we immediately close the process on sigint / sigterm (otherwise webpack dev server closing will take time)\n    this.addSignalListener();\n\n    // Compatibility check for Webpack dev server v3 (e.g. for Angular v8)\n    if (typeof (this.WsDevServer as any).addDevServerEntrypoints !== 'undefined') {\n      // @ts-ignore in the capsules it throws an error about compatibilities issues between webpack.compiler and webpackDevServer/webpack/compiler\n      const webpackDs = new (this.WsDevServer as any)(this.getCompiler(), this.config.devServer);\n      return webpackDs.listen(port);\n    }\n\n    // @ts-ignore in the capsules it throws an error about compatibilities issues between webpack.compiler and webpackDevServer/webpack/compiler\n    const webpackDs: WDS = new this.WsDevServer(this.config.devServer, this.getCompiler());\n    await webpackDs.start();\n\n    return webpackDs.server;\n  }\n\n  private addSignalListener() {\n    process.on('SIGTERM', () => {\n      process.exit();\n    });\n\n    process.on('SIGINT', () => {\n      process.exit();\n    });\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/webpack/webpack.main.runtime.ts",
    "content": "import { MainRuntime } from '@arco-cli/core/dist/cli';\nimport { LoggerAspect, LoggerMain } from '@arco-cli/core/dist/logger';\nimport webpack, { Configuration } from 'webpack';\nimport WsDevServer from 'webpack-dev-server';\nimport SpeedMeasurePlugin from 'speed-measure-webpack-plugin';\nimport { ENV_BUNDLE_SPEED_ANALYZER } from '@arco-cli/legacy/dist/constants';\n\nimport { WorkspaceAspect, Workspace } from '@aspect/workspace';\nimport { BundlerContext, BundlerMode, DevServer, DevServerContext, Target } from '@aspect/bundler';\n\nimport { WebpackAspect } from './webpack.aspect';\nimport { WebpackConfigMutator } from './webpackConfigMutator';\nimport { WebpackDevServer } from './webpack.devServer';\nimport { WebpackBundler } from './webpack.bundler';\nimport baseConfigFactory from './config/webpack.config';\nimport devServerConfigFactory from './config/webpack.dev.config';\n\nexport type GlobalWebpackConfigTransformContext = {\n  mode: BundlerMode;\n  /**\n   * A path for the host root dir\n   * Host root dir is usually the env root dir\n   * This can be used in different bundle options which run require.resolve\n   * for example when configuring webpack aliases or webpack expose loader on the peers deps\n   */\n  hostRootDir?: string;\n};\n\nexport type WebpackConfigTransformContext = GlobalWebpackConfigTransformContext & {\n  target: Target;\n};\n\nexport type WebpackConfigDevServerTransformContext = GlobalWebpackConfigTransformContext &\n  DevServerContext;\n\nexport type WebpackConfigTransformer = (\n  config: WebpackConfigMutator,\n  context: WebpackConfigTransformContext\n) => WebpackConfigMutator;\n\nfunction runTransformersWithContext(\n  config: WebpackConfigMutator,\n  context: any,\n  transformers: Array<WebpackConfigTransformer | WebpackConfigDevServerTransformContext> = []\n): WebpackConfigMutator {\n  if (!Array.isArray(transformers)) return config;\n  const newConfig = transformers.reduce((acc, transformer) => {\n    // @ts-ignore\n    return transformer(acc, context);\n  }, config);\n  return newConfig;\n}\n\nexport class WebpackMain {\n  static runtime = MainRuntime;\n\n  static dependencies = [WorkspaceAspect, LoggerAspect];\n\n  static slots = [];\n\n  static provider([workspace, loggerMain]: [Workspace, LoggerMain]) {\n    const logger = loggerMain.createLogger(WebpackAspect.id);\n    const webpackMain = new WebpackMain(workspace, logger);\n    return webpackMain;\n  }\n\n  constructor(private workspace, private logger) {}\n\n  private useSpeedMeasurePlugin(config) {\n    if (process.env[ENV_BUNDLE_SPEED_ANALYZER]) {\n      const speedMeasurePlugin = new SpeedMeasurePlugin();\n      return speedMeasurePlugin.wrap(config);\n    }\n\n    return config;\n  }\n\n  private createConfigs(\n    targets: Target[],\n    factory: (target: Target, context: BundlerContext) => Configuration,\n    transformers: WebpackConfigTransformer[],\n    transformerContext: GlobalWebpackConfigTransformContext,\n    bundlerContext: BundlerContext\n  ) {\n    transformers = transformers || [];\n\n    return targets.map((target) => {\n      const baseConfig = factory(target, bundlerContext);\n      const configMutator = new WebpackConfigMutator(baseConfig, webpack);\n      const context = { ...transformerContext, target };\n      const afterMutation = runTransformersWithContext(\n        configMutator.clone(),\n        context,\n        transformers\n      );\n      return afterMutation.raw;\n    });\n  }\n\n  /**\n   * create an instance of webpack dev server for a set of components\n   */\n  createDevServer(\n    context: DevServerContext,\n    transformers: WebpackConfigTransformer[] = []\n  ): DevServer {\n    const config = devServerConfigFactory(\n      context.id,\n      this.workspace.path,\n      context.entry,\n      context.rootPath,\n      context.publicPath,\n      context.title\n    );\n    const configMutator = new WebpackConfigMutator(config, webpack);\n    const transformerContext: WebpackConfigDevServerTransformContext = Object.assign(context, {\n      mode: 'dev' as const,\n    });\n    const afterMutation = runTransformersWithContext(configMutator.clone(), transformerContext, [\n      ...transformers,\n    ]);\n\n    return new WebpackDevServer(\n      this.useSpeedMeasurePlugin(afterMutation.raw),\n      webpack,\n      WsDevServer as any\n    );\n  }\n\n  createBundler(\n    context: BundlerContext,\n    transformers?: WebpackConfigTransformer[],\n    initialConfigs?: webpack.Configuration[],\n    webpackInstance?: any\n  ) {\n    const transformerContext: GlobalWebpackConfigTransformContext = { mode: 'prod' };\n    // eslint-disable-next-line max-len\n    const configs =\n      initialConfigs ||\n      this.createConfigs(\n        context.targets,\n        baseConfigFactory,\n        transformers,\n        transformerContext,\n        context\n      );\n    return new WebpackBundler(\n      context.targets,\n      configs,\n      this.logger,\n      webpackInstance || webpack,\n      context.metaData\n    );\n  }\n}\n\nWebpackAspect.addRuntime(WebpackMain);\n"
  },
  {
    "path": "packages/aspect/src/webpack/webpackConfigMutator.ts",
    "content": "import { isObject, omit } from 'lodash';\nimport { merge, mergeWithCustomize, mergeWithRules, CustomizeRule } from 'webpack-merge';\nimport type { Configuration, ResolveOptions, RuleSetRule } from 'webpack';\nimport type { ICustomizeOptions } from 'webpack-merge/dist/types';\n\nexport * from 'webpack-merge';\n\ntype ConflictPolicy = 'override' | 'error' | 'ignore';\ntype ArrayPosition = 'append' | 'prepend';\n\ntype AddKeyOpts = {\n  conflictPolicy?: ConflictPolicy;\n};\n\ntype AddToArrayOpts = {\n  position?: ArrayPosition;\n};\n\ntype MergeOpts = {\n  rawConfigPosition: ArrayPosition;\n};\n\ntype Rules = {\n  [s: string]: CustomizeRule | Rules;\n};\n\nconst DEFAULT_ADD_TO_ARRAY_OPTS: AddToArrayOpts = {\n  position: 'prepend',\n};\n\nconst DEFAULT_ADD_KEY_OPTS: AddKeyOpts = {\n  conflictPolicy: 'override',\n};\n\nconst DEFAULT_MERGE_OPTS: MergeOpts = {\n  rawConfigPosition: 'prepend',\n};\n\nexport class WebpackConfigMutator {\n  constructor(public raw: Configuration, public webpack: any) {}\n\n  clone(): WebpackConfigMutator {\n    return new WebpackConfigMutator(merge({}, this.raw), this.webpack);\n  }\n\n  /**\n   * Add a key value to the top level config\n   */\n  addTopLevel(key: string, value: any, opts: AddKeyOpts = {}): WebpackConfigMutator {\n    const concreteOpts = { ...DEFAULT_ADD_KEY_OPTS, ...opts };\n    const exist = this.raw.hasOwnProperty(key);\n    if (concreteOpts.conflictPolicy === 'override') {\n      this.raw[key] = value;\n    } else if (exist) {\n      if (concreteOpts.conflictPolicy === 'error') {\n        throw new Error(`key with name ${key} already exist in config`);\n      }\n    } else {\n      this.raw[key] = value;\n    }\n    return this;\n  }\n\n  /**\n   * Remove a key from the top level\n   */\n  removeTopLevel(key: string): WebpackConfigMutator {\n    delete this.raw[key];\n    return this;\n  }\n\n  /**\n   * Add new entry to the config\n   */\n  addEntry(entry: string, opts: AddToArrayOpts = {}): WebpackConfigMutator {\n    if (!this.raw.entry) {\n      this.raw.entry = [];\n    }\n    if (!Array.isArray(this.raw.entry)) {\n      throw new Error(`can't add an entry to a function type raw entry`);\n    }\n    this.raw.entry = addToArray(this.raw.entry, entry, opts);\n    return this;\n  }\n\n  /**\n   * Add rule to the module config\n   */\n  addModuleRule(rule: RuleSetRule, opts: AddToArrayOpts = {}): WebpackConfigMutator {\n    if (!this.raw.module) {\n      this.raw.module = {};\n    }\n    if (!this.raw.module.rules) {\n      this.raw.module.rules = [];\n    }\n\n    addToArray(this.raw.module.rules, rule, opts);\n    return this;\n  }\n\n  /**\n   * Add many rules to the module config\n   */\n  addModuleRules(rules: RuleSetRule[], opts: AddToArrayOpts = {}): WebpackConfigMutator {\n    rules.forEach((rule) => this.addModuleRule(rule, opts));\n    return this;\n  }\n\n  /**\n   * Add rule to the module config\n   */\n  addRuleToOneOf(rule: RuleSetRule, opts: AddToArrayOpts = {}): WebpackConfigMutator {\n    if (!this.raw.module) {\n      this.raw.module = {};\n    }\n    if (!this.raw.module.rules) {\n      this.raw.module.rules = [];\n    }\n    // @ts-ignore\n    if (!this.raw.module.rules.find((r) => !!r.oneOf)) {\n      this.raw.module.rules.unshift({ oneOf: [] });\n    }\n\n    addToArray(\n      this.raw.module.rules.find((r) => !!(r as RuleSetRule).oneOf) as RuleSetRule[],\n      rule,\n      opts\n    );\n    return this;\n  }\n\n  /**\n   * Add a new plugin\n   */\n  addPlugin(plugin: any, opts: AddToArrayOpts = {}): WebpackConfigMutator {\n    if (!this.raw.plugins) {\n      this.raw.plugins = [];\n    }\n    addToArray(this.raw.plugins, plugin, opts);\n    return this;\n  }\n\n  /**\n   * Add many new plugins\n   */\n  addPlugins(plugins: Array<any>, opts: AddToArrayOpts = {}): WebpackConfigMutator {\n    if (!this.raw.plugins) {\n      this.raw.plugins = [];\n    }\n    this.raw.plugins = addManyToArray(this.raw.plugins, plugins, opts);\n    return this;\n  }\n\n  /**\n   * Add aliases\n   */\n  addAliases(aliases: { [index: string]: string | false | string[] }): WebpackConfigMutator {\n    if (!this.raw.resolve) {\n      this.raw.resolve = {};\n    }\n    if (!this.raw.resolve.alias) {\n      this.raw.resolve.alias = {};\n    }\n    Object.assign(this.raw.resolve.alias, aliases);\n    return this;\n  }\n\n  /**\n   * Add aliases\n   */\n  removeAliases(aliases: string[]): WebpackConfigMutator {\n    if (!this.raw.resolve) {\n      return this;\n    }\n    if (!this.raw.resolve.alias) {\n      return this;\n    }\n    if (isObject(this.raw?.resolve?.alias)) {\n      this.raw.resolve.alias = omit(this.raw.resolve.alias, aliases);\n    }\n    return this;\n  }\n\n  /**\n   * Add resolve\n   */\n  addResolve(resolve: ResolveOptions): WebpackConfigMutator {\n    if (!this.raw.resolve) {\n      this.raw.resolve = {};\n    }\n    Object.assign(this.raw.resolve, resolve);\n    return this;\n  }\n\n  /**\n   * to be used to ignore replace packages with global variable\n   * Useful when trying to offload libs to CDN\n   */\n  addExternals(externalDeps: Configuration['externals']): WebpackConfigMutator {\n    if (!externalDeps) return this;\n    let externals = this.raw.externals;\n    if (!externals) {\n      externals = externalDeps;\n    } else if (Array.isArray(externalDeps)) {\n      externals = externalDeps.concat(externals);\n    } else if (\n      Array.isArray(externals) ||\n      externalDeps.constructor === Function ||\n      externalDeps.constructor === RegExp\n    ) {\n      externals = [externalDeps].concat(externals);\n    } else if (externalDeps instanceof Object && externals instanceof Object) {\n      // @ts-ignore\n      externals = {\n        ...externals,\n        ...externalDeps,\n      };\n    }\n\n    this.raw.externals = externals;\n    return this;\n  }\n\n  /**\n   * Merge external configs with the current config (utilize webpack-merge)\n   */\n  merge(config: Configuration | Configuration[], opts?: MergeOpts): WebpackConfigMutator {\n    const configs = Array.isArray(config) ? config : [config];\n    const concreteOpts = { ...DEFAULT_MERGE_OPTS, ...(opts || {}) };\n    const { firstConfig, configs: otherConfigs } = getConfigsToMerge(\n      this.raw,\n      configs,\n      concreteOpts.rawConfigPosition\n    );\n    const merged = merge(firstConfig, ...otherConfigs);\n    this.raw = merged;\n    return this;\n  }\n\n  /**\n   * Merge external configs with the current config uses customize (array/object) function (utilize webpack-merge)\n   */\n  mergeWithCustomize(\n    configs: Configuration[],\n    customizes: ICustomizeOptions,\n    opts: MergeOpts\n  ): WebpackConfigMutator {\n    const concreteOpts = { ...DEFAULT_MERGE_OPTS, ...opts };\n    const { firstConfig, configs: otherConfigs } = getConfigsToMerge(\n      this.raw,\n      configs,\n      concreteOpts.rawConfigPosition\n    );\n    const merged = mergeWithCustomize(customizes)(firstConfig, ...otherConfigs);\n    this.raw = merged;\n    return this;\n  }\n\n  /**\n   * Merge external configs with the current config uses rules (utilize webpack-merge)\n   */\n  mergeWithRules(configs: Configuration[], rules: Rules, opts: MergeOpts): WebpackConfigMutator {\n    const concreteOpts = { ...DEFAULT_MERGE_OPTS, ...opts };\n    const { firstConfig, configs: otherConfigs } = getConfigsToMerge(\n      this.raw,\n      configs,\n      concreteOpts.rawConfigPosition\n    );\n    const merged = mergeWithRules(rules)(firstConfig, ...otherConfigs);\n    this.raw = merged;\n    return this;\n  }\n}\n\nfunction getConfigsToMerge(\n  originalConfig: Configuration,\n  configs: Configuration[],\n  originalPosition: ArrayPosition\n): { firstConfig: Configuration; configs: Configuration[] } {\n  let firstConfig = originalConfig;\n  if (originalPosition === 'append') {\n    firstConfig = configs.shift() || {};\n    configs.push(originalConfig);\n  }\n  return {\n    firstConfig,\n    configs,\n  };\n}\n\nfunction addToArray(array: Array<any>, val: any, opts: AddToArrayOpts = {}): Array<any> {\n  const concreteOpts = { ...DEFAULT_ADD_TO_ARRAY_OPTS, ...opts };\n  if (concreteOpts.position === 'prepend') {\n    array?.unshift(val);\n  } else {\n    array?.push(val);\n  }\n  return array;\n}\n\nfunction addManyToArray(\n  array: Array<any>,\n  vals: Array<any>,\n  opts: AddToArrayOpts = {}\n): Array<any> {\n  const concreteOpts = { ...DEFAULT_ADD_TO_ARRAY_OPTS, ...opts };\n  if (concreteOpts.position === 'prepend') {\n    array?.unshift(...vals);\n  } else {\n    array?.push(...vals);\n  }\n  return array;\n}\n"
  },
  {
    "path": "packages/aspect/src/workspace/events/index.ts",
    "content": "export * from './onComponentAddEvent';\nexport * from './onComponentChangeEvent';\nexport * from './onComponentRemovedEvent';\n"
  },
  {
    "path": "packages/aspect/src/workspace/events/onComponentAddEvent.ts",
    "content": "import { ArcoBaseEvent } from '@aspect/pubsub';\n\nclass OnComponentAddEventData {\n  constructor(readonly idStr, readonly hook) {}\n}\n\nexport class OnComponentAddEvent extends ArcoBaseEvent<OnComponentAddEventData> {\n  static readonly TYPE = 'on-component-add';\n\n  constructor(readonly timestamp, readonly idStr, readonly hook) {\n    super(OnComponentAddEvent.TYPE, '0.0.1', timestamp, new OnComponentAddEventData(idStr, hook));\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/workspace/events/onComponentChangeEvent.ts",
    "content": "import { ArcoBaseEvent } from '@aspect/pubsub';\n\nclass OnComponentChangeEventData {\n  constructor(readonly idStr, readonly hook) {}\n}\n\nexport class OnComponentChangeEvent extends ArcoBaseEvent<OnComponentChangeEventData> {\n  static readonly TYPE = 'on-component-change';\n\n  constructor(readonly timestamp, readonly idStr, readonly hook) {\n    super(\n      OnComponentChangeEvent.TYPE,\n      '0.0.1',\n      timestamp,\n      new OnComponentChangeEventData(idStr, hook)\n    );\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/workspace/events/onComponentRemovedEvent.ts",
    "content": "import { ArcoBaseEvent } from '@aspect/pubsub';\n\nclass OnComponentRemovedEventData {\n  constructor(readonly idStr) {}\n}\n\nexport class OnComponentRemovedEvent extends ArcoBaseEvent<OnComponentRemovedEventData> {\n  static readonly TYPE = 'on-component-removed';\n\n  constructor(readonly timestamp, readonly idStr) {\n    super(OnComponentRemovedEvent.TYPE, '0.0.1', timestamp, new OnComponentRemovedEventData(idStr));\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/workspace/exceptions/index.ts",
    "content": "export { WorkspaceNotFoundError } from './workspaceNotFoundError';\nexport { NoIdMatchPatternError } from './noIdMatchPatternError';\n"
  },
  {
    "path": "packages/aspect/src/workspace/exceptions/noIdMatchPatternError.ts",
    "content": "export class NoIdMatchPatternError extends Error {\n  isUserError = true;\n\n  constructor(pattern?: string) {\n    super(`unable to find any matching for \"${pattern}\" pattern`);\n    this.name = this.constructor.name;\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/workspace/exceptions/workspaceNotFoundError.ts",
    "content": "import AbstractError from '@arco-cli/legacy/dist/error/abstractError';\n\nexport class WorkspaceNotFoundError extends AbstractError {\n  message = `workspace not found, please run arco command in a arco workspace`;\n}\n"
  },
  {
    "path": "packages/aspect/src/workspace/index.ts",
    "content": "import { WorkspaceAspect } from './workspace.aspect';\n\nexport default WorkspaceAspect;\nexport { WorkspaceAspect };\nexport type { WorkspaceMain } from './workspace.main.runtime';\nexport type { Workspace } from './workspace';\nexport type { WorkspaceConfig } from './type';\n"
  },
  {
    "path": "packages/aspect/src/workspace/type/custom.d.ts",
    "content": "declare module '*.module.css' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\ndeclare module '*.module.scss' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\ndeclare module '*.module.sass' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.module.less' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.less' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.css' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.sass' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.scss' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.mdx' {\n  const component: any;\n  export default component;\n}\n"
  },
  {
    "path": "packages/aspect/src/workspace/type/index.ts",
    "content": "export type { WorkspaceConfig } from './workspaceConfig';\n"
  },
  {
    "path": "packages/aspect/src/workspace/type/onComponentEvents.ts",
    "content": "import { Component } from '@aspect/component';\n\nexport type SerializableResults = { results: any; toString: () => string };\n\nexport type OnComponentEventResult = { extensionId: string; results: SerializableResults };\n\nexport type OnComponentLoad = (component: Component) => Promise<Record<string, any> | undefined>;\n\nexport type OnComponentAdd = (\n  component: Component,\n  files: string[]\n) => Promise<SerializableResults>;\n\nexport type OnComponentChange = (\n  component: Component,\n  files: string[]\n) => Promise<SerializableResults>;\n\nexport type OnComponentRemove = (componentId: string) => Promise<SerializableResults>;\n"
  },
  {
    "path": "packages/aspect/src/workspace/type/workspaceConfig.ts",
    "content": "import { ComponentConfig } from '@arco-cli/legacy/dist/workspace/componentInfo';\n\n/**\n * config of arco.aspect/workspace\n */\nexport interface WorkspaceConfig {\n  /**\n   * name of the workspace.\n   */\n  name: string;\n\n  /**\n   * components map of the workspace\n   */\n  components:\n    | ComponentConfig[]\n    | {\n        /**\n         * component shared configuration fields\n         */\n        extends?: Partial<ComponentConfig>;\n        /**\n         * component separate configuration fields\n         */\n        members: ComponentConfig[];\n      };\n}\n"
  },
  {
    "path": "packages/aspect/src/workspace/uiRuntime/graphqlProvider.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { PropsWithChildren } from 'react';\nimport { ApolloProvider, ApolloClient, InMemoryCache } from '@apollo/client';\n\nexport function GraphqlProvider({ children }: PropsWithChildren<any>) {\n  const client = new ApolloClient({\n    uri: '/graphql',\n    cache: new InMemoryCache(),\n  });\n\n  return <ApolloProvider client={client}>{children}</ApolloProvider>;\n}\n"
  },
  {
    "path": "packages/aspect/src/workspace/uiRuntime/hooks/useWorkspace.ts",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport { useMemo } from 'react';\nimport { gql } from '@apollo/client';\nimport { useDataQuery } from '@arco-cli/ui-foundation-react';\nimport { WorkspaceModel } from '../workspaceModel';\n\nconst wcComponentFields = gql`\n  fragment wcComponentFields on Component {\n    id\n    name\n    labels\n    description\n    author\n    packageName\n    version\n  }\n`;\n\nconst WORKSPACE = gql`\n  query workspace {\n    workspace {\n      name\n      path\n      components {\n        ...wcComponentFields\n      }\n    }\n  }\n  ${wcComponentFields}\n`;\n\nexport function useWorkspace() {\n  const { data } = useDataQuery(WORKSPACE);\n\n  const workspace = useMemo(() => {\n    return data?.workspace ? WorkspaceModel.from(data.workspace) : null;\n  }, [data?.workspace]);\n\n  return {\n    workspace,\n  };\n}\n"
  },
  {
    "path": "packages/aspect/src/workspace/uiRuntime/index.ts",
    "content": "export { WorkspaceAspect } from '../workspace.aspect';\nexport type { WorkspaceUI } from './workspace.ui.runtime';\n"
  },
  {
    "path": "packages/aspect/src/workspace/uiRuntime/style/workspace.module.scss",
    "content": "@import '~@arco-cli/ui-foundation-react/dist/style/z-indexes';\n\n$navbar-height: 60px;\n\n:global(body[arco-theme='dark']) {\n  color-scheme: dark;\n  background-color: var(--preview-color-bg-1);\n}\n\n.emptyContainer {\n  height: 100vh;\n}\n\n.workspaceWrapper {\n  display: flex;\n  flex-direction: column;\n  overflow: hidden;\n  height: 100vh;\n}\n\n.main {\n  display: flex;\n  flex: 1 1;\n  height: 100%;\n  overflow: hidden;\n}\n\n.overview {\n  flex: 1;\n  height: calc(100vh - $navbar-height);\n  padding: 40px 20px;\n  overflow-y: scroll;\n\n  iframe {\n    width: 100%;\n    height: 100%;\n    border: none;\n    box-shadow: none;\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/workspace/uiRuntime/workspace.tsx",
    "content": "import React, { useRef, useState } from 'react';\n// eslint-disable-next-line import/no-extraneous-dependencies\nimport { Route, RouteProps } from 'react-router-dom';\nimport {\n  BackTop,\n  Navbar,\n  SideBar,\n  WorkspaceContextProvider,\n  WorkspaceOverview,\n} from '@arco-cli/ui-foundation-react';\n\nimport { SlotRouter } from '@aspect/react-router/uiRuntime';\nimport { getIdFromLocation } from '@aspect/component/uiRuntime/utils/getIdFromLocation';\n\nimport { useWorkspace } from './hooks/useWorkspace';\n\nimport styles from './style/workspace.module.scss';\n\ninterface WorkspaceProps {\n  routes: RouteProps[];\n}\n\nconst OVERVIEW_SCROLL_CONTAINER_ID = 'a-overview-scroll-container';\n\nexport function Workspace({ routes }: WorkspaceProps) {\n  const refOverviewContainer = useRef<HTMLDivElement>(null);\n  const [componentId, setComponentId] = useState(getIdFromLocation());\n  const { workspace } = useWorkspace();\n\n  if (!workspace) {\n    return <div className={styles.emptyContainer} />;\n  }\n\n  return (\n    <WorkspaceContextProvider\n      name={workspace.name}\n      components={workspace.components}\n      overviewScrollContainerID={OVERVIEW_SCROLL_CONTAINER_ID}\n    >\n      <div className={styles.workspaceWrapper}>\n        <Navbar title={workspace.name} />\n        <main className={styles.main}>\n          <SideBar\n            componentMenuProps={{\n              componentId,\n              onComponentChange: (componentId) => setComponentId(componentId),\n            }}\n          />\n          <div\n            ref={refOverviewContainer}\n            id={OVERVIEW_SCROLL_CONTAINER_ID}\n            className={styles.overview}\n          >\n            <SlotRouter key={componentId} routes={routes}>\n              <Route index element={<WorkspaceOverview />} />\n            </SlotRouter>\n            <BackTop target={() => refOverviewContainer.current} />\n          </div>\n        </main>\n      </div>\n    </WorkspaceContextProvider>\n  );\n}\n"
  },
  {
    "path": "packages/aspect/src/workspace/uiRuntime/workspace.ui.runtime.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React from 'react';\nimport type { RouteProps } from 'react-router-dom';\nimport { Slot, SlotRegistry } from '@arco-cli/stone';\nimport { UIAspect, UIUI, UIRuntime, UIRootUI as UIRoot } from '@arco-cli/service/dist/ui/uiRuntime';\n\nimport { DocsAspect } from '@aspect/docs/uiRuntime';\nimport { ComponentAspect, ComponentUI } from '@aspect/component/uiRuntime';\n\nimport { WorkspaceAspect } from '../workspace.aspect';\nimport { Workspace } from './workspace';\nimport { GraphqlProvider } from './graphqlProvider';\n\ntype RouteSlot = SlotRegistry<RouteProps>;\n\nexport class WorkspaceUI {\n  static runtime = UIRuntime;\n\n  // TODO ensure load order, WorkspaceAspect should load at last\n  static dependencies = [UIAspect, ComponentAspect, DocsAspect];\n\n  static slots = [Slot.withType<RouteProps>()];\n\n  static provider([ui, componentUI]: [UIUI, ComponentUI], _config, [routeSlot]: [RouteSlot]) {\n    const workspaceUI = new WorkspaceUI(routeSlot, componentUI);\n    ui.registerRoot(workspaceUI.uiRoot.bind(workspaceUI));\n    workspaceUI.registerRoute({\n      path: workspaceUI.componentUI.routePath,\n      element: workspaceUI.componentUI.getComponentUI(WorkspaceAspect.id),\n    });\n    return workspaceUI;\n  }\n\n  constructor(private routeSlot: RouteSlot, private componentUI: ComponentUI) {}\n\n  registerRoute(route: RouteProps) {\n    this.routeSlot.register(route);\n    return this;\n  }\n\n  uiRoot(): UIRoot {\n    return {\n      routes: [\n        {\n          path: '/*',\n          element: (\n            <GraphqlProvider>\n              <Workspace routes={this.routeSlot.values()} />\n            </GraphqlProvider>\n          ),\n        },\n      ],\n    };\n  }\n}\n\nWorkspaceAspect.addRuntime(WorkspaceUI);\n"
  },
  {
    "path": "packages/aspect/src/workspace/uiRuntime/workspaceModel.ts",
    "content": "import { ComponentModel, ComponentModelProps } from '@aspect/component/uiRuntime';\n\nexport type WorkspaceProps = {\n  name: string;\n  path: string;\n  components: ComponentModelProps[];\n};\n\nexport class WorkspaceModel {\n  constructor(\n    /**\n     * name of the workspace.\n     */\n    readonly name: string,\n\n    /**\n     * absolute path of the workspace.\n     */\n    readonly path: string,\n\n    /**\n     * components container in the workspace.\n     */\n    readonly components: ComponentModel[]\n  ) {}\n\n  /**\n   * return a component from the workspace.\n   */\n  getComponent(id: string) {\n    return this.components.find((component) => component.id === id);\n  }\n\n  static from({ name, path, components }: WorkspaceProps) {\n    return new WorkspaceModel(\n      name,\n      path,\n      components.map((value) => {\n        return ComponentModel.from(value);\n      })\n    );\n  }\n\n  static empty() {\n    return new WorkspaceModel('', '', []);\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/workspace/watch/watchQueue.ts",
    "content": "import PQueue from 'p-queue';\n\nexport class WatchQueue {\n  readonly queue: PQueue;\n\n  constructor(concurrency = 1) {\n    this.queue = new PQueue({ concurrency, autoStart: true });\n  }\n\n  getQueue() {\n    return this.queue;\n  }\n\n  add<T>(fn: () => T, priority?: number): Promise<T> {\n    return this.queue.add(fn, { priority });\n  }\n\n  onIdle(): Promise<void> {\n    return this.queue.onIdle();\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/workspace/watch/watcher.ts",
    "content": "import { dirname, sep } from 'path';\nimport { difference } from 'lodash';\nimport chalk from 'chalk';\nimport mapSeries from 'p-map-series';\nimport chokidar, { FSWatcher } from 'chokidar';\nimport loader from '@arco-cli/legacy/dist/cli/loader';\nimport logger from '@arco-cli/legacy/dist/logger/logger';\nimport { pathNormalizeToLinux } from '@arco-cli/legacy/dist/utils/path';\nimport { FILE_WORKSPACE_JSONC, FILE_WORKSPACE_JS } from '@arco-cli/legacy/dist/constants';\n\nimport { PubsubMain } from '@aspect/pubsub';\n\nimport { WorkspaceAspect } from '../workspace.aspect';\nimport { OnComponentChangeEvent, OnComponentAddEvent, OnComponentRemovedEvent } from '../events';\nimport { Workspace } from '../workspace';\nimport { OnComponentEventResult } from '../type/onComponentEvents';\nimport { WatchQueue } from './watchQueue';\n\nexport type EventMessages = {\n  onAll: () => void;\n  onStart: (workspace: Workspace) => void;\n  onReady: (workspace: Workspace, trackDir: Record<string, string>, verbose: boolean) => void;\n  onChange: (\n    files: string[],\n    results: OnComponentEventResult[],\n    verbose: boolean,\n    duration: number,\n    failureMsg: string\n  ) => void;\n  onAdd: (\n    files: string[],\n    results: OnComponentEventResult[],\n    verbose: boolean,\n    duration: number,\n    failureMsg: string\n  ) => void;\n  onUnlink: (filePath: string) => void;\n  onError: (error: Error) => void;\n};\n\nexport type WatchOptions = {\n  msgs?: EventMessages;\n};\n\nconst DEBOUNCE_WAIT_MS = 100;\n\nexport class Watcher {\n  private fsWatcher: FSWatcher;\n\n  private changedFilesPerComponent: { [componentId: string]: string[] } = {};\n\n  private watchQueue = new WatchQueue();\n\n  private workspaceJsonChangesInProgress = false;\n\n  constructor(\n    private workspace: Workspace,\n    private pubsub: PubsubMain,\n    private trackDirs: { [dir: string]: string } = {},\n    private verbose = false\n  ) {}\n\n  async watchAll(opts: WatchOptions) {\n    const { msgs } = opts;\n    const pathsToWatch = await this.getPathsToWatch();\n    await this.createWatcher(pathsToWatch);\n    const watcher = this.fsWatcher;\n\n    msgs?.onStart(this.workspace);\n\n    return new Promise((_resolve, reject) => {\n      watcher.on('ready', () => {\n        msgs?.onReady(this.workspace, this.trackDirs, this.verbose);\n      });\n\n      watcher.on('change', async (filePath) => {\n        const startTime = new Date().getTime();\n        const { files, results, debounced, failureMsg } = await this.handleChange(filePath);\n        if (debounced) {\n          return;\n        }\n        const duration = new Date().getTime() - startTime;\n        msgs?.onChange(files, results, this.verbose, duration, failureMsg);\n      });\n\n      watcher.on('add', async (filePath) => {\n        const startTime = new Date().getTime();\n        const { files, results, debounced, failureMsg } = await this.handleChange(filePath);\n        if (debounced) {\n          return;\n        }\n        const duration = new Date().getTime() - startTime;\n        msgs?.onAdd(files, results, this.verbose, duration, failureMsg);\n      });\n\n      watcher.on('unlink', async (p) => {\n        msgs?.onUnlink(p);\n        await this.handleChange(p);\n      });\n\n      watcher.on('error', (err) => {\n        msgs?.onError(err);\n        reject(err);\n      });\n    });\n  }\n\n  /**\n   * *** DEBOUNCING ***\n   * some actions trigger multiple files changes at (almost) the same time. e.g. \"git pull\".\n   * this causes some performance and instability issues. a debouncing mechanism was implemented to help with this.\n   * the way how it works is that the first file of the same component starts the execution with a delay (e.g. 200ms).\n   * if, in the meanwhile, another file of the same component was changed, it won't start a new execution, instead,\n   * it'll only add the file to `this.changedFilesPerComponent` prop.\n   * once the execution starts, it'll delete this component-id from the `this.changedFilesPerComponent` array,\n   * indicating the next file-change to start a new execution.\n   *\n   * implementation wise, `lodash.debounce` doesn't help here, because:\n   * A) it doesn't return the results, unless \"leading\" option is true. here, it must be false, otherwise, it'll start\n   * the execution immediately.\n   * B) it debounces the method regardless the param passes to it. so it'll disregard the component-id and will delay\n   * other components undesirably.\n   */\n  private async handleChange(filePath: string): Promise<{\n    results: OnComponentEventResult[];\n    files?: string[];\n    failureMsg?: string;\n    debounced?: boolean;\n  }> {\n    try {\n      if (filePath.endsWith(FILE_WORKSPACE_JSONC) || filePath.endsWith(FILE_WORKSPACE_JS)) {\n        this.workspaceJsonChangesInProgress = true;\n        const buildResults = await this.watchQueue.add(() => this.handleWorkspaceJsonChanges());\n        this.workspaceJsonChangesInProgress = false;\n        loader.stop();\n        return { results: buildResults, files: [filePath] };\n      }\n\n      if (this.workspaceJsonChangesInProgress) {\n        await this.watchQueue.onIdle();\n      }\n\n      const componentId = this.getComponentIdByPath(filePath);\n      if (!componentId) {\n        const failureMsg = `file ${filePath} is not part of any component, ignoring it`;\n        logger.debug(failureMsg);\n        loader.stop();\n        return { results: [], files: [filePath], failureMsg };\n      }\n\n      if (this.changedFilesPerComponent[componentId]) {\n        this.changedFilesPerComponent[componentId].push(filePath);\n        loader.stop();\n        return { results: [], debounced: true };\n      }\n\n      this.changedFilesPerComponent[componentId] = [filePath];\n      await this.sleep(DEBOUNCE_WAIT_MS);\n      const files = this.changedFilesPerComponent[componentId];\n      delete this.changedFilesPerComponent[componentId];\n\n      const buildResults = await this.watchQueue.add(() =>\n        this.triggerCompChanges(componentId, files)\n      );\n      const failureMsg = buildResults.length\n        ? undefined\n        : `files ${files.join(\n            ', '\n          )} are inside the component ${componentId} but configured to be ignored`;\n      loader.stop();\n      return { results: buildResults, files, failureMsg };\n    } catch (err: any) {\n      const msg = `watcher found an error while handling ${filePath}`;\n      logger.error(msg, err);\n      logger.console(`${msg}, ${err.message}`);\n      loader.stop();\n      return { results: [], files: [filePath], failureMsg: err.message };\n    }\n  }\n\n  private async sleep(ms: number) {\n    // eslint-disable-next-line no-promise-executor-return\n    return new Promise((resolve) => setTimeout(resolve, ms));\n  }\n\n  private async triggerCompChanges(\n    componentId: string,\n    files: string[]\n  ): Promise<OnComponentEventResult[]> {\n    await this.workspace.updateComponentInfo(componentId);\n    const component = await this.workspace.get(componentId);\n    const compFiles = files.filter((filePath) => {\n      const isCompFile = Boolean(component.files.find((p) => p.path === filePath));\n      if (!isCompFile) {\n        logger.debug(\n          `file ${filePath} is inside the component ${componentId.toString()} but configured to be ignored`\n        );\n      }\n      return isCompFile;\n    });\n    if (!compFiles.length) {\n      return [];\n    }\n    const buildResults = await this.executeWatchOperationsOnComponent(componentId, compFiles, true);\n    return buildResults;\n  }\n\n  /**\n   * if workspace.json changed, it's possible that a new component has been added. trigger onComponentAdd.\n   */\n  private async handleWorkspaceJsonChanges(): Promise<OnComponentEventResult[]> {\n    const previousTrackDirs = { ...this.trackDirs };\n    await this.setTrackDirs();\n    const newDirs: string[] = difference(\n      Object.keys(this.trackDirs),\n      Object.keys(previousTrackDirs)\n    );\n    const removedDirs: string[] = difference(\n      Object.keys(previousTrackDirs),\n      Object.keys(this.trackDirs)\n    );\n    const results: OnComponentEventResult[] = [];\n    if (newDirs.length) {\n      this.fsWatcher.add(newDirs);\n      const addResults = await mapSeries(newDirs, async (dir) =>\n        this.executeWatchOperationsOnComponent(this.trackDirs[dir], [], false)\n      );\n      results.push(...addResults.flat());\n    }\n    if (removedDirs.length) {\n      await this.fsWatcher.unwatch(removedDirs);\n      await mapSeries(removedDirs, (dir) =>\n        this.executeWatchOperationsOnRemove(previousTrackDirs[dir])\n      );\n    }\n    return results;\n  }\n\n  private async executeWatchOperationsOnRemove(componentId: string) {\n    logger.debug(`running OnComponentRemove hook for ${chalk.bold(componentId.toString())}`);\n    this.pubsub.pub(WorkspaceAspect.id, this.creatOnComponentRemovedEvent(componentId.toString()));\n    await this.workspace.triggerOnComponentRemove(componentId);\n  }\n\n  private async executeWatchOperationsOnComponent(\n    componentId: string,\n    files: string[],\n    isChange = true\n  ): Promise<OnComponentEventResult[]> {\n    const idStr = componentId.toString();\n\n    if (isChange) {\n      logger.debug(`running OnComponentChange hook for ${chalk.bold(idStr)}`);\n      this.pubsub.pub(\n        WorkspaceAspect.id,\n        this.creatOnComponentChangeEvent(idStr, 'OnComponentChange')\n      );\n    } else {\n      logger.debug(`running OnComponentAdd hook for ${chalk.bold(idStr)}`);\n      this.pubsub.pub(WorkspaceAspect.id, this.creatOnComponentAddEvent(idStr, 'OnComponentAdd'));\n    }\n\n    let buildResults: OnComponentEventResult[];\n    try {\n      buildResults = isChange\n        ? await this.workspace.triggerOnComponentChange(componentId, files)\n        : await this.workspace.triggerOnComponentAdd(componentId);\n    } catch (err: any) {\n      // do not exit the watch process on errors, just print them\n      const msg = `found an issue during onComponentChange or onComponentAdd hooks`;\n      logger.error(msg, err);\n      logger.console(`\\n${msg}: ${err.message || err}`);\n      return [];\n    }\n    return buildResults;\n  }\n\n  private creatOnComponentRemovedEvent(idStr) {\n    return new OnComponentRemovedEvent(Date.now(), idStr);\n  }\n\n  private creatOnComponentChangeEvent(idStr, hook) {\n    return new OnComponentChangeEvent(Date.now(), idStr, hook);\n  }\n\n  private creatOnComponentAddEvent(idStr, hook) {\n    return new OnComponentAddEvent(Date.now(), idStr, hook);\n  }\n\n  private getComponentIdByPath(filePath: string): string | null {\n    const relativeFile = this.getRelativePathLinux(filePath);\n    const trackDir = this.findTrackDirByFilePathRecursively(relativeFile);\n\n    // the file is not part of any component. If it was a new component, or a new file of\n    // existing component, then, handleWorkspaceJsonChanges() should deal with it.\n    return trackDir ? this.trackDirs[trackDir] : null;\n  }\n\n  private getRelativePathLinux(filePath: string) {\n    return pathNormalizeToLinux(this.workspace.toRelativePath(filePath));\n  }\n\n  private findTrackDirByFilePathRecursively(filePath: string): string | null {\n    if (this.trackDirs[filePath]) return filePath;\n    const parentDir = dirname(filePath);\n    if (parentDir === filePath) return null;\n    return this.findTrackDirByFilePathRecursively(parentDir);\n  }\n\n  private async createWatcher(pathsToWatch: string[]) {\n    this.fsWatcher = chokidar.watch(pathsToWatch, {\n      ignoreInitial: true,\n      // Using the function way since the regular way not working as expected\n      // See: https://github.com/paulmillr/chokidar/issues/773\n      ignored: (path) => {\n        // Ignore package.json temporarily since it creates endless loop since it's re-written after each build\n        return path.includes(`${sep}node_modules${sep}`) || path.includes(`${sep}package.json`);\n      },\n      persistent: true,\n      useFsEvents: false,\n    });\n  }\n\n  async setTrackDirs() {\n    this.trackDirs = {};\n    const components = await this.workspace.list();\n    components.map(async (component) => {\n      this.trackDirs[component.componentDir] = component.id;\n    });\n  }\n\n  private async getPathsToWatch(): Promise<string[]> {\n    await this.setTrackDirs();\n    const paths = [...Object.keys(this.trackDirs)];\n    const pathsAbsolute = paths.map((dir) => this.workspace.toAbsolutePath(dir));\n    return pathsAbsolute;\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/workspace/workspace.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const WorkspaceAspect = Aspect.create({\n  id: 'arco.aspect/workspace',\n});\n\nexport default WorkspaceAspect;\n"
  },
  {
    "path": "packages/aspect/src/workspace/workspace.graphql.ts",
    "content": "import gql from 'graphql-tag';\nimport { Workspace } from './workspace';\n\nexport default function (workspace: Workspace) {\n  return {\n    typeDefs: gql`\n      type Workspace {\n        name: String\n        path: String\n        components: [Component]\n        getComponent(id: String!): Component\n      }\n\n      type Query {\n        workspace: Workspace\n      }\n    `,\n    resolvers: {\n      Workspace: {\n        path: (ws) => ws.path,\n        name: (ws) => ws.name,\n        components: async (ws: Workspace) => {\n          return ws.list();\n        },\n        getComponent: async (ws: Workspace, { id }: { id: string }) => {\n          try {\n            const component = await ws.get(id);\n            return component;\n          } catch (error: any) {\n            return null;\n          }\n        },\n      },\n      Query: {\n        workspace: () => workspace,\n      },\n    },\n  };\n}\n"
  },
  {
    "path": "packages/aspect/src/workspace/workspace.main.runtime.ts",
    "content": "import { Slot } from '@arco-cli/stone';\nimport { LoggerAspect, LoggerMain } from '@arco-cli/core/dist/logger';\nimport { UIAspect, UIMain } from '@arco-cli/service/dist/ui';\nimport { MainRuntime } from '@arco-cli/core/dist/cli';\nimport { AspectLoaderAspect, AspectLoaderMain } from '@arco-cli/core/dist/aspect-loader';\nimport { getWorkspaceInfo } from '@arco-cli/legacy/dist/workspace/workspaceLocator';\nimport { GraphqlAspect, GraphqlMain } from '@arco-cli/core/dist/graphql';\nimport { CORE_ASPECT_ID_MAP } from '@arco-cli/legacy/dist/constants';\n\nimport { PubsubAspect, PubsubMain } from '@aspect/pubsub';\nimport { ComponentAspect, ComponentMain } from '@aspect/component';\n\nimport { WorkspaceAspect } from './workspace.aspect';\nimport {\n  OnComponentAddSlot,\n  OnComponentChangeSlot,\n  OnComponentLoadSlot,\n  OnComponentRemoveSlot,\n  Workspace,\n} from './workspace';\nimport { WorkspaceUiRoot } from './workspace.uiRoot';\nimport { WorkspaceNotFoundError } from './exceptions';\nimport { WorkspaceConfig } from './type';\nimport getWorkspaceSchema from './workspace.graphql';\nimport {\n  OnComponentAdd,\n  OnComponentChange,\n  OnComponentLoad,\n  OnComponentRemove,\n} from './type/onComponentEvents';\n\nexport const WorkspaceMain = {\n  name: WorkspaceAspect.id,\n  runtime: MainRuntime,\n  dependencies: [\n    LoggerAspect,\n    UIAspect,\n    ComponentAspect,\n    PubsubAspect,\n    AspectLoaderAspect,\n    GraphqlAspect,\n  ],\n  slots: [\n    Slot.withType<OnComponentLoad>(),\n    Slot.withType<OnComponentAdd>(),\n    Slot.withType<OnComponentChange>(),\n    Slot.withType<OnComponentRemove>(),\n  ],\n  provider: async (\n    [_loggerMain, ui, component, pubsub, aspectLoader, graphql]: [\n      LoggerMain,\n      UIMain,\n      ComponentMain,\n      PubsubMain,\n      AspectLoaderMain,\n      GraphqlMain\n    ],\n    config: WorkspaceConfig,\n    [onComponentLoadSlot, onComponentAddSlot, onComponentChangeSlot, onComponentRemoveSlot]: [\n      OnComponentLoadSlot,\n      OnComponentAddSlot,\n      OnComponentChangeSlot,\n      OnComponentRemoveSlot\n    ],\n    stone\n  ) => {\n    const arcoConfig = stone.config.get(CORE_ASPECT_ID_MAP.APP_ARCO);\n\n    const workspaceInfo = await getWorkspaceInfo(arcoConfig.cwd);\n    if (!workspaceInfo) {\n      throw new WorkspaceNotFoundError();\n    }\n\n    const workspace = await Workspace.load({\n      path: workspaceInfo.path,\n      configFilename: workspaceInfo.configFilename,\n      config,\n      pubsub,\n      aspectLoader,\n      onComponentLoadSlot,\n      onComponentAddSlot,\n      onComponentChangeSlot,\n      onComponentRemoveSlot,\n    });\n\n    ui.registerUiRoot(new WorkspaceUiRoot(workspace));\n    component.registerHost(workspace);\n    graphql.register(getWorkspaceSchema(workspace));\n\n    return workspace;\n  },\n};\n\nWorkspaceAspect.addRuntime(WorkspaceMain);\n"
  },
  {
    "path": "packages/aspect/src/workspace/workspace.ts",
    "content": "import path from 'path';\nimport fs, { readFileSync, writeFileSync } from 'fs-extra';\nimport { uniqBy, merge } from 'lodash';\nimport mapSeries from 'p-map-series';\nimport minimatch from 'minimatch';\nimport { parse, assign, stringify } from 'comment-json';\nimport { SlotRegistry } from '@arco-cli/stone';\nimport { AspectLoaderMain, getAspectDef } from '@arco-cli/core/dist/aspect-loader';\nimport { ComponentInfo, ComponentConfig } from '@arco-cli/legacy/dist/workspace/componentInfo';\nimport { getFilesByDir } from '@arco-cli/legacy/dist/workspace/componentOps/addComponents';\nimport { getGitIgnoreForArco } from '@arco-cli/legacy/dist/utils/ignore';\nimport { FILE_WORKSPACE_JSONC } from '@arco-cli/legacy/dist/constants';\n\nimport { PubsubMain } from '@aspect/pubsub';\nimport { ComponentFactory, Component } from '@aspect/component';\n\nimport { WorkspaceConfig } from './type';\nimport {\n  SerializableResults,\n  OnComponentChange,\n  OnComponentEventResult,\n  OnComponentLoad,\n  OnComponentAdd,\n  OnComponentRemove,\n} from './type/onComponentEvents';\nimport { Watcher } from './watch/watcher';\nimport { NoIdMatchPatternError } from './exceptions';\n\nexport type OnComponentAddSlot = SlotRegistry<OnComponentAdd>;\n\nexport type OnComponentLoadSlot = SlotRegistry<OnComponentLoad>;\n\nexport type OnComponentChangeSlot = SlotRegistry<OnComponentChange>;\n\nexport type OnComponentRemoveSlot = SlotRegistry<OnComponentRemove>;\n\nexport type WorkspaceProps = {\n  path: string;\n  config: WorkspaceConfig;\n  configFilename: string;\n  pubsub: PubsubMain;\n  aspectLoader: AspectLoaderMain;\n  onComponentAddSlot: OnComponentAddSlot;\n  onComponentLoadSlot: OnComponentLoadSlot;\n  onComponentChangeSlot: OnComponentChangeSlot;\n  onComponentRemoveSlot: OnComponentRemoveSlot;\n};\n\nexport class Workspace implements ComponentFactory {\n  static async load({\n    path,\n    config,\n    configFilename,\n    pubsub,\n    aspectLoader,\n    onComponentAddSlot,\n    onComponentLoadSlot,\n    onComponentChangeSlot,\n    onComponentRemoveSlot,\n  }: WorkspaceProps): Promise<Workspace> {\n    const workspace = new Workspace(\n      path,\n      config,\n      configFilename,\n      pubsub,\n      aspectLoader,\n      onComponentAddSlot,\n      onComponentLoadSlot,\n      onComponentChangeSlot,\n      onComponentRemoveSlot\n    );\n\n    await workspace.updateComponentInfo();\n    return workspace;\n  }\n\n  constructor(\n    public path: string,\n    public config: WorkspaceConfig,\n    private configFilename: string,\n    private pubsub: PubsubMain,\n    private aspectLoader: AspectLoaderMain,\n    private onComponentAddSlot: OnComponentAddSlot,\n    private onComponentLoadSlot: OnComponentLoadSlot,\n    private onComponentChangeSlot: OnComponentChangeSlot,\n    private onComponentRemoveSlot: OnComponentRemoveSlot\n  ) {\n    const rawComponentsConfig = this.config.components;\n    if (Array.isArray(rawComponentsConfig)) {\n      this.componentConfigList = rawComponentsConfig;\n    } else {\n      this.componentConfigList = rawComponentsConfig.members.map((rawConfig) =>\n        merge({}, rawComponentsConfig.extends, rawConfig)\n      );\n    }\n  }\n\n  readonly watcher = new Watcher(this, this.pubsub);\n\n  private componentCache: Record<string, Component> = {};\n\n  private componentInfoList: ComponentInfo[] = [];\n\n  private componentConfigList: ComponentConfig[] = [];\n\n  private componentPattern = '';\n\n  private get modulesPath() {\n    return path.join(this.path, 'node_modules');\n  }\n\n  private clearComponentCache(componentId?: string) {\n    if (componentId) {\n      delete this.componentCache[componentId];\n    } else {\n      this.componentCache = {};\n    }\n  }\n\n  private filterComponentInfoList(pattern = this.componentPattern): ComponentInfo[] {\n    pattern = (pattern || '').trim();\n    let filterFn: (info: ComponentInfo) => boolean;\n\n    if (!pattern) {\n      filterFn = () => true;\n    } else {\n      let hasUserSpecifiedRuleType = false;\n\n      pattern.replace(/^(glob|reg|is):(.+)/, (_, type: string, value: string) => {\n        hasUserSpecifiedRuleType = true;\n        const rules = value.split(',');\n        switch (type) {\n          case 'is':\n            filterFn = (info) => rules.indexOf(info.id) > -1;\n            break;\n          case 'glob':\n            filterFn = (info) => !!rules.find((rule) => minimatch(info.id, rule));\n            break;\n          case 'reg':\n            filterFn = (info) => !!rules.find((rule) => info.id.match(new RegExp(rule)));\n            break;\n          default:\n        }\n        return '';\n      });\n\n      if (!hasUserSpecifiedRuleType) {\n        filterFn = (info) =>\n          !!pattern.split(',').find((rule) =>\n            // if there is a '*' in user-given string, treat it as a glob string\n            rule.indexOf('*') > -1 ? minimatch(info.id, rule) : info.id.includes(rule)\n          );\n      }\n    }\n\n    return this.componentInfoList.filter(filterFn);\n  }\n\n  get name() {\n    return this.config.name || this.path.split('/').pop();\n  }\n\n  /**\n   * set component pattern for current workspace\n   * componentPattern will also work for workspace.list()\n   */\n  setComponentPattern(pattern: string) {\n    this.componentPattern = pattern;\n  }\n\n  updateWorkspaceConfigFile(aspectId: string, newConfig: any) {\n    const configFilePath = path.join(this.path, this.configFilename);\n    if (configFilePath.endsWith(FILE_WORKSPACE_JSONC)) {\n      const config = parse(readFileSync(configFilePath, 'utf8'));\n      writeFileSync(configFilePath, stringify(assign(config, { [aspectId]: newConfig }), null, 2));\n    } else {\n      throw new Error(`cannot update config files of this file type '${configFilePath}'`);\n    }\n  }\n\n  async updateComponentInfo(componentId?: string) {\n    if (!componentId) {\n      // clear component infos, and re-collect info from workspace config file\n      this.componentInfoList = [];\n    }\n\n    // clear component cache, as component info may have changed\n    this.clearComponentCache(componentId);\n\n    const workspacePath = this.path;\n    const infoList = this.componentInfoList;\n    const gitIgnore = getGitIgnoreForArco(workspacePath);\n\n    await Promise.all(\n      this.componentConfigList.map(async (config) => {\n        if (componentId && !ComponentInfo.nameMatchId(config.name, componentId)) return;\n\n        const componentInfo = ComponentInfo.fromJson(config, workspacePath);\n        if (componentId && componentId !== componentInfo.id) return;\n\n        const rootDir = config.rootDir;\n        if (rootDir) {\n          try {\n            componentInfo.files = await getFilesByDir(rootDir, workspacePath, gitIgnore);\n          } catch (error) {\n            componentInfo.files = [];\n            componentInfo.noFilesError = error;\n          }\n        }\n\n        const index = componentId && infoList.findIndex((info) => info.id === componentId);\n        if (typeof index === 'number' && index !== -1) {\n          infoList[index] = componentInfo;\n        } else {\n          infoList.push(componentInfo);\n        }\n      })\n    );\n  }\n\n  registerOnComponentLoad(loadFn: OnComponentLoad) {\n    this.onComponentLoadSlot.register(loadFn);\n    return this;\n  }\n\n  registerOnComponentAdd(onComponentAddFunc: OnComponentAdd) {\n    this.onComponentAddSlot.register(onComponentAddFunc);\n    return this;\n  }\n\n  registerOnComponentChange(onComponentChangeFunc: OnComponentChange) {\n    this.onComponentChangeSlot.register(onComponentChangeFunc);\n    return this;\n  }\n\n  registerOnComponentRemove(onComponentRemoveFunc: OnComponentRemove) {\n    this.onComponentRemoveSlot.register(onComponentRemoveFunc);\n    return this;\n  }\n\n  /**\n   * Provides a cache folder, unique per key.\n   * Return value may be undefined, if workspace folder is unconventional (bare-scope, no node_modules, etc)\n   */\n  getCacheDir(\n    /*\n     * unique key, i.e. aspect or component id\n     */\n    id: string\n  ) {\n    const PREFIX = 'arco-cli';\n    const cacheDir = path.join(this.modulesPath, '.cache', PREFIX, id);\n\n    // maybe should also check it's a folder and has write permissions\n    if (!fs.existsSync(cacheDir)) {\n      fs.mkdirSync(cacheDir, { recursive: true });\n    }\n\n    return cacheDir;\n  }\n\n  async get(id: string, componentInfoList = this.componentInfoList) {\n    const componentInfo = componentInfoList.find((info) => info.id === id);\n\n    if (!componentInfo) {\n      this.clearComponentCache(id);\n      return null;\n    }\n\n    if (this.componentCache[id]) {\n      return this.componentCache[id];\n    }\n\n    const component = await Component.loadFromFileSystem(componentInfo, this.path);\n    const onComponentLoadTasks = this.onComponentLoadSlot\n      .toArray()\n      .map(async ([extension, onLoad]) => {\n        const data = await onLoad(component);\n        return component.upsertExtensionData(extension, data);\n      });\n\n    await Promise.all(onComponentLoadTasks);\n    this.componentCache[id] = component;\n\n    return component;\n  }\n\n  getMany(ids: string[] = []) {\n    const filteredComponentInfoList = this.filterComponentInfoList();\n    return Promise.all(ids.map((id) => this.get(id, filteredComponentInfoList)));\n  }\n\n  getManyByPattern(pattern: string, throwForNoMatch?: boolean): Promise<Component[]> {\n    if (!pattern) {\n      return this.list();\n    }\n\n    const filteredComponentInfos = this.filterComponentInfoList(pattern);\n    if (filteredComponentInfos.length) {\n      return this.getMany(filteredComponentInfos.map((info) => info.id));\n    }\n\n    if (throwForNoMatch) {\n      throw new NoIdMatchPatternError(pattern);\n    } else {\n      return Promise.resolve([]);\n    }\n  }\n\n  // TODO modified components\n  // getNewAndModified() { }\n\n  list() {\n    const ids = this.filterComponentInfoList().map((info) => info.id);\n    return this.getMany(ids);\n  }\n\n  async resolveAspects(runtimeName: string) {\n    const coreAspectIds = this.aspectLoader.getCoreAspectIds();\n    let coreAspectDefs = await Promise.all(\n      coreAspectIds.map(async (coreId) => {\n        const rawDef = await getAspectDef(coreId, runtimeName);\n        return this.aspectLoader.loadDefinition(rawDef);\n      })\n    );\n\n    if (runtimeName) {\n      coreAspectDefs = coreAspectDefs.filter(({ runtimePath }) => runtimePath);\n    }\n\n    return uniqBy(coreAspectDefs, (def) => `${def.aspectPath}-${def.runtimePath}`);\n  }\n\n  // TODO track a new added component\n  async track() {}\n\n  toAbsolutePath(pathStr: string): string {\n    if (path.isAbsolute(pathStr))\n      throw new Error(`toAbsolutePath expects relative path, got ${pathStr}`);\n    return path.join(this.path, pathStr);\n  }\n\n  toRelativePath(pathToCheck: string): string {\n    const absolutePath = path.resolve(pathToCheck);\n    return path.relative(this.path, absolutePath);\n  }\n\n  async triggerOnComponentAdd(id: string): Promise<OnComponentEventResult[]> {\n    const component = await this.get(id);\n    const onAddEntries = this.onComponentAddSlot.toArray();\n    const results: Array<{ extensionId: string; results: SerializableResults }> = [];\n    const files = component.files.map((file) => file.path);\n\n    await mapSeries(onAddEntries, async ([extension, onAddFunc]) => {\n      const onAddResult = await onAddFunc(component, files);\n      results.push({ extensionId: extension, results: onAddResult });\n    });\n\n    return results;\n  }\n\n  async triggerOnComponentChange(id: string, files: string[]): Promise<OnComponentEventResult[]> {\n    const component = await this.get(id);\n    const onChangeEntries = this.onComponentChangeSlot.toArray();\n    const results: Array<{ extensionId: string; results: SerializableResults }> = [];\n\n    await mapSeries(onChangeEntries, async ([extension, onChangeFunc]) => {\n      const onChangeResult = await onChangeFunc(component, files);\n      results.push({ extensionId: extension, results: onChangeResult });\n    });\n\n    return results;\n  }\n\n  async triggerOnComponentRemove(id: string): Promise<OnComponentEventResult[]> {\n    const onRemoveEntries = this.onComponentRemoveSlot.toArray();\n    const results: Array<{ extensionId: string; results: SerializableResults }> = [];\n\n    await mapSeries(onRemoveEntries, async ([extension, onRemoveFunc]) => {\n      const onRemoveResult = await onRemoveFunc(id);\n      results.push({ extensionId: extension, results: onRemoveResult });\n    });\n\n    return results;\n  }\n}\n"
  },
  {
    "path": "packages/aspect/src/workspace/workspace.uiRoot.ts",
    "content": "import { UIRoot } from '@arco-cli/service/dist/ui';\n// import { FILE_WORKSPACE_JSONC } from '@arco-cli/legacy/dist/constants';\nimport { Workspace } from './workspace';\n\nexport class WorkspaceUiRoot implements UIRoot {\n  constructor(private workspace: Workspace) {}\n\n  buildOptions = {};\n\n  get name() {\n    return this.workspace.name;\n  }\n\n  get path() {\n    return this.workspace.path;\n  }\n\n  // get configFile() {\n  //   return FILE_WORKSPACE_JSONC;\n  // }\n\n  getConfig() {\n    return {};\n  }\n\n  async resolveAspects(runtimeName: string) {\n    return this.workspace.resolveAspects(runtimeName);\n  }\n}\n"
  },
  {
    "path": "packages/aspect/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"dist\",\n    \"paths\": {\n      \"@aspect/*\": [\"src/*\"],\n      \"@arco-cli/stone\": [\"../stone/src\"],\n      \"@arco-cli/legacy/dist/*\": [\"../legacy/src/*\"],\n      \"@arco-cli/core/dist/*\": [\"../core/src/*\"],\n      \"@arco-cli/aspect/dist/*\": [\"../aspect/src/*\"],\n      \"@arco-cli/service/dist*\": [\"../service/src/*\"],\n      \"@arco-cli/ui-foundation-react\": [\"../ui-foundation-react/src\"],\n      \"@arco-cli/ui-foundation-react/dist/*\": [\"../ui-foundation-react/src/*\"]\n    }\n  }\n}\n"
  },
  {
    "path": "packages/core/package.json",
    "content": "{\n  \"name\": \"@arco-cli/core\",\n  \"version\": \"2.3.2\",\n  \"homepage\": \"https://github.com/arco-design/arco-cli\",\n  \"repository\": \"https://github.com/arco-design/arco-cli\",\n  \"main\": \"./dist/index.js\",\n  \"scripts\": {\n    \"dev\": \"sh ../../.scripts/build.sh dev\",\n    \"build\": \"sh ../../.scripts/build.sh\",\n    \"build-type\": \"sh ../../.scripts/build-type.sh\",\n    \"clean\": \"rm -rf dist\",\n    \"clean-type\": \"find dist -name *.d.ts |xargs rm -rf\",\n    \"prepublishOnly\": \"npm run build\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@arco-cli/legacy\": \"^2.3.2\",\n    \"@arco-cli/stone\": \"^2.0.0-beta.0\",\n    \"@babel/runtime\": \"^7.20.6\",\n    \"@graphql-modules/core\": \"^0.7.17\",\n    \"body-parser\": \"^1.20.1\",\n    \"chalk\": \"^4.1.2\",\n    \"cors\": \"^2.8.5\",\n    \"didyoumean\": \"^1.2.2\",\n    \"express\": \"^4.18.2\",\n    \"express-graphql\": \"^0.12.0\",\n    \"fs-extra\": \"^10.1.0\",\n    \"glob\": \"^8.0.3\",\n    \"graphql\": \"^14.7.0\",\n    \"graphql-subscriptions\": \"^1.2.1\",\n    \"lodash\": \"^4.17.21\",\n    \"node-fetch\": \"^3.3.0\",\n    \"pad-right\": \"^0.2.2\",\n    \"pretty-time\": \"^1.1.0\",\n    \"yargs\": \"^17.6.2\"\n  },\n  \"devDependencies\": {\n    \"@types/yargs\": \"^17.0.13\"\n  }\n}\n"
  },
  {
    "path": "packages/core/src/aspect-loader/aspectDefinition.ts",
    "content": "export type AspectDefinitionProps = {\n  id?: string;\n  aspectPath: string;\n  runtimePath: string | null;\n};\n\nexport class AspectDefinition {\n  constructor(\n    /**\n     * path to the root directory of the aspect module\n     */\n    readonly aspectPath: string,\n\n    /**\n     * path to the runtime entry\n     */\n    readonly runtimePath: string | null,\n\n    /**\n     * id of the component (used instead of component in the case of core aspect)\n     */\n    readonly id?: string,\n    /**\n     * aspect defined using 'file://' protocol\n     */\n    readonly local?: boolean\n  ) {}\n\n  static from({ aspectPath, runtimePath, id }: AspectDefinitionProps) {\n    return new AspectDefinition(aspectPath, runtimePath, id);\n  }\n}\n"
  },
  {
    "path": "packages/core/src/aspect-loader/aspectLoader.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const AspectLoaderAspect = Aspect.create({\n  id: 'arco.core/aspect-loader',\n});\n\nexport default AspectLoaderAspect;\n"
  },
  {
    "path": "packages/core/src/aspect-loader/aspectLoader.main.runtime.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\nimport { CORE_ASPECT_ID_MAP } from '@arco-cli/legacy/dist/constants';\n\nimport { MainRuntime } from '@core/cli';\n\nimport { AspectLoaderAspect } from './aspectLoader.aspect';\nimport { AspectDefinition, AspectDefinitionProps } from './aspectDefinition';\n\nexport class AspectLoaderMain {\n  static runtime = MainRuntime;\n\n  static dependencies = [];\n\n  static slots = [];\n\n  static provider() {\n    return new AspectLoaderMain();\n  }\n\n  constructor() {}\n\n  private _reserved = [CORE_ASPECT_ID_MAP.APP_ARCO];\n\n  private _coreAspects: Aspect[];\n\n  get coreAspects() {\n    return this._coreAspects;\n  }\n\n  setCoreAspects(aspects: Aspect[]) {\n    this._coreAspects = aspects;\n    return this;\n  }\n\n  getCoreAspectIds() {\n    const ids = this.coreAspects.map((aspect) => aspect.id);\n    return ids.concat(this._reserved);\n  }\n\n  loadDefinition(props: AspectDefinitionProps): AspectDefinition {\n    return AspectDefinition.from(props);\n  }\n}\n\nAspectLoaderAspect.addRuntime(AspectLoaderMain);\n"
  },
  {
    "path": "packages/core/src/aspect-loader/coreAspect.ts",
    "content": "import glob from 'glob';\nimport { join, resolve } from 'path';\nimport { existsSync } from 'fs-extra';\nimport { CORE_ASPECT_ID_MAP, CORE_ASPECT_PACKAGE_NAME_MAP } from '@arco-cli/legacy/dist/constants';\n\nconst RESOLVE_MODULE_PATHS = [];\nconst CLI_NPM_PACKAGE_SCOPE = '@arco-cli';\n\nfunction getCoreAspectName(id: string): string {\n  const [, ...name] = id.split('/');\n  return name.join('.');\n}\n\nfunction getCoreAspectPackageName(id: string): string {\n  switch (id) {\n    case CORE_ASPECT_ID_MAP.APP_ARCO:\n      return CORE_ASPECT_PACKAGE_NAME_MAP.APP_ARCO;\n\n    case CORE_ASPECT_ID_MAP.ENV_REACT:\n      return CORE_ASPECT_PACKAGE_NAME_MAP.ENV_REACT;\n\n    default:\n      return `${CLI_NPM_PACKAGE_SCOPE}/${id.split('/')[0].split('.').pop()}`;\n  }\n}\n\nfunction getAspectDir(id: string): string {\n  const aspectName = getCoreAspectName(id);\n  const packageName = getCoreAspectPackageName(id);\n\n  let dirPath = '';\n  try {\n    // it will be like packageName/dist/index.js\n    const packageEntryFilePath = require.resolve(packageName, {\n      paths: RESOLVE_MODULE_PATHS,\n    });\n\n    // remove the \"index.js\" at the end, it will be like packageName/dist\n    dirPath = join(packageEntryFilePath, '..');\n\n    // if several aspects share the same package, locate the aspect dir\n    // it will be like packageName/dist/aspectName\n    const _aspectDirPath = join(dirPath, aspectName);\n    if (existsSync(_aspectDirPath)) {\n      dirPath = _aspectDirPath;\n    }\n  } catch (e) {\n    // __dirname is node_modules/@arco-cli/core/dist/aspect-loader\n    const arcoCliNodeModulesHome = resolve(__dirname, '../../..');\n\n    // some aspect has standalone package like @arco-cli/arco\n    dirPath = resolve(arcoCliNodeModulesHome, aspectName);\n\n    if (!existsSync(dirPath)) {\n      dirPath = resolve(\n        arcoCliNodeModulesHome,\n        `${packageName.split('/').pop()}/dist/${aspectName}`\n      );\n    }\n  }\n\n  if (!existsSync(dirPath)) {\n    throw new Error(`unable to find ${aspectName} in ${dirPath}`);\n  }\n\n  return dirPath;\n}\n\nexport async function getAspectDef(aspectId: string, runtime: string, resolveModuleFrom?: string) {\n  if (resolveModuleFrom && RESOLVE_MODULE_PATHS.indexOf(resolveModuleFrom) === -1) {\n    RESOLVE_MODULE_PATHS.push(resolveModuleFrom);\n  }\n\n  const dirPath = getAspectDir(aspectId);\n  const files = glob.sync(`${dirPath}/**/**.js`);\n  const aspectPath = files.find((file) => file.includes('.aspect.js')) || join(dirPath, '..');\n  const runtimePath = runtime\n    ? files.find((file) => file.includes(`.${runtime}.runtime.js`))\n    : null;\n\n  return {\n    id: aspectId,\n    aspectPath,\n    runtimePath,\n  };\n}\n"
  },
  {
    "path": "packages/core/src/aspect-loader/index.ts",
    "content": "import { AspectLoaderAspect } from './aspectLoader.aspect';\n\nexport default AspectLoaderAspect;\nexport { AspectLoaderAspect };\nexport { PluginDefinition } from './pluginDefinition';\nexport { AspectDefinition } from './aspectDefinition';\nexport { AspectLoaderMain } from './aspectLoader.main.runtime';\nexport { getAspectDef } from './coreAspect';\n"
  },
  {
    "path": "packages/core/src/aspect-loader/pluginDefinition.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport interface PluginDefinition {\n  /**\n   * regex pattern for detecting the definition file within a component.\n   */\n  pattern: string | RegExp;\n\n  /**\n   * runtimes for the plugin to apply.\n   */\n  runtimes: string[];\n\n  /**\n   * register the plugin to its slot registry.\n   */\n  /**\n   * Plugin implementation.\n   * @param object The object that was exported as default by the *.plugin-pattern file.\n   * @param sourceAspect Pointer to the aspect that is using the plugin (the aspect that contain the *.plugin-pattern file).\n   */\n  register<T>(object: T, sourceAspect: Aspect): void;\n}\n"
  },
  {
    "path": "packages/core/src/cli/cli.aspect.ts",
    "content": "import { Aspect, RuntimeDefinition } from '@arco-cli/stone';\n\nexport const MainRuntime = new RuntimeDefinition('main');\n\nexport const CLIAspect = Aspect.create({\n  id: 'arco.core/cli',\n  declareRuntime: MainRuntime,\n});\n\nexport default CLIAspect;\n"
  },
  {
    "path": "packages/core/src/cli/cli.main.runtime.ts",
    "content": "import { clone } from 'lodash';\nimport { SlotRegistry, Slot } from '@arco-cli/stone';\nimport { Command } from '@arco-cli/legacy/dist/cli/command';\nimport { groups, GroupsType } from '@arco-cli/legacy/dist/cli/commandGroups';\nimport { BASE_DOCS_DOMAIN } from '@arco-cli/legacy/dist/constants';\nimport registerCommands from '@arco-cli/legacy/dist/cli/registerCommands';\n\nimport { Logger, LoggerAspect, LoggerMain } from '@core/logger';\n\nimport { getCommandId } from './getCommandId';\nimport { CLIAspect, MainRuntime } from './cli.aspect';\nimport { CLIParser } from './cliParser';\nimport { LegacyCommandAdapter } from './legacyCommandAdapter';\nimport { HelpCmd } from './commands/help';\n\nexport type CommandList = Array<Command>;\nexport type OnStart = (hasWorkspace: boolean) => Promise<void>;\n\nexport type OnStartSlot = SlotRegistry<OnStart>;\nexport type CommandsSlot = SlotRegistry<CommandList>;\n\nexport class CLIMain {\n  static runtime = MainRuntime;\n\n  static dependencies = [LoggerAspect];\n\n  static slots = [Slot.withType<CommandList>(), Slot.withType<OnStart>()];\n\n  static provider(\n    [loggerMain]: [LoggerMain],\n    _,\n    [commandsSlog, onStartSlot]: [CommandsSlot, OnStartSlot]\n  ) {\n    const logger = loggerMain.createLogger(CLIAspect.id);\n    const cliMain = new CLIMain(commandsSlog, onStartSlot, logger);\n    const legacyRegistry = registerCommands();\n    const legacyCommandsAdapters = legacyRegistry.commands.map(\n      (command) => new LegacyCommandAdapter(command, cliMain)\n    );\n    const helpCmd = new HelpCmd(cliMain, BASE_DOCS_DOMAIN);\n    cliMain.register(...legacyCommandsAdapters, helpCmd);\n    return cliMain;\n  }\n\n  constructor(\n    private commandsSlot: CommandsSlot,\n    private onStartSlot: OnStartSlot,\n    private logger: Logger\n  ) {}\n\n  public groups: GroupsType = clone(groups);\n\n  private async invokeOnStart(hasWorkspace: boolean) {\n    const onStartFns = this.onStartSlot.values();\n    const promises = onStartFns.map(async (onStart) => onStart(hasWorkspace));\n    return Promise.all(promises);\n  }\n\n  private setDefaults(command: Command) {\n    command.alias = command.alias || '';\n    command.description = command.description || '';\n    command.extendedDescription = command.extendedDescription || '';\n    command.group = command.group || 'ungrouped';\n    command.options = command.options || [];\n    command.private = command.private || false;\n    command.commands = command.commands || [];\n    if (command.loader === undefined) {\n      if (command.internal) {\n        command.loader = false;\n      } else {\n        command.loader = true;\n      }\n    }\n  }\n\n  register(...commands: CommandList) {\n    commands.forEach((command) => {\n      this.setDefaults(command);\n      command.commands!.forEach((cmd) => this.setDefaults(cmd));\n    });\n    this.commandsSlot.register(commands);\n  }\n\n  unregister(commandName: string) {\n    this.commandsSlot.toArray().forEach(([aspectId, commands]) => {\n      const filteredCommands = commands.filter((command) => {\n        return getCommandId(command.name) !== commandName;\n      });\n      this.commandsSlot.map.set(aspectId, filteredCommands);\n    });\n  }\n\n  registerGroup(name: string, description: string) {\n    if (this.groups[name]) {\n      this.logger.consoleWarning(`CLI group \"${name}\" is already registered`);\n    } else {\n      this.groups[name] = description;\n    }\n  }\n\n  registerOnStart(onStartFn: OnStart) {\n    this.onStartSlot.register(onStartFn);\n    return this;\n  }\n\n  /**\n   * list of all registered commands. (legacy and new).\n   */\n  get commands(): CommandList {\n    return this.commandsSlot.values().flat();\n  }\n\n  /**\n   * get an instance of a registered command. (useful for aspects to modify and extend existing commands)\n   */\n  getCommand(name: string): Command | undefined {\n    return this.commands.find((command) => getCommandId(command.name) === name);\n  }\n\n  async run(hasWorkspace: boolean) {\n    await this.invokeOnStart(hasWorkspace);\n    const parser = new CLIParser(this.commands, this.groups, undefined, BASE_DOCS_DOMAIN);\n    await parser.parse();\n  }\n}\n\nCLIAspect.addRuntime(CLIMain);\n"
  },
  {
    "path": "packages/core/src/cli/cliParser.ts",
    "content": "import yargs from 'yargs';\nimport didYouMean from 'didyoumean';\nimport { Command } from '@arco-cli/legacy/dist/cli/command';\nimport { GroupsType } from '@arco-cli/legacy/dist/cli/commandGroups';\nimport { compact } from 'lodash';\nimport logger from '@arco-cli/legacy/dist/logger/logger';\nimport loader from '@arco-cli/legacy/dist/cli/loader';\nimport chalk from 'chalk';\nimport { getCommandId } from './getCommandId';\nimport { formatHelp } from './help';\nimport { GLOBAL_GROUP, STANDARD_GROUP, YargsAdapter } from './yargsAdapter';\nimport { CommandNotFoundError } from './exceptions';\n\nexport class CLIParser {\n  constructor(\n    private commands: Command[],\n    private groups: GroupsType,\n    public parser = yargs,\n    private docsDomain: string\n  ) {}\n\n  async parse(args = process.argv.slice(2)) {\n    this.throwForNonExistsCommand(args[0]);\n    logger.debug(`[+] CLI-INPUT: ${args.join(' ')}`);\n    yargs(args);\n    yargs.help(false);\n    this.configureParser();\n    this.commands.forEach((command: Command) => {\n      if (command.commands && command.commands.length) {\n        this.parseCommandWithSubCommands(command);\n      } else {\n        const yargsCommand = this.getYargsCommand(command);\n        yargs.command(yargsCommand);\n      }\n    });\n    this.configureGlobalFlags();\n    this.setHelpMiddleware();\n    this.handleCommandFailure();\n    this.configureCompletion();\n\n    // don't allow non-exist flags and non-exist commands\n    yargs.strict();\n    yargs.wrap(null);\n\n    await yargs.parse();\n  }\n\n  private setHelpMiddleware() {\n    yargs.middleware((argv) => {\n      if (argv._.length === 0 && argv.help) {\n        // this is the main help page\n        this.printHelp();\n        process.exit(0);\n      }\n      if (argv.help) {\n        loader.off();\n        // this is a command help page\n        yargs.showHelp(this.logCommandHelp.bind(this));\n        if (!logger.isDaemon) process.exit(0);\n      }\n    }, true);\n  }\n\n  private handleCommandFailure() {\n    yargs.fail((msg, err) => {\n      loader.stop();\n      if (err) throw err;\n      yargs.showHelp(this.logCommandHelp.bind(this));\n      const args = process.argv.slice(2);\n      const isHelpFlagEntered = args.includes('--help') || args.includes('-h');\n      const isMsgAboutMissingArgs = msg.startsWith('Not enough non-option arguments');\n      // avoid showing the \"Not enough non-option arguments\" message when the user is trying to get the command help\n      if (!isMsgAboutMissingArgs || !isHelpFlagEntered) {\n        console.log(`\\n${chalk.yellow(msg)}`);\n      }\n      if (!logger.isDaemon) process.exit(1);\n    });\n  }\n\n  private configureCompletion() {\n    const commandsToShowComponentIdsForCompletion = [\n      'show',\n      'build',\n      'test',\n      'lint',\n      'log',\n      'dependents',\n      'dependencies',\n    ];\n    // @ts-ignore\n    yargs.completion('completion', async function (current, argv, completionFilter, done) {\n      if (!current.startsWith('-') && commandsToShowComponentIdsForCompletion.includes(argv._[1])) {\n        // TODO command args completion\n        done();\n      } else {\n        completionFilter();\n      }\n    });\n  }\n\n  private printHelp() {\n    const help = formatHelp(this.commands, this.groups, this.docsDomain);\n    console.log(help);\n  }\n\n  private configureParser() {\n    yargs.parserConfiguration({\n      'strip-aliased': true,\n      'boolean-negation': false,\n      'populate--': true,\n    });\n  }\n\n  private parseCommandWithSubCommands(command: Command) {\n    const yarnCommand = this.getYargsCommand(command);\n    yarnCommand.builder = () => {\n      command.commands?.forEach((cmd) => {\n        const subCommand = this.getYargsCommand(cmd);\n        yargs.command(subCommand);\n      });\n      // since the \"builder\" method is overridden, the global flags of the main command are gone, this fixes it.\n      yargs.options(YargsAdapter.getGlobalOptions(command));\n      return yargs;\n    };\n    yargs.command(yarnCommand);\n  }\n\n  private getYargsCommand(command: Command): YargsAdapter {\n    const yarnCommand = new YargsAdapter(command);\n    yarnCommand.builder = yarnCommand.builder.bind(yarnCommand);\n    yarnCommand.handler = yarnCommand.handler.bind(yarnCommand);\n    return yarnCommand;\n  }\n\n  private configureGlobalFlags() {\n    yargs.version(false);\n    yargs\n      .option('help', {\n        alias: 'h',\n        describe: 'show help',\n        group: GLOBAL_GROUP,\n      })\n      .option('version', {\n        global: false,\n        alias: 'v',\n        describe: 'show version',\n        group: GLOBAL_GROUP,\n      });\n  }\n\n  private throwForNonExistsCommand(commandName: string) {\n    if (!commandName || commandName.startsWith('-')) {\n      return;\n    }\n\n    const commandsNames = this.commands.map((c) => getCommandId(c.name));\n    const aliases = this.commands.map((c) => c.alias).filter((a) => a);\n    const existingGlobalFlags = ['-V', '--version'];\n    const validCommands = [...commandsNames, ...aliases, ...existingGlobalFlags];\n    const commandExist = validCommands.includes(commandName);\n\n    if (!commandExist) {\n      didYouMean.returnFirstMatch = true;\n      const suggestions = didYouMean(\n        commandName,\n        this.commands.filter((c) => !c.private).map((c) => getCommandId(c.name))\n      );\n      const suggestion = suggestions && Array.isArray(suggestions) ? suggestions[0] : suggestions;\n\n      throw new CommandNotFoundError(commandName, suggestion as string);\n    }\n  }\n\n  /**\n   * manipulate the command help output. there is no API from Yarn to do any of this, so it needs to be done manually.\n   * see https://github.com/yargs/yargs/issues/1956\n   *\n   * the original order of the output:\n   * description\n   * Options\n   * Commands\n   * Global\n   * Positionals\n   * Examples\n   */\n  private logCommandHelp(help: string) {\n    const command = this.findCommandByArgv();\n\n    const replacer = (_, p1, p2) => `${p1}${chalk.green(p2)}`;\n    const lines = help.split('\\n');\n    const linesWithoutEmpty = compact(lines);\n    const cmdLine = linesWithoutEmpty[0];\n    const description: string[] = [];\n    const options: string[] = [];\n    const globalOptions: string[] = [];\n    const subCommands: string[] = [];\n    const args: string[] = [];\n    const examples: string[] = [];\n\n    let optionsStarted = false;\n    let globalStarted = false;\n    let subCommandsStarted = false;\n    let positionalsStarted = false;\n    let examplesStarted = false;\n    for (let i = 1; i < linesWithoutEmpty.length; i += 1) {\n      const currentLine = linesWithoutEmpty[i];\n      if (currentLine === STANDARD_GROUP) {\n        optionsStarted = true;\n      } else if (currentLine === GLOBAL_GROUP) {\n        globalStarted = true;\n      } else if (currentLine === 'Commands:') {\n        subCommandsStarted = true;\n      } else if (currentLine === 'Positionals:') {\n        positionalsStarted = true;\n      } else if (currentLine === 'Examples:') {\n        examplesStarted = true;\n      } else if (examplesStarted) {\n        examples.push(currentLine);\n      } else if (positionalsStarted) {\n        args.push(currentLine);\n      } else if (globalStarted) {\n        globalOptions.push(currentLine);\n      } else if (optionsStarted) {\n        options.push(currentLine);\n      } else if (subCommandsStarted) {\n        subCommands.push(currentLine);\n      } else {\n        description.push(currentLine);\n      }\n    }\n\n    // show the flags in green\n    const optionsColored = options.map((opt) =>\n      opt.replace(/(--)([\\w-]+)/, replacer).replace(/(-)([\\w-]+)/, replacer)\n    );\n    const argsColored = args.map((arg) =>\n      arg.replace(/^ {2}\\S+/, (argName) => chalk.green(argName))\n    ); // regex: two spaces then the first word until a white space\n    const optionsStr = options.length ? `\\n${STANDARD_GROUP}\\n${optionsColored.join('\\n')}\\n` : '';\n    const argumentsStr = args.length ? `\\nArguments:\\n${argsColored.join('\\n')}\\n` : '';\n    const examplesStr = examples.length ? `\\nExamples:\\n${examples.join('\\n')}\\n` : '';\n    const subCommandsStr = subCommands.length\n      ? `\\n${'Commands:'}\\n${subCommands.join('\\n')}\\n`\n      : '';\n    // show the description in bold\n    const descriptionColored = description.map((desc) => chalk.bold(desc));\n    if (command?.extendedDescription) {\n      descriptionColored.push(command?.extendedDescription);\n    }\n    if (command?.helpUrl) {\n      descriptionColored.push(`for more info, visit: ${chalk.underline(command.helpUrl)}`);\n    }\n    const descriptionStr = descriptionColored.join('\\n');\n    const globalOptionsStr = globalOptions.join('\\n');\n\n    const finalOutput = `${cmdLine}\n\n${descriptionStr}\n${argumentsStr}${subCommandsStr}${optionsStr}${examplesStr}\n${GLOBAL_GROUP}\n${globalOptionsStr}`;\n\n    console.log(finalOutput);\n  }\n\n  private findCommandByArgv(): Command | undefined {\n    const [enteredCommand, enteredSubCommand] = process.argv.slice(2);\n    if (!enteredCommand) return null;\n\n    const isCommandMatch = (cmd: Command, str: string) => {\n      // e.g. \"tag <id>\".startsWith(\"tag \")\n      // e.g. \"globals\" === \"globals\"\n      // e.g. \"t\" === \"t\"\n      return cmd.name.startsWith(`${str} `) || cmd.name === str || cmd.alias === str;\n    };\n    const command = this.commands.find((cmd) => isCommandMatch(cmd, enteredCommand));\n\n    if (!command) return null;\n    // no sub-commands\n    if (!command.commands || !enteredSubCommand) return command;\n\n    const subCommand = command.commands.find((cmd) => isCommandMatch(cmd, enteredSubCommand));\n    return subCommand || command;\n  }\n}\n"
  },
  {
    "path": "packages/core/src/cli/commandRunner.ts",
    "content": "import logger, { LoggerLevel } from '@arco-cli/legacy/dist/logger';\nimport { CLIArgs, Command, Flags, RenderResult } from '@arco-cli/legacy/dist/cli/command';\nimport { parseCommandName } from '@arco-cli/legacy/dist/cli/commandRegistry';\nimport loader from '@arco-cli/legacy/dist/cli/loader';\nimport { handleErrorAndExit } from '@arco-cli/legacy/dist/cli/handleErrors';\n\nexport class CommandRunner {\n  constructor(private command: Command, private args: CLIArgs, private flags: Flags) {\n    this.commandName = parseCommandName(this.command.name);\n  }\n\n  private readonly commandName: string;\n\n  private bootstrapCommand() {\n    // Analytics.init(this.commandName, this.flags, this.args);\n    logger.info(`[*] started a new command: \"${this.commandName}\" with the following data:`, {\n      args: this.args,\n      flags: this.flags,\n    });\n  }\n\n  /**\n   * when both \"render\" and \"report\" were implemented, check whether it's a terminal.\n   * if it's a terminal, use \"render\", if not, use \"report\" because \"report\" is just a string\n   */\n  private shouldRunRender() {\n    const isTerminal = process.stdout.isTTY;\n    return this.command.report && !isTerminal ? false : Boolean(this.command.render);\n  }\n\n  /**\n   * this works for both, Stone commands and Legacy commands (the legacy-command-adapter\n   * implements json() method)\n   */\n  private async runJsonHandler() {\n    if (!this.flags.json) return null;\n    if (!this.command.json)\n      throw new Error(`command \"${this.commandName}\" doesn't implement \"json\" method`);\n    const result = await this.command.json(this.args, this.flags);\n    const code = result.code || 0;\n    const data = result.data || result;\n    await this.writeAndExit(JSON.stringify(data, null, 2), code);\n    return null;\n  }\n\n  private async runRenderHandler() {\n    if (!this.command.render) {\n      throw new Error('runRenderHandler expects command.render to be implemented');\n    }\n\n    const result = await this.command.render(this.args, this.flags);\n    loader.off();\n    const { data, code } = toRenderResult(result);\n\n    if (this.command.inkRender) {\n      const { waitUntilExit } = this.command.inkRender(data);\n      await waitUntilExit?.();\n    }\n\n    return logger.exitAfterFlush(code, this.commandName);\n  }\n\n  private async runReportHandler() {\n    if (!this.command.report)\n      throw new Error('runReportHandler expects command.report to be implemented');\n    const result = await this.command.report(this.args, this.flags);\n    loader.off();\n    const data = typeof result === 'string' ? result : result.data;\n    const exitCode = typeof result === 'string' ? 0 : result.code;\n    await this.writeAndExit(`${data}\\n`, exitCode);\n    return null;\n  }\n\n  /**\n   * the loader and logger.console write output to the console during the command execution.\n   * for internals commands, such as, _put, _fetch, the command.loader = false.\n   */\n  private determineConsoleWritingDuringCommand() {\n    if (this.command.loader && !this.flags.json && !this.flags['get-yargs-completions']) {\n      loader.on();\n      loader.start(`running command \"${this.commandName}\"...`);\n      logger.shouldWriteToConsole = true;\n    } else {\n      loader.off();\n      logger.shouldWriteToConsole = false;\n    }\n    if (this.flags.log) {\n      // probably not necessary anymore. it is handled in src/logger - determineWritingLogToScreen()\n      const logValue = typeof this.flags.log === 'string' ? this.flags.log : undefined;\n      logger.switchToConsoleLogger(logValue as LoggerLevel);\n    }\n  }\n\n  private async writeAndExit(data: string, exitCode: number) {\n    return process.stdout.write(data, async () =>\n      logger.exitAfterFlush(exitCode, this.commandName, data)\n    );\n  }\n\n  private async runMigrateIfNeeded(): Promise<any> {\n    // @ts-ignore LegacyCommandAdapter has .migration\n    if (this.command.migration) {\n      logger.debug('Checking if a migration is needed');\n      // TODO complete migrate func here\n      return null;\n    }\n    return null;\n  }\n\n  /**\n   * run command using one of the handler, \"json\"/\"report\"/\"render\". once done, exit the process.\n   */\n  async runCommand(): Promise<void> {\n    try {\n      this.bootstrapCommand();\n      await this.runMigrateIfNeeded();\n      this.determineConsoleWritingDuringCommand();\n      if (this.flags.json) {\n        return await this.runJsonHandler();\n      }\n      if (this.shouldRunRender()) {\n        return await this.runRenderHandler();\n      }\n      if (this.command.report) {\n        return await this.runReportHandler();\n      }\n    } catch (err: any) {\n      return handleErrorAndExit(err, this.commandName, this.command.internal);\n    }\n\n    throw new Error(\n      `command \"${this.commandName}\" doesn't implement \"render\" nor \"report\" methods`\n    );\n  }\n}\n\nfunction toRenderResult(obj: RenderResult | any) {\n  return isRenderResult(obj) ? obj : { data: obj, code: 0 };\n}\n\nfunction isRenderResult(obj: RenderResult | any): obj is RenderResult {\n  return typeof obj === 'object' && typeof obj.code === 'number' && obj.hasOwnProperty('data');\n}\n"
  },
  {
    "path": "packages/core/src/cli/commands/help.ts",
    "content": "import { Command, CommandOptions } from '@arco-cli/legacy/dist/cli/command';\nimport { CLIMain } from '../cli.main.runtime';\nimport { formatHelp } from '../help';\n\nexport class HelpCmd implements Command {\n  name = 'help';\n\n  description = 'show help information';\n\n  // Default command (meaning, if no args are provided, this will be used)\n  // https://github.com/yargs/yargs/blob/master/docs/advanced.md#default-command\n  alias = '$0';\n\n  loader = false;\n\n  group = 'general';\n\n  options = [] as CommandOptions;\n\n  constructor(private cliMain: CLIMain, private docsDomain: string) {}\n\n  async report() {\n    return formatHelp(this.cliMain.commands, this.cliMain.groups, this.docsDomain);\n  }\n}\n"
  },
  {
    "path": "packages/core/src/cli/exceptions/alreadyExistsError.ts",
    "content": "import ArcoError from '@arco-cli/legacy/dist/error/arcoError';\n\nexport class AlreadyExistsError extends ArcoError {\n  constructor(type: string, name: string) {\n    super(`${type} ${name} already exists.`);\n  }\n}\n"
  },
  {
    "path": "packages/core/src/cli/exceptions/commandNotFoundError.ts",
    "content": "import chalk from 'chalk';\nimport ArcoError from '@arco-cli/legacy/dist/error/arcoError';\n\nexport class CommandNotFoundError extends ArcoError {\n  commandName: string;\n\n  suggestion?: string;\n\n  constructor(commandName: string, suggestion?: string) {\n    super(`command ${commandName} was not found`);\n    this.commandName = commandName;\n    this.suggestion = suggestion;\n  }\n\n  report() {\n    let output = chalk.yellow(\n      `warning: '${chalk.bold(this.commandName)}' is not a valid command.\nsee 'arco help' for additional information`\n    );\n    if (this.suggestion) {\n      output += `\\nDid you mean ${chalk.bold(this.suggestion)}?`;\n    }\n    return output;\n  }\n}\n"
  },
  {
    "path": "packages/core/src/cli/exceptions/index.ts",
    "content": "export { AlreadyExistsError } from './alreadyExistsError';\nexport { CommandNotFoundError } from './commandNotFoundError';\n"
  },
  {
    "path": "packages/core/src/cli/getCommandId.ts",
    "content": "export function getCommandId(cmdName: string) {\n  return cmdName.split(' ')[0].trim();\n}\n"
  },
  {
    "path": "packages/core/src/cli/help.ts",
    "content": "import chalk from 'chalk';\nimport rightpad from 'pad-right';\nimport { capitalize } from 'lodash';\nimport { GroupsType } from '@arco-cli/legacy/dist/cli/commandGroups';\nimport { CommandList } from './cli.main.runtime';\nimport { getCommandId } from './getCommandId';\n\nconst SPACE = ' ';\nconst TITLE_LEFT_SPACES_NUMBER = 2;\nconst COMMAND_LEFT_SPACES_NUMBER = 4;\nconst NAME_WITH_SPACES_LENGTH = 15;\n\ntype GroupContent = {\n  commands: { [cmdName: string]: string };\n  description: string;\n};\n\ntype HelpProps = {\n  [groupName: string]: GroupContent;\n};\n\nexport function formatHelp(commands: CommandList, groups: GroupsType, docsDomain: string) {\n  const helpProps = groupCommands(commands, groups);\n  const commandsStr = formatCommandsHelp(helpProps);\n\n  return `${getHeader(docsDomain)}\n\n${commandsStr}\n\n${getFooter()}`;\n}\n\nfunction groupCommands(commands: CommandList, groups: GroupsType): HelpProps {\n  const help: HelpProps = commands\n    .filter((command) => !command.private && command.description)\n    .reduce(function (partialHelp, command) {\n      // at this stage, it must be set\n      const groupName = command.group as string;\n      partialHelp[groupName] = partialHelp[groupName] || {\n        commands: {},\n        description: groups[groupName] || capitalize(command.group),\n      };\n      const cmdId = getCommandId(command.name);\n      partialHelp[groupName].commands[cmdId] = command.description;\n      return partialHelp;\n    }, {});\n  return help;\n}\n\nfunction formatCommandsHelp(helpProps: HelpProps): string {\n  return Object.keys(helpProps)\n    .map((groupName) => commandsSectionTemplate(helpProps[groupName]))\n    .join('\\n\\n');\n}\n\nfunction commandsSectionTemplate(section: GroupContent): string {\n  const titleSpace = SPACE.repeat(TITLE_LEFT_SPACES_NUMBER);\n  const title = `${titleSpace}${chalk.underline.bold.blue(section.description)}`;\n  const commands = Object.keys(section.commands)\n    .map((cmdName) => commandTemplate(cmdName, section.commands[cmdName]))\n    .join('\\n');\n  const res = `${title}\\n${commands}`;\n  return res;\n}\n\nfunction commandTemplate(name: string, description: string): string {\n  const nameSpace = SPACE.repeat(COMMAND_LEFT_SPACES_NUMBER);\n  const nameWithRightSpace = rightpad(name, NAME_WITH_SPACES_LENGTH, SPACE);\n  return `${nameSpace}${chalk.green(nameWithRightSpace)}${description}`;\n}\n\nfunction getHeader(docsDomain: string): string {\n  return `${chalk.bold('usage: arco [--version] [--help] <command> [<args>]')}\n\n${chalk.yellow(`Arco Material Market: https://${docsDomain}`)}`;\n}\n\nfunction getFooter(): string {\n  return `${chalk.yellow(\n    \"Please use 'arco <command> --help' for more information and guides on specific commands.\"\n  )}`;\n}\n"
  },
  {
    "path": "packages/core/src/cli/index.ts",
    "content": "import { CLIAspect, MainRuntime } from './cli.aspect';\n\nexport default CLIAspect;\nexport { CLIAspect, MainRuntime };\nexport type { CLIMain } from './cli.main.runtime';\n"
  },
  {
    "path": "packages/core/src/cli/legacyCommandAdapter.ts",
    "content": "import { LegacyCommand } from '@arco-cli/legacy/dist/cli/legacyCommand';\nimport { Command, CommandOptions, GenericObject } from '@arco-cli/legacy/dist/cli/command';\nimport { CLIMain } from './cli.main.runtime';\n\ntype ActionResult = {\n  code: number;\n  report: string;\n};\n\nexport class LegacyCommandAdapter implements Command {\n  alias: string;\n\n  name: string;\n\n  description: string;\n\n  options: CommandOptions;\n\n  extendedDescription?: string;\n\n  group?: string;\n\n  loader?: boolean;\n\n  commands: Command[];\n\n  private?: boolean;\n\n  migration?: boolean;\n\n  internal?: boolean;\n\n  skipWorkspace?: boolean;\n\n  helpUrl?: string;\n\n  _packageManagerArgs?: string[];\n\n  constructor(private cmd: LegacyCommand, cliExtension: CLIMain) {\n    this.name = cmd.name;\n    this.description = cmd.description;\n    this.helpUrl = cmd.helpUrl;\n    this.options = cmd.options || [];\n    this.alias = cmd.alias;\n    this.extendedDescription = cmd.extendedDescription;\n    this.skipWorkspace = cmd.skipWorkspace;\n    this.group = cmd.group;\n    this.loader = cmd.loader;\n    this.private = cmd.private;\n    this.migration = cmd.migration;\n    this.internal = cmd.internal;\n    this.commands = (cmd.commands || []).map((sub) => new LegacyCommandAdapter(sub, cliExtension));\n  }\n\n  private async action(params: any, options: { [key: string]: any }): Promise<ActionResult> {\n    const res = await this.cmd.action(params, options, this._packageManagerArgs);\n    let data = res;\n    let code = 0;\n    if (res && res.__code !== undefined) {\n      data = res.data;\n      code = res.__code;\n    }\n    const report = this.cmd.report(data, params, options);\n    return {\n      code,\n      report,\n    };\n  }\n\n  async report(\n    params: any,\n    options: { [key: string]: any }\n  ): Promise<{ data: string; code: number }> {\n    const actionResult = await this.action(params, options);\n    return { data: actionResult.report, code: actionResult.code };\n  }\n\n  async json(params: any, options: { [key: string]: any }): Promise<GenericObject> {\n    const actionResult = await this.action(params, options);\n    return {\n      data: JSON.parse(actionResult.report),\n      code: actionResult.code,\n    };\n  }\n}\n"
  },
  {
    "path": "packages/core/src/cli/utils.ts",
    "content": "import yargs from 'yargs';\n\nconst ENV_JEST_ARGS = process.env.JEST_ARGS;\n\n/**\n * parse cli args from raw args like: 'jest -u --silent=false; mocha -h'\n */\nexport function parseCliRawArgs(\n  command: 'jest',\n  originArgs = ''\n): { args: string; parsed: Record<string, any> } {\n  const argsFromEnv = command === 'jest' ? ENV_JEST_ARGS : null;\n  const regExp = new RegExp(`^\\\\s*${command}\\\\s*`, 'i');\n  const args =\n    argsFromEnv ||\n    (originArgs.split(';').find((str) => regExp.test(str)) || '').replace(regExp, '');\n  return {\n    args,\n    parsed: yargs(args).argv,\n  };\n}\n"
  },
  {
    "path": "packages/core/src/cli/yargsAdapter.ts",
    "content": "import { camelCase } from 'lodash';\nimport { Command } from '@arco-cli/legacy/dist/cli/command';\nimport { Arguments, CommandModule, Argv, Options } from 'yargs';\nimport { CommandRunner } from './commandRunner';\n\nexport const GLOBAL_GROUP = 'Global';\nexport const STANDARD_GROUP = 'Options';\n\nexport class YargsAdapter implements CommandModule {\n  command: string;\n\n  describe?: string;\n\n  aliases?: string;\n\n  constructor(private commanderCommand: Command) {\n    this.command = commanderCommand.name;\n    this.describe = commanderCommand.description;\n    this.aliases = commanderCommand.alias;\n  }\n\n  builder(yargs: Argv) {\n    const options = YargsAdapter.optionsToBuilder(this.commanderCommand);\n    yargs.option(options);\n    this.commanderCommand.arguments?.forEach((arg) => {\n      yargs.positional(arg.name, { description: arg.description });\n    });\n    this.commanderCommand.examples?.forEach((example) => {\n      yargs.example(example.cmd, example.description);\n    });\n\n    return yargs;\n  }\n\n  handler(argv: Arguments) {\n    const enteredArgs = getArgsFromCommandName(this.commanderCommand.name);\n    const argsValues = enteredArgs.map((a) => argv[a]) as any[];\n    // a workaround to get a flag syntax such as \"--all [version]\" work with yargs.\n    const flags = Object.keys(argv).reduce((acc, current) => {\n      if (current === '_' || current === '$0' || current === '--') return acc;\n      // const flagName = current.split(' ')[0];\n      acc[current] = typeof argv[current] === 'string' && !argv[current] ? true : argv[current];\n      return acc;\n    }, {});\n    this.commanderCommand._packageManagerArgs = (argv['--'] || []) as string[];\n\n    const commandRunner = new CommandRunner(this.commanderCommand, argsValues, flags);\n    return commandRunner.runCommand();\n  }\n\n  get positional() {\n    return this.commanderCommand.arguments;\n  }\n\n  static optionsToBuilder(command: Command): { [key: string]: Options } {\n    const option = command.options.reduce((acc, [alias, opt, desc]) => {\n      const optName = opt.split(' ')[0];\n      acc[optName] = {\n        alias,\n        describe: desc,\n        group: STANDARD_GROUP,\n        type: opt.includes(' ') ? 'string' : 'boolean',\n        requiresArg: opt.includes('<'),\n      } as Options;\n      return acc;\n    }, {});\n    const globalOptions = YargsAdapter.getGlobalOptions(command);\n\n    return { ...option, ...globalOptions };\n  }\n\n  static getGlobalOptions(command: Command): Record<string, any> {\n    const globalOptions: Record<string, any> = {};\n    if (!command.internal) {\n      globalOptions.log = {\n        describe:\n          'print log messages to the screen, options are: [trace, debug, info, warn, error, fatal], the default is info',\n        group: GLOBAL_GROUP,\n      };\n      globalOptions['safe-mode'] = {\n        describe:\n          'bootstrap the bare-minimum with only the CLI aspect. useful mainly for low-level commands when cli refuses to load',\n        group: GLOBAL_GROUP,\n      };\n    }\n    return globalOptions;\n  }\n}\n\nfunction getArgsFromCommandName(commandName: string) {\n  const commandSplit = commandName.split(' ');\n  // remove the first element, it's the command-name\n  commandSplit.shift();\n\n  return commandSplit.map((existArg) => {\n    const trimmed = existArg.trim();\n    if (\n      (!trimmed.startsWith('<') && !trimmed.startsWith('[')) ||\n      (!trimmed.endsWith('>') && !trimmed.endsWith(']'))\n    ) {\n      throw new Error(\n        `expect arg \"${trimmed}\" of \"${commandName}\" to be wrapped with \"[]\" or \"<>\"`\n      );\n    }\n    // remove the opening and closing brackets\n    const withoutBrackets = trimmed.slice(1, -1);\n    return camelCase(withoutBrackets);\n  });\n}\n"
  },
  {
    "path": "packages/core/src/express/express.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const ExpressAspect = Aspect.create({\n  id: 'arco.core/express',\n});\n\nexport default ExpressAspect;\n"
  },
  {
    "path": "packages/core/src/express/express.main.runtime.ts",
    "content": "import { Slot, SlotRegistry } from '@arco-cli/stone';\nimport express, { Express } from 'express';\nimport bodyParser from 'body-parser';\nimport { concat, flatten, lowerCase, sortBy } from 'lodash';\n\nimport { MainRuntime } from '@core/cli';\nimport { Logger, LoggerAspect, LoggerMain } from '@core/logger';\n\nimport { ExpressAspect } from './express.aspect';\nimport { catchErrors } from './middlewares';\nimport { Middleware, Request, Response, Route, Verb, MiddlewareManifest } from './types';\n\nexport type ExpressConfig = {\n  port: number;\n  namespace: string;\n  loggerIgnorePath: string[];\n};\n\nexport type MiddlewareSlot = SlotRegistry<MiddlewareManifest[]>;\n\nexport type RouteSlot = SlotRegistry<Route[]>;\n\nexport class ExpressMain {\n  static runtime = MainRuntime;\n\n  static dependencies = [LoggerAspect];\n\n  static slots = [Slot.withType<Route[]>(), Slot.withType<MiddlewareManifest[]>()];\n\n  static defaultConfig = {\n    port: 4001,\n    namespace: 'api',\n    loggerIgnorePath: ['/api/_health'],\n  };\n\n  static async provider(\n    [loggerFactory]: [LoggerMain],\n    config: ExpressConfig,\n    [routeSlot, middlewareSlot]: [RouteSlot, MiddlewareSlot]\n  ) {\n    const logger = loggerFactory.createLogger(ExpressAspect.id);\n    return new ExpressMain(config, routeSlot, logger, middlewareSlot);\n  }\n\n  constructor(\n    /**\n     * extension config\n     */\n    readonly config: ExpressConfig,\n\n    /**\n     * slot for registering express route\n     */\n    private routeSlot: RouteSlot,\n\n    /**\n     * logger extension.\n     */\n    readonly logger: Logger,\n\n    readonly middlewareSlot: MiddlewareSlot\n  ) {}\n\n  private createRootRoutes() {\n    return [\n      {\n        namespace: ExpressAspect.id,\n        method: 'get',\n        path: '/_health',\n        disableNamespace: false,\n        priority: 0,\n        middlewares: [async (_req: Request, res: Response) => res.send('ok')],\n      },\n    ];\n  }\n\n  private createRoutes() {\n    const routesSlots = this.routeSlot.toArray();\n    const routeEntries = routesSlots.map(([, routes]) => {\n      return routes.map((route) => {\n        const middlewares = flatten([this.verbValidation(route), route.middlewares]);\n        return {\n          method: lowerCase(route.method),\n          path: route.route,\n          disableNamespace: route.disableNamespace,\n          middlewares,\n          priority: route.priority || 0,\n        };\n      });\n    });\n\n    return flatten(routeEntries);\n  }\n\n  private verbValidation(route: Route): Middleware {\n    return async (req: express.Request, res: express.Response, next: express.NextFunction) => {\n      if (!route.verb) return next();\n      const verb = req.headers['x-verb'] || Verb.READ;\n      if (verb !== route.verb) {\n        res.status(403);\n        return res.jsonp({ message: 'You are not authorized', error: 'forbidden' });\n      }\n      return next();\n    };\n  }\n\n  private catchErrorsMiddlewares(middlewares: Middleware[]) {\n    return middlewares.map((middleware) => catchErrors(middleware));\n  }\n\n  private bodyParser(app: Express) {\n    app.use(bodyParser.json({ limit: '5000mb' }));\n    app.use(bodyParser.raw({ type: 'application/octet-stream', limit: '5000mb' }));\n  }\n\n  /**\n   * start a express server.\n   */\n  async listen(port?: number) {\n    const serverPort = port || this.config.port;\n    const app = this.createApp();\n    app.listen(serverPort);\n  }\n\n  /**\n   * register a new express routes.\n   * route will be added as `/api/${route}`\n   */\n  register(routes: Route[]) {\n    this.routeSlot.register(routes);\n    return this;\n  }\n\n  /**\n   * register a new middleware into express.\n   */\n  registerMiddleware(middlewares: MiddlewareManifest[]) {\n    this.middlewareSlot.register(middlewares);\n    return this;\n  }\n\n  createApp(expressApp?: Express, options?: { disableBodyParser: true }): Express {\n    const internalRoutes = this.createRootRoutes();\n    const routes = this.createRoutes();\n    const allRoutes = concat(routes, internalRoutes);\n    const sortedRoutes = sortBy(allRoutes, (r) => r.priority).reverse();\n    const app = expressApp || express();\n    app.use((req, _res, next) => {\n      if (this.config.loggerIgnorePath.includes(req.url)) return next();\n      this.logger.debug(`express got a request to a URL: ${req.url}', headers:`, req.headers);\n      return next();\n    });\n    if (!options?.disableBodyParser) this.bodyParser(app);\n\n    this.middlewareSlot\n      .toArray()\n      .flatMap(([, middlewares]) =>\n        middlewares.flatMap((middlewareManifest) => app.use(middlewareManifest.middleware))\n      );\n    sortedRoutes.forEach((routeInfo) => {\n      const { method, path, middlewares, disableNamespace } = routeInfo;\n      const namespace = disableNamespace ? '' : `/${this.config.namespace}`;\n      app[method](`${namespace}${path}`, this.catchErrorsMiddlewares(middlewares));\n    });\n\n    return app;\n  }\n}\n\nExpressAspect.addRuntime(ExpressMain);\n"
  },
  {
    "path": "packages/core/src/express/index.ts",
    "content": "export { RouteSlot } from './express.main.runtime';\nexport { Route, Verb } from './types';\nexport { Request, Response, NextFunction } from './types';\nexport type { ExpressMain } from './express.main.runtime';\nexport { ExpressAspect } from './express.aspect';\n"
  },
  {
    "path": "packages/core/src/express/middlewares/error.ts",
    "content": "import * as express from 'express';\nimport logger from '@arco-cli/legacy/dist/logger/logger';\n\ninterface ResponseError {\n  status?: number;\n  message?: string;\n}\n\nfunction handleError(\n  err: ResponseError,\n  req: express.Request,\n  res: express.Response,\n  // Do not remove unused next, it's needed for express to catch errors!\n  _next: express.NextFunction\n) {\n  logger.error(`express.errorHandle, url ${req.url}, error:`, err);\n  err.status = err.status || 500;\n  res.status(err.status);\n  return res.jsonp({\n    message: err.message,\n    error: err,\n  });\n}\n\nexport const catchErrors =\n  (action: any) => (req: express.Request, res: express.Response, next: express.NextFunction) =>\n    action(req, res, next).catch((error: ResponseError) => handleError(error, req, res, next));\n"
  },
  {
    "path": "packages/core/src/express/middlewares/index.ts",
    "content": "export { catchErrors } from './error';\n"
  },
  {
    "path": "packages/core/src/express/types/index.ts",
    "content": "export { Request } from './request';\nexport { Response } from './response';\nexport { NextFunction } from './next';\nexport { Route, Middleware, Verb } from './route';\nexport { MiddlewareManifest } from './middlewareManifest';\n"
  },
  {
    "path": "packages/core/src/express/types/middlewareManifest.ts",
    "content": "import { Middleware } from './route';\n\nexport interface MiddlewareManifest {\n  middleware: Middleware;\n}\n"
  },
  {
    "path": "packages/core/src/express/types/next.ts",
    "content": "import express from 'express';\n\nexport type NextFunction = express.NextFunction;\n"
  },
  {
    "path": "packages/core/src/express/types/request.ts",
    "content": "export type { Request } from 'express';\n"
  },
  {
    "path": "packages/core/src/express/types/response.ts",
    "content": "import express from 'express';\n\nexport type Response = express.Response;\n"
  },
  {
    "path": "packages/core/src/express/types/route.ts",
    "content": "import { NextFunction } from './next';\nimport { Request } from './request';\nimport { Response } from './response';\n\n/**\n * define express Middleware\n */\nexport type Middleware = (req: Request, res: Response, next: NextFunction) => Promise<any>;\n\nexport enum Verb {\n  // eslint-disable-next-line no-unused-vars\n  WRITE = 'write',\n  // eslint-disable-next-line no-unused-vars\n  READ = 'read',\n}\n\n/**\n * express new Route\n */\nexport interface Route {\n  method: string;\n  route: string | RegExp;\n  disableNamespace?: boolean;\n  verb?: Verb;\n  middlewares: Middleware[];\n  /** route priority if 2 route with the same name default is 0 */\n  priority?: number;\n}\n"
  },
  {
    "path": "packages/core/src/graphql/graphql.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const GraphqlAspect = Aspect.create({\n  id: 'arco.core/graphql',\n});\n\nexport default GraphqlAspect;\n"
  },
  {
    "path": "packages/core/src/graphql/graphql.main.runtime.ts",
    "content": "import cors from 'cors';\nimport { createServer } from 'http';\nimport { GraphQLModule } from '@graphql-modules/core';\nimport { Stone, Slot, SlotRegistry } from '@arco-cli/stone';\nimport express, { Express } from 'express';\nimport { graphqlHTTP } from 'express-graphql';\nimport { PubSubEngine, PubSub } from 'graphql-subscriptions';\n\nimport { MainRuntime } from '@core/cli';\nimport { Logger, LoggerAspect, LoggerMain } from '@core/logger';\n\nimport { Schema } from './schema';\nimport { GraphqlAspect } from './graphql.aspect';\n\nexport enum Verb {\n  // eslint-disable-next-line no-unused-vars\n  WRITE = 'write',\n  // eslint-disable-next-line no-unused-vars\n  READ = 'read',\n}\n\ntype GraphQLConfig = {\n  port: number;\n};\n\ntype SchemaSlot = SlotRegistry<Schema>;\n\ntype PubSubSlot = SlotRegistry<PubSubEngine>;\n\nexport type GraphQLServerOptions = {\n  schemaSlot?: SchemaSlot;\n  app?: Express;\n  graphiql?: boolean;\n};\n\nexport class GraphqlMain {\n  constructor(\n    /**\n     * extension config\n     */\n    readonly config: GraphQLConfig,\n\n    /**\n     * slot for registering graphql modules\n     */\n    private moduleSlot: SchemaSlot,\n\n    /**\n     * Stone context.\n     */\n    private context: Stone,\n\n    /**\n     * logger extension.\n     */\n    readonly logger: Logger,\n\n    /**\n     * graphql pubsub. allows to emit events to clients.\n     */\n    private pubSubSlot: PubSubSlot\n  ) {}\n\n  get pubsub(): PubSubEngine {\n    const pubSubSlots = this.pubSubSlot.values();\n    if (pubSubSlots.length) return pubSubSlots[0];\n    return new PubSub();\n  }\n\n  private modules = new Map<string, GraphQLModule>();\n\n  async createServer(options: GraphQLServerOptions) {\n    const { graphiql = true } = options;\n    const schema = this.createRootModule(options.schemaSlot).schema;\n    const app: Express = options.app || express();\n\n    app.use(\n      cors({\n        origin(_origin, callback) {\n          callback(null, true);\n        },\n        credentials: true,\n      })\n    );\n\n    app.use(\n      '/graphql',\n      // @ts-ignore\n      graphqlHTTP((request, _res, params) => {\n        return {\n          schema,\n          graphiql,\n          rootValue: request,\n          customFormatErrorFn: (err) => {\n            this.logger.error('graphql got an error during running the following query:', params);\n            this.logger.error('graphql error ', err);\n            return Object.assign(err, {\n              ERR_CODE:\n                // @ts-ignore\n                err?.originalError?.errors?.[0].ERR_CODE || err.originalError?.constructor?.name,\n              // @ts-ignore\n              HTTP_CODE: err?.originalError?.errors?.[0].HTTP_CODE || err.originalError?.code,\n            });\n          },\n        };\n      })\n    );\n\n    return createServer(app);\n  }\n\n  /**\n   * register a pubsub client\n   */\n  registerPubSub(pubsub: PubSubEngine) {\n    const pubSubSlots = this.pubSubSlot.toArray();\n    if (pubSubSlots.length) throw new Error('can not register more then one pubsub provider');\n    this.pubSubSlot.register(pubsub);\n    return this;\n  }\n\n  /**\n   * register a new graphql module.\n   */\n  register(schema: Schema) {\n    this.moduleSlot.register(schema);\n    return this;\n  }\n\n  private createRootModule(schemaSlot?: SchemaSlot) {\n    const modules = this.buildModules(schemaSlot);\n    return new GraphQLModule({\n      imports: modules,\n    });\n  }\n\n  private buildModules(schemaSlot: SchemaSlot = this.moduleSlot) {\n    const schemaSlots = schemaSlot.toArray();\n    return schemaSlots.map(([extensionId, schema]) => {\n      const moduleDeps = this.getModuleDependencies(extensionId);\n\n      const module = new GraphQLModule({\n        typeDefs: schema.typeDefs,\n        resolvers: schema.resolvers,\n        schemaDirectives: schema.schemaDirectives,\n        imports: moduleDeps,\n        context: (session) => {\n          return {\n            ...session,\n            verb: session?.headers?.['x-verb'] || Verb.READ,\n          };\n        },\n      });\n\n      this.modules.set(extensionId, module);\n\n      return module;\n    });\n  }\n\n  private getModuleDependencies(extensionId: string): GraphQLModule[] {\n    const extension = this.context.extensions.get(extensionId);\n    if (!extension) throw new Error(`aspect ${extensionId} was not found`);\n    const deps = this.context.getDependencies(extension);\n    const ids = deps.map((dep) => dep.id);\n\n    return Array.from(this.modules.entries())\n      .map(([depId, module]) => {\n        const dep = ids.includes(depId);\n        if (!dep) return undefined;\n        return module;\n      })\n      .filter((module) => !!module);\n  }\n\n  static slots = [Slot.withType<Schema>(), Slot.withType<PubSubSlot>()];\n\n  static defaultConfig = {\n    port: 4000,\n  };\n\n  static runtime = MainRuntime;\n\n  static dependencies = [LoggerAspect];\n\n  static async provider(\n    [loggerFactory]: [LoggerMain],\n    config: GraphQLConfig,\n    [moduleSlot, pubSubSlot]: [SchemaSlot, PubSubSlot],\n    context: Stone\n  ) {\n    const logger = loggerFactory.createLogger(GraphqlAspect.id);\n    const graphqlMain = new GraphqlMain(config, moduleSlot, context, logger, pubSubSlot);\n    return graphqlMain;\n  }\n}\n\nGraphqlAspect.addRuntime(GraphqlMain);\n"
  },
  {
    "path": "packages/core/src/graphql/index.ts",
    "content": "import { GraphqlAspect } from './graphql.aspect';\n\nexport default GraphqlAspect;\nexport { GraphqlAspect };\nexport type { Schema } from './schema';\nexport type { GraphqlMain } from './graphql.main.runtime';\n"
  },
  {
    "path": "packages/core/src/graphql/schema.ts",
    "content": "import type { DocumentNode } from 'graphql';\nimport type { SchemaDirectives } from '@graphql-modules/core';\n\n/**\n * graphql schema for an extension.\n */\nexport type Schema = {\n  typeDefs?: string | DocumentNode;\n  resolvers?: { [key: string]: any };\n  schemaDirectives?: SchemaDirectives;\n};\n"
  },
  {
    "path": "packages/core/src/index.ts",
    "content": "// don't write any content here\n// we create this file to make require.resolve() can find path of this package\n"
  },
  {
    "path": "packages/core/src/logger/index.ts",
    "content": "import { LoggerAspect } from './logger.aspect';\n\nexport default LoggerAspect;\nexport { LoggerAspect };\nexport { Logger } from './logger';\nexport { LongProcessLogger } from './longProcessLogger';\nexport type { LoggerMain } from './logger.main.runtime';\n"
  },
  {
    "path": "packages/core/src/logger/logger.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const LoggerAspect = Aspect.create({\n  id: 'arco.core/logger',\n});\n\nexport default LoggerAspect;\n"
  },
  {
    "path": "packages/core/src/logger/logger.main.runtime.ts",
    "content": "import { MainRuntime } from '@core/cli/cli.aspect';\n\nimport { LoggerAspect } from './logger.aspect';\n\nimport { Logger } from './logger';\n\nexport class LoggerMain {\n  static runtime = MainRuntime;\n\n  static dependencies = [];\n\n  static provider() {\n    return new LoggerMain();\n  }\n\n  constructor() {}\n\n  createLogger(extensionName: string): Logger {\n    return new Logger(extensionName);\n  }\n}\n\nLoggerAspect.addRuntime(LoggerMain);\n"
  },
  {
    "path": "packages/core/src/logger/logger.ts",
    "content": "import chalk from 'chalk';\nimport loader from '@arco-cli/legacy/dist/cli/loader';\nimport logger, { IArcoLogger } from '@arco-cli/legacy/dist/logger';\n\nimport { LongProcessLogger } from './longProcessLogger';\n\nexport class Logger implements IArcoLogger {\n  constructor(private extensionName: string) {}\n\n  get isLoaderStarted() {\n    return loader.isStarted;\n  }\n\n  trace(message: string, ...meta: any[]) {\n    logger.trace(this.colorMessage(message), ...meta);\n  }\n\n  debug(message: string, ...meta: any[]) {\n    logger.debug(this.colorMessage(message), ...meta);\n  }\n\n  info(message: string, ...meta: any[]) {\n    logger.info(this.colorMessage(message), ...meta);\n  }\n\n  warn(message: string, ...meta: any[]) {\n    logger.warn(this.colorMessage(message), ...meta);\n  }\n\n  error(message: string, ...meta: any[]) {\n    logger.error(this.colorMessage(message), ...meta);\n  }\n\n  fatal(message: string, ...meta: any[]) {\n    logger.fatal(this.colorMessage(message), ...meta);\n  }\n\n  createLongProcessLogger(processDescription: string, totalItems?: number): LongProcessLogger {\n    return new LongProcessLogger(this, this.extensionName, processDescription, totalItems);\n  }\n\n  /**\n   * single status-line on bottom of the screen.\n   * the text is replaced every time this method is called.\n   */\n  setStatusLine(text: string) {\n    loader.setTextAndRestart(text);\n  }\n\n  /**\n   * remove the text from the last line on the screen.\n   */\n  clearStatusLine() {\n    loader.stop();\n  }\n\n  clearConsole() {\n    logger.clearConsole();\n  }\n\n  /**\n   * print to the screen. if message is empty, print the last logged message.\n   */\n  console(message?: string, ...meta: any[]) {\n    if (message) this.info(message, meta);\n    if (!loader.isStarted && logger.shouldWriteToConsole) {\n      console.log(message, ...meta);\n    } else {\n      loader.stopAndPersist({ text: message });\n    }\n  }\n\n  consoleWarn(message?: string, ...meta: any[]) {\n    if (message) this.warn(message, ...meta);\n    if (!loader.isStarted && logger.shouldWriteToConsole) {\n      console.warn(message, ...meta);\n    } else {\n      loader.stopAndPersist({ text: message });\n    }\n  }\n\n  consoleError(message?: string, ...meta: any[]) {\n    if (message) this.error(message, ...meta);\n    if (!loader.isStarted && logger.shouldWriteToConsole) {\n      console.error(message, ...meta);\n    } else {\n      loader.stopAndPersist({ text: message });\n    }\n  }\n\n  /**\n   * print to the screen as a title, with bold text.\n   */\n  consoleTitle(message: string) {\n    this.info(message);\n    loader.stopAndPersist({ text: chalk.bold(message) });\n  }\n\n  /**\n   * print to the screen with a green `✔` prefix. if message is empty, print the last logged message.\n   */\n  consoleSuccess(message?: string) {\n    if (message) this.info(message);\n    loader.succeed(message);\n  }\n\n  /**\n   * turn off the logger.\n   */\n  off() {\n    return loader.off();\n  }\n\n  on() {\n    return loader.on();\n  }\n\n  profile(id: string, console?: boolean) {\n    logger.profile(id, console);\n  }\n\n  /**\n   * print to the screen with a red `✖` prefix. if message is empty, print the last logged message.\n   */\n  consoleFailure(message?: string) {\n    if (message) this.error(message);\n    loader.fail(message);\n  }\n\n  /**\n   * print to the screen with a red `⚠` prefix. if message is empty, print the last logged message.\n   */\n  consoleWarning(message?: string) {\n    if (message) {\n      this.warn(message);\n      message = chalk.yellow(message);\n    }\n    loader.warn(message);\n  }\n\n  private colorMessage(message: string) {\n    if (logger.isJsonFormat) return `${this.extensionName}, ${message}`;\n    return `${chalk.bold(this.extensionName)}, ${message}`;\n  }\n}\n"
  },
  {
    "path": "packages/core/src/logger/longProcessLogger.ts",
    "content": "import prettyTime from 'pretty-time';\nimport type { Logger } from './logger';\n\n/**\n * use it for a long-running process. upon creation, it logs the `processDescription`.\n * if the process involves iteration over a list of items, such as running tag on a list of\n * components, then pass the `totalItems` as the total components in the list.\n * later, during the iteration, call `logProgress(componentName)`.\n * once done, call `end()`.\n * the status-line will show all messages in the terminal.\n * see README for more data.\n */\nexport class LongProcessLogger {\n  constructor(\n    private logPublisher: Logger,\n    private extensionName: string,\n    private processDescription: string,\n    private totalItems?: number,\n    private currentItem = 0,\n    private startTime = process.hrtime()\n  ) {\n    this.start();\n  }\n\n  logProgress(itemName = '') {\n    this.currentItem += 1;\n    const message = `${this.processDescription} (${this.currentItem}/${this.totalItems}). ${itemName}`;\n    this.logPublisher.debug(message);\n    this.logPublisher.setStatusLine(`${this.extensionName}, ${message}`);\n  }\n\n  end() {\n    const duration = process.hrtime(this.startTime);\n    const message = `${this.processDescription} (completed in ${prettyTime(duration)})`;\n    this.logAndConsole(message);\n  }\n\n  private start() {\n    const totalItemsStr = this.totalItems ? `(total: ${this.totalItems})` : '';\n    const message = `${this.processDescription} ${totalItemsStr}`;\n    this.logAndConsole(message);\n  }\n\n  private logAndConsole(message: string) {\n    this.logPublisher.info(message);\n    this.logPublisher.setStatusLine(`${this.extensionName}, ${message}`);\n  }\n}\n"
  },
  {
    "path": "packages/core/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"dist\",\n    \"paths\": {\n      \"@core/*\": [\"src/*\"],\n      \"@arco-cli/stone\": [\"../stone/src\"],\n      \"@arco-cli/legacy/dist/*\": [\"../legacy/src/*\"],\n      \"@arco-cli/core/dist/*\": [\"../core/src/*\"],\n      \"@arco-cli/aspect/dist/*\": [\"../aspect/src/*\"],\n      \"@arco-cli/service/dist*\": [\"../service/src/*\"],\n      \"@arco-cli/ui-foundation-react\": [\"../ui-foundation-react/src\"],\n      \"@arco-cli/ui-foundation-react/dist/*\": [\"../ui-foundation-react/src/*\"]\n    }\n  }\n}\n"
  },
  {
    "path": "packages/generator/.gitignore",
    "content": "/example\n"
  },
  {
    "path": "packages/generator/bin/arco-generate",
    "content": "#!/usr/bin/env node\nrequire('../dist/app');\n"
  },
  {
    "path": "packages/generator/package.json",
    "content": "{\n  \"name\": \"@arco-cli/generator\",\n  \"version\": \"2.1.0\",\n  \"main\": \"./dist/index.js\",\n  \"bin\": {\n    \"arco-generate\": \"./bin/arco-generate\"\n  },\n  \"scripts\": {\n    \"dev\": \"sh ../../.scripts/build.sh dev no-source-maps\",\n    \"build\": \"sh ../../.scripts/build.sh no-source-maps\",\n    \"build-type\": \"sh ../../.scripts/build-type.sh\",\n    \"clean\": \"rm -rf dist\",\n    \"clean-type\": \"find dist -name *.d.ts |xargs rm -rf\",\n    \"prepublishOnly\": \"npm run build\"\n  },\n  \"dependencies\": {\n    \"@babel/runtime\": \"^7.20.6\",\n    \"axios\": \"^1.5.0\",\n    \"chalk\": \"^4.1.2\",\n    \"compressing\": \"^1.10.0\",\n    \"fs-extra\": \"^10.1.0\",\n    \"gulp\": \"^4.0.2\",\n    \"gulp-if\": \"^3.0.0\",\n    \"gulp-ignore\": \"^3.0.0\",\n    \"gulp-rename\": \"^2.0.0\",\n    \"gulp-replace\": \"^1.1.3\",\n    \"ora\": \"^5.4.1\",\n    \"through2\": \"^4.0.2\",\n    \"wget-improved\": \"^3.4.0\",\n    \"yargs\": \"^17.6.2\"\n  },\n  \"devDependencies\": {\n    \"@types/yargs\": \"^17.0.13\"\n  },\n  \"files\": [\n    \"bin\",\n    \"dist\"\n  ],\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "packages/generator/src/app.ts",
    "content": "/* eslint-disable no-console */\nimport path from 'path';\nimport chalk from 'chalk';\nimport yargs from 'yargs';\nimport fs from 'fs-extra';\nimport ora from 'ora';\n\nimport { Forker } from './forker';\nimport { Generator } from './generator';\nimport isInGitRepository from './utils/isInGitRepository';\nimport execQuick from './utils/execQuick';\nimport { installDependencies } from './utils/installDependencies';\n\nasync function newCommandHandler({\n  name: workspaceName,\n  path: parentDirPath = './',\n  packageName,\n  packageVersion,\n  description,\n  force,\n  template = 'react-workspace',\n  templateArgs = '',\n}: {\n  name: string;\n  path?: string;\n  template?: string;\n  templateArgs?: string;\n  packageName?: string;\n  packageVersion?: string;\n  description?: string;\n  force?: boolean;\n}) {\n  const generator = new Generator(workspaceName, {\n    path: parentDirPath,\n    packageName,\n    description,\n    version: packageVersion,\n    template,\n    templateArgs,\n  });\n  const workspacePath = generator.getTargetPath();\n\n  if (fs.existsSync(workspacePath)) {\n    if (force) {\n      fs.removeSync(workspacePath);\n    } else {\n      console.log(\n        chalk.red(\n          `Already a workspace exist at ${workspacePath}, use the ${chalk.yellow(\n            '--force'\n          )} flag to overwrite it`\n        )\n      );\n      return;\n    }\n  }\n\n  const spinner = ora();\n\n  spinner.start('copying workspace files...');\n  await generator.generate();\n  spinner.succeed('workspace files has been successfully copied');\n\n  // change cwd to workspace directory\n  process.chdir(path.resolve(workspacePath));\n\n  if (!(await isInGitRepository())) {\n    try {\n      spinner.start('initializing the Git repository');\n      const { stderr, code } = await execQuick('git init');\n      if (code !== 0) {\n        spinner.warn(\n          `[WARNING] failed to initialize git repository${stderr ? `, details:\\n${stderr}` : ''}`\n        );\n      } else {\n        spinner.succeed('Git repository has been successfully initialized');\n      }\n    } catch (err) {}\n  }\n\n  try {\n    spinner.start('installing workspace npm dependencies, this may take a few minutes...');\n    const { stderr, code, command } = await installDependencies();\n    if (code !== 0) {\n      spinner.warn(\n        `[WARNING] failed to install workspace dependencies via command [${command}]${\n          stderr ? `, details:\\n${stderr}` : ''\n        }`\n      );\n    } else {\n      spinner.succeed('workspace dependencies has been successfully installed');\n    }\n  } catch (err) {}\n\n  const userGuideTips = chalk.white(\n    `${chalk.green(`\nCongrats! A new workspace has been created successfully at '${workspacePath}'`)}\n\nInside the directory '${workspaceName}' you can run various commands including:\n\n   ${chalk.yellow('npx arco create ComponentName')}\n     Create your first component\n\n   ${chalk.yellow('npx arco start')}\n     Starts the workspace in development mode\n\n   ${chalk.yellow('npx arco help')}\n     Shows all available commands\n   `\n  );\n\n  console.log(userGuideTips);\n}\n\nasync function forkCommandHandler({\n  id,\n  path: targetPath,\n  host,\n  force,\n}: {\n  id: string;\n  path?: string;\n  host?: string;\n  force?: boolean;\n}) {\n  if (!id) {\n    console.log(chalk.red('Argument component-id is necessary'));\n    process.exit(1);\n  }\n\n  if (fs.existsSync(targetPath)) {\n    const targetDirFiles = (await fs.readdir(targetPath)).filter((file) => file !== '.DS_Store');\n    if (targetDirFiles.length && !force) {\n      console.log(\n        chalk.yellow(\n          `The target directory is not empty. If you want to overwrite files with the same name, please use '--force' option.\\n`\n        )\n      );\n    }\n  }\n\n  const forker = new Forker(id, targetPath, host, force);\n  const { ok, componentConfig } = await forker.fork();\n\n  if (ok) {\n    let userGuideTip = chalk.green(`\nCongrats! ${chalk.green(\n      `The component ${id} has been forked to ${targetPath}`\n    )}. You can use it now.\n`);\n\n    if (componentConfig?.entries?.main) {\n      userGuideTip += chalk.white(`\nImport it from ${path.resolve(targetPath, componentConfig.entries.main)}.\n`);\n    }\n\n    console.log(userGuideTip);\n  } else {\n    console.log(\n      chalk.red(`\nForking component ${id} failed, process exited.\n`)\n    );\n  }\n}\n\n// eslint-disable-next-line no-unused-expressions\nyargs\n  .scriptName('arco-generate')\n  .command(\n    'new <name>',\n    'create an empty arco material workspace',\n    (yargs) => {\n      return yargs\n        .positional('name', {\n          type: 'string',\n          describe: 'Workspace directory name',\n        })\n        .option('path', {\n          alias: 'p',\n          type: 'string',\n          describe: 'Path to new workspace (default to current dir)',\n        })\n        .option('package-name', {\n          type: 'string',\n          describe: 'Package name of workspace root NPM package',\n        })\n        .option('package-version', {\n          type: 'string',\n          describe: 'Package version of workspace root NPM package',\n        })\n        .option('description', {\n          type: 'string',\n          describe: 'Package description of workspace root NPM package',\n        })\n        .option('force', {\n          type: 'boolean',\n          describe: 'Force overwrite directory, if it already exists',\n        })\n        .option('template', {\n          type: 'string',\n          describe: 'The template to generating a new workspace',\n        })\n        .option('templateArgs', {\n          type: 'string',\n          describe: 'The arguments for template to generating a new workspace',\n        });\n    },\n    // eslint-disable-next-line no-return-await\n    async (options) => await newCommandHandler(options)\n  )\n  .command(\n    'fork <id>',\n    'fork a component from remote via component-id',\n    (yargs) => {\n      return yargs\n        .positional('id', {\n          type: 'string',\n          describe: 'Component id',\n        })\n        .option('path', {\n          alias: 'p',\n          type: 'string',\n          describe: 'Path to download component',\n        })\n        .option('host', {\n          type: 'string',\n          describe: 'Hostname of Arco material market',\n        })\n        .option('force', {\n          type: 'boolean',\n          describe:\n            'Force overwrite directories/files with same name, if target directory is not empty',\n        });\n    },\n    // eslint-disable-next-line no-return-await\n    async (options) => await forkCommandHandler(options)\n  )\n  .help().argv;\n"
  },
  {
    "path": "packages/generator/src/forker.ts",
    "content": "import path, { resolve } from 'path';\nimport axios from 'axios';\nimport fs from 'fs-extra';\nimport compressing from 'compressing';\nimport ora from 'ora';\nimport chalk from 'chalk';\n\nimport { wgetAsync } from './utils/wgetAsync';\nimport { toFsCompatible } from './utils/toFsCompatible';\n\nconst SOURCE_DIR_NAME = 'source';\nconst CONFIG_FILENAME_SUFFIX = '-config.json';\n\nexport class Forker {\n  private readonly tempDir = resolve(__dirname, '.temp');\n\n  private readonly spinner = ora();\n\n  constructor(\n    private readonly componentId: string,\n    private readonly path: string,\n    private readonly host: string = 'arco.design',\n    private readonly overwrite = false\n  ) {\n    fs.ensureDirSync(this.tempDir);\n  }\n\n  private async cleanTempDir() {\n    if (fs.existsSync(this.tempDir)) {\n      await fs.emptyDir(this.tempDir);\n    }\n  }\n\n  async getMaterialZipURL(\n    componentId: string = this.componentId\n  ): Promise<{ ok: boolean; forkable?: boolean; url?: string }> {\n    if (componentId) {\n      try {\n        const {\n          data: { ok, result },\n        } = await axios.post(`https://${this.host}/material/api/material`, {\n          name: componentId,\n          needPackageInfo: false,\n        });\n\n        if (ok && result.length) {\n          const [targetMaterial] = result;\n          return {\n            ok: true,\n            forkable: !!targetMaterial?.forkable,\n            url: targetMaterial?.fileManifest?.cdn?.zip || '',\n          };\n        }\n      } catch (e) {}\n    }\n\n    return { ok: false };\n  }\n\n  private async downloadAndUnzipFiles(zipURL: string): Promise<{\n    ok: boolean;\n    msg?: string;\n    path?: string;\n    config?: Record<string, any> & { forkable?: boolean | { sources: string[] } };\n  }> {\n    const componentDirName = toFsCompatible(this.componentId);\n    const unzipDirPath = resolve(this.tempDir, componentDirName);\n    const zipPath = resolve(this.tempDir, `${componentDirName}.zip`);\n\n    try {\n      // download component zip files\n      await wgetAsync(zipURL, zipPath);\n      // unzip files\n      await compressing.zip.uncompress(zipPath, unzipDirPath);\n\n      const componentSourceDir = resolve(unzipDirPath, SOURCE_DIR_NAME);\n      const componentForkConfigFilePath = resolve(\n        componentSourceDir,\n        `${toFsCompatible(this.componentId)}${CONFIG_FILENAME_SUFFIX}`\n      );\n\n      if (fs.existsSync(componentSourceDir) && fs.existsSync(componentForkConfigFilePath)) {\n        const config = await fs.readJson(componentForkConfigFilePath);\n        const componentConfig = config['arco.aspect/workspace']?.component;\n        return { ok: true, path: componentSourceDir, config: componentConfig };\n      }\n\n      return {\n        ok: false,\n        msg: `component source code directory not found, ${componentSourceDir} does not exist`,\n      };\n    } catch (err) {\n      return {\n        ok: false,\n        msg: err.toString(),\n      };\n    }\n  }\n\n  async fork(): Promise<{ ok: boolean; componentConfig?: Record<string, any> }> {\n    this.spinner.start(`fetching component info of ${this.componentId}...`);\n\n    let succeed = false;\n    let componentConfig: Record<string, any> = null;\n\n    const { ok: materialInfoGot, forkable, url: zipURL } = await this.getMaterialZipURL();\n\n    if (forkable && zipURL) {\n      this.spinner.start('downloading component files...');\n      const { ok, msg, config, path: sourceDir } = await this.downloadAndUnzipFiles(zipURL);\n      componentConfig = config;\n\n      if (ok) {\n        this.spinner.start('coping component files to target path...');\n\n        const pathsToCopy: string[] = [];\n        if (typeof config.forkable === 'object' && Array.isArray(config?.forkable?.sources)) {\n          pathsToCopy.push(\n            ...config.forkable.sources.map((sourcePath) => resolve(sourceDir, sourcePath))\n          );\n        }\n\n        if (pathsToCopy.length <= 1) {\n          const dirToFlat = pathsToCopy.pop() || sourceDir;\n          const currentDirName = path.basename(dirToFlat);\n          (await fs.readdir(dirToFlat, { withFileTypes: true })).forEach((child) => {\n            if (!child.name.endsWith(CONFIG_FILENAME_SUFFIX)) {\n              pathsToCopy.push(resolve(sourceDir, currentDirName, child.name));\n            }\n          });\n        }\n\n        try {\n          // copy all source files to target dir\n          await fs.ensureDir(this.path);\n          await Promise.all(\n            pathsToCopy.map(async (pathToCopy) => {\n              await fs.copy(pathToCopy, resolve(this.path, path.basename(pathToCopy)), {\n                overwrite: this.overwrite,\n              });\n            })\n          );\n          succeed = true;\n        } catch (err) {\n          this.spinner.fail(`failed to copy component source files to ${this.path}`);\n          console.error(chalk.red(err.toString()));\n        }\n      } else {\n        this.spinner.fail(`failed to download component source files from ${zipURL}`);\n        console.error(chalk.red(msg));\n      }\n    } else {\n      this.spinner.fail(\n        `this component cannot be forked, ${\n          materialInfoGot\n            ? forkable\n              ? 'URL of its source files are not found, please contact the material author'\n              : 'it not a forkable component, please contact the material author'\n            : `failed to get material info of ${this.componentId}`\n        }`\n      );\n    }\n\n    // clear temp download files\n    await this.cleanTempDir();\n\n    if (succeed) {\n      this.spinner.succeed(`component ${this.componentId} has been forked`);\n    }\n\n    return { ok: succeed, componentConfig };\n  }\n}\n"
  },
  {
    "path": "packages/generator/src/generator.ts",
    "content": "/* eslint-disable @typescript-eslint/no-var-requires */\nimport path from 'path';\nimport fs from 'fs-extra';\nimport gulp from 'gulp';\nimport gulpIgnore from 'gulp-ignore';\nimport gulpRename from 'gulp-rename';\nimport through2 from 'through2';\nimport yargs from 'yargs';\n\nimport {\n  GenerateOptions,\n  ComponentExports,\n  GeneratorContext,\n  TemplateDirectoryDescriptionFunction,\n  TemplateFunction,\n  TemplateManifest,\n} from './types';\n\nconst DEFAULT_TEMPLATE_NAME = 'react-component';\nconst FILENAME_TEMPLATE_DESCRIPTION = '__arco.tpl.desc.json';\nconst FILENAME_TEMPLATE_DIRECTORY_DESCRIPTION = '__arco.dir.desc.js';\n\ntype GulpFile = { path: string; contents: Buffer };\n\nexport class Generator {\n  static parseLocalTemplatePath(template: string): null | { prefix: string; path: string } {\n    const match = (template || '').match(/^(file:)(.+)/);\n    if (match) {\n      return {\n        prefix: match[1],\n        path: match[2],\n      };\n    }\n    return null;\n  }\n\n  private readonly CWD = process.cwd();\n\n  constructor(private name: string, private options: GenerateOptions = {}) {\n    this.options.path ||= this.CWD;\n    this.options.packageName ||= this.name;\n    this.options.template ||= DEFAULT_TEMPLATE_NAME;\n  }\n\n  private getTemplatePath() {\n    const template = this.options.template;\n    const localTemplate = Generator.parseLocalTemplatePath(template);\n    return localTemplate?.path || path.join(__dirname, 'templates', template);\n  }\n\n  getTargetPath() {\n    return path.join(this.options.path, this.name);\n  }\n\n  async generate(): Promise<null | {\n    path: string;\n    manifest: TemplateManifest;\n    exports: ComponentExports;\n  }> {\n    const CWD = this.CWD;\n    const targetPath = this.getTargetPath();\n    const templatePath = this.getTemplatePath();\n\n    let componentExports: ComponentExports = {\n      path: '',\n      modules: [],\n    };\n\n    try {\n      let templateManifest: TemplateManifest = {};\n      const ignorePathList: string[] = [];\n      const templateTransformResultMap: Record<string, { name: string; contents: string }> = {};\n\n      const readStream = () => {\n        if (!fs.existsSync(templatePath)) {\n          throw new Error(\n            `unable to find template from path '${templatePath}'\nplease check if this directory exists\nor did you forget to add prefix 'file:' for '--template' if you want to specify a local directory as template`\n          );\n        }\n\n        return gulp.src([`${templatePath}/**/*`], {\n          dot: true,\n          base: templatePath,\n        });\n      };\n\n      // handle files with template function and find files to ignore\n      await new Promise((resolve, reject) => {\n        readStream()\n          .pipe(\n            through2.obj((file: GulpFile, _, cb) => {\n              const ignoreFilePathTails = [\n                '.d.ts',\n                '.js.map',\n                FILENAME_TEMPLATE_DESCRIPTION,\n                FILENAME_TEMPLATE_DIRECTORY_DESCRIPTION,\n              ];\n\n              const context: GeneratorContext = {\n                name: this.name,\n                packageName: this.options.packageName,\n                version: this.options.version,\n                description: this.options.description,\n                path: templatePath,\n                templateArgs: yargs(this.options.templateArgs || '').argv,\n              };\n\n              // get manifest of template here\n              if (file.path.endsWith(FILENAME_TEMPLATE_DESCRIPTION)) {\n                try {\n                  templateManifest = fs.readJSONSync(file.path);\n                } catch (err) {}\n              }\n\n              // directories ignore\n              if (file.path.endsWith(FILENAME_TEMPLATE_DIRECTORY_DESCRIPTION)) {\n                try {\n                  const fnModule = require(file.path);\n                  const fn: TemplateDirectoryDescriptionFunction =\n                    typeof fnModule === 'function' ? fnModule : fnModule.default;\n                  const { ignore } = fn(context) || {};\n                  if (ignore) {\n                    ignorePathList.push(path.dirname(file.path));\n                  }\n                } catch (error) {\n                  console.error(`\\n${error}\\n`);\n                }\n              }\n\n              // files ignore\n              if (ignoreFilePathTails.find((tail) => file.path.endsWith(tail))) {\n                ignorePathList.push(file.path);\n              }\n\n              // handle file template\n              if (file.path.endsWith('.tpl.js')) {\n                try {\n                  const fnModule = require(file.path);\n                  const templateFn: TemplateFunction =\n                    typeof fnModule === 'function' ? fnModule : fnModule.default;\n                  if (typeof templateFn === 'function') {\n                    const template = templateFn(context);\n                    if (template === false) {\n                      ignorePathList.push(file.path);\n                    } else {\n                      templateTransformResultMap[file.path] = {\n                        name: template.filename,\n                        contents: template.contents,\n                      };\n\n                      const isComponentEntry =\n                        path.dirname(file.path) === templatePath &&\n                        /index\\.[jt]sx?/i.test(template.filename || '');\n                      if (isComponentEntry && template.exports) {\n                        componentExports = {\n                          path: path.resolve(\n                            CWD,\n                            targetPath,\n                            path.relative(templatePath, path.dirname(file.path))\n                          ),\n                          modules: template.exports,\n                        };\n                      }\n                    }\n                  }\n                } catch (error) {\n                  console.error(`\\n${error}\\n`);\n                }\n              }\n\n              cb(null, file);\n            })\n          )\n          // we need this noop callback to trigger end event\n          // https://github.com/gulpjs/gulp/issues/1637#issuecomment-216963506\n          .on('data', () => null)\n          .on('end', resolve)\n          .on('error', reject);\n      });\n\n      // copy all workspace files\n      await new Promise((resolve, reject) => {\n        readStream()\n          .pipe(\n            gulpIgnore.include((file: GulpFile) => {\n              return !ignorePathList.find((ignorePath) => file.path.startsWith(ignorePath));\n            })\n          )\n          .pipe(\n            through2.obj((file: GulpFile, _, cb) => {\n              if (templateTransformResultMap[file.path]) {\n                file.contents = Buffer.from(templateTransformResultMap[file.path].contents);\n              }\n              cb(null, file);\n            })\n          )\n          .pipe(\n            gulpRename((filePath: { dirname: string; basename: string; extname: string }, file) => {\n              if (templateTransformResultMap[file.path]) {\n                const newFilename = templateTransformResultMap[file.path].name;\n                return {\n                  dirname: filePath.dirname,\n                  basename: newFilename,\n                  extname: '',\n                };\n              }\n\n              return filePath;\n            })\n          )\n          .pipe(gulp.dest(targetPath))\n          .on('end', resolve)\n          .on('error', reject);\n      });\n\n      return {\n        path: targetPath,\n        manifest: templateManifest,\n        exports: componentExports,\n      };\n    } catch (err) {\n      throw new Error(\n        `failed to generate ${targetPath}, using template from ${templatePath}, details:\\n${err.toString()}`\n      );\n    }\n  }\n}\n"
  },
  {
    "path": "packages/generator/src/index.ts",
    "content": "export { Generator } from './generator';\nexport type { TemplateManifest, TemplateType, GenerateOptions } from './types';\n"
  },
  {
    "path": "packages/generator/src/templates/react-component/__arco.tpl.desc.json",
    "content": "{\n  \"name\": \"react-component\",\n  \"type\": \"component\",\n  \"entries\": {\n    \"main\": \"index.ts\",\n    \"style\": \"style/index.ts\",\n    \"preview\": \"__docs__/index.mdx\",\n    \"jsdoc\": [\"interface.ts\"]\n  }\n}\n"
  },
  {
    "path": "packages/generator/src/templates/react-component/__docs__/basic.tpl.tsx",
    "content": "import { TemplateFunction } from '../../../types';\n\nconst templateFn: TemplateFunction = function ({ name: componentName }) {\n  componentName = componentName.replace(/-(.)/g, (_, $1) => $1.toUpperCase());\n\n  return {\n    filename: 'basic.tsx',\n    contents: `import React from 'react';\nimport { ${componentName} } from '..';\n\nexport default function Basic() {\n  return <${componentName} />;\n}\n`,\n  };\n};\n\nexport default templateFn;\n"
  },
  {
    "path": "packages/generator/src/templates/react-component/__docs__/index.tpl.ts",
    "content": "import { TemplateFunction } from '../../../types';\n\nconst templateFn: TemplateFunction = function ({ name: componentName }) {\n  componentName = componentName.replace(/-(.)/g, (_, $1) => $1.toUpperCase());\n\n  return {\n    filename: 'index.mdx',\n    contents: `---\ntitle: ${componentName}\ndescription: Some description about this component.\nlabels: ['Keyword-1', 'Keyword-2']\n---\n\n# 基本用法\n\nimport Basic from './basic';\n\n<div data-arco-demo=\"Basic\">\n  <Basic />\n</div>\n`,\n  };\n};\n\nexport default templateFn;\n"
  },
  {
    "path": "packages/generator/src/templates/react-component/__test__/index.test.tpl.tsx",
    "content": "import { TemplateFunction } from '../../../types';\n\nconst templateFn: TemplateFunction = function ({ name: componentName }) {\n  componentName = componentName.replace(/-(.)/g, (_, $1) => $1.toUpperCase());\n\n  return {\n    filename: 'index.test.tsx',\n    contents: `/* eslint-disable import/no-extraneous-dependencies */\nimport React from 'react';\nimport { render } from '@testing-library/react';\nimport { ${componentName} } from '../index';\n\ndescribe('${componentName}', () => {\n  it('render current content', () => {\n    render(<${componentName} />);\n    expect(document.querySelector('div')).toHaveTextContent('Edit this component');\n  });\n});\n`,\n  };\n};\n\nexport default templateFn;\n"
  },
  {
    "path": "packages/generator/src/templates/react-component/component.tpl.tsx",
    "content": "import { TemplateFunction } from '../../types';\n\nconst templateFn: TemplateFunction = function ({ name: componentName }) {\n  componentName = componentName.replace(/-(.)/g, (_, $1) => $1.toUpperCase());\n\n  return {\n    filename: `${componentName}.tsx`,\n    contents: `import React from 'react';\nimport { ${componentName}Props } from './interface';\n\nexport function ${componentName}({ style }: ${componentName}Props) {\n  return <div style={style}>Edit this component</div>;\n}\n`,\n  };\n};\n\nexport default templateFn;\n"
  },
  {
    "path": "packages/generator/src/templates/react-component/index.tpl.tsx",
    "content": "import { TemplateFunction } from '../../types';\n\nconst templateFn: TemplateFunction = function ({ name: componentName }) {\n  componentName = componentName.replace(/-(.)/g, (_, $1) => $1.toUpperCase());\n\n  return {\n    filename: 'index.ts',\n    contents: `export { ${componentName} } from './${componentName}';\nexport type { ${componentName}Props } from './interface';\n`,\n    exports: [\n      {\n        name: componentName,\n      },\n      {\n        name: `${componentName}Props`,\n        type: true,\n      },\n    ],\n  };\n};\n\nexport default templateFn;\n"
  },
  {
    "path": "packages/generator/src/templates/react-component/interface.tpl.ts",
    "content": "import { TemplateFunction } from '../../types';\n\nconst templateFn: TemplateFunction = function ({ name: componentName }) {\n  componentName = componentName.replace(/-(.)/g, (_, $1) => $1.toUpperCase());\n\n  return {\n    filename: 'interface.ts',\n    contents: `import { CSSProperties } from 'react';\n\n/**\n * @title ${componentName}\n */\nexport interface ${componentName}Props {\n  style?: CSSProperties;\n  className?: string | string[];\n  /**\n   * @zh 组件尺寸\n   * @en Component Size\n   * @defaultValue default\n   * @version 1.1.0\n   */\n  size?: 'small' | 'default' | 'large';\n}\n`,\n  };\n};\n\nexport default templateFn;\n"
  },
  {
    "path": "packages/generator/src/templates/react-component/style/index.less",
    "content": ""
  },
  {
    "path": "packages/generator/src/templates/react-component/style/index.ts",
    "content": "import './index.less';\n"
  },
  {
    "path": "packages/generator/src/templates/react-package/__arco.tpl.desc.json",
    "content": "{\n  \"name\": \"react-package\",\n  \"type\": \"package\"\n}\n"
  },
  {
    "path": "packages/generator/src/templates/react-package/gitignore.tpl.ts",
    "content": "import { TemplateFunction } from '../../types';\n\nconst TemplateFn: TemplateFunction = function () {\n  return {\n    filename: '.gitignore',\n    contents: `# dist things\n/lib\n/es\n/artifacts\n`,\n  };\n};\n\nexport default TemplateFn;\n"
  },
  {
    "path": "packages/generator/src/templates/react-package/package.json.tpl.ts",
    "content": "import { GeneratorContext, TemplateFunction } from '../../types';\n\nconst templateFn: TemplateFunction = function ({\n  packageName = '',\n  version = '0.1.0',\n  description = '',\n}: GeneratorContext) {\n  const packageJson = {\n    name: packageName,\n    version,\n    description,\n    main: './lib/index.js',\n    module: './es/index.js',\n    types: './es/index.d.ts',\n    scripts: {\n      clean: 'rm -rf es lib artifacts',\n    },\n    peerDependencies: {\n      react: '>=16',\n      'react-dom': '^16.0.1',\n    },\n    dependencies: {},\n    sideEffects: ['{es,lib,src}/**/style/*', '*.less'],\n    files: ['es', 'lib'],\n    license: 'MIT',\n  };\n\n  return {\n    filename: 'package.json',\n    contents: JSON.stringify(packageJson, null, 2),\n  };\n};\n\nexport default templateFn;\n"
  },
  {
    "path": "packages/generator/src/templates/react-package/src/index.ts",
    "content": ""
  },
  {
    "path": "packages/generator/src/templates/react-package/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*.ts\", \"src/**/*.tsx\"]\n}\n"
  },
  {
    "path": "packages/generator/src/templates/react-workspace/.husky/pre-commit",
    "content": "#!/usr/bin/env sh\n. \"$(dirname -- \"$0\")/_/husky.sh\"\n\nnpm run eslint\nnpm run stylelint\n"
  },
  {
    "path": "packages/generator/src/templates/react-workspace/.scripts/workspaceHooks/afterComponentCreated.js",
    "content": "/* eslint-disable @typescript-eslint/no-var-requires */\nconst fs = require('fs');\nconst path = require('path');\n\nmodule.exports = function (componentInfo) {\n  const { path: pathComponentEntry, modules } = componentInfo || {};\n\n  let pathLibraryEntry = path.resolve(pathComponentEntry, '../index.ts');\n  if (!fs.existsSync(pathLibraryEntry)) {\n    pathLibraryEntry = path.resolve(pathLibraryEntry, '../index.tsx');\n  }\n\n  if (fs.existsSync(pathLibraryEntry) && fs.existsSync(pathComponentEntry)) {\n    const libraryEntryContent = fs.readFileSync(pathLibraryEntry).toString();\n    const exportExpressions = modules\n      .map(\n        ({ name, type }) =>\n          `export${type ? ' type' : ''} { ${name} } from '${path\n            .relative(path.dirname(pathLibraryEntry), pathComponentEntry)\n            .replace(/^[^.]/, (match) => `./${match}`)}';`\n      )\n      .join('\\n');\n\n    if (libraryEntryContent.indexOf(exportExpressions) === -1) {\n      fs.writeFileSync(pathLibraryEntry, `${libraryEntryContent}\\n${exportExpressions}\\n`);\n    }\n  }\n};\n"
  },
  {
    "path": "packages/generator/src/templates/react-workspace/__arco.tpl.desc.json",
    "content": "{\n  \"name\": \"react-workspace\",\n  \"type\": \"workspace\"\n}\n"
  },
  {
    "path": "packages/generator/src/templates/react-workspace/arco.env.config.js",
    "content": "/* eslint-disable @typescript-eslint/no-var-requires */\nconst fs = require('fs');\nconst path = require('path');\n\nmodule.exports = function defineConfig() {\n  const webpackConfigTransformer = (config) => {\n    const mdxLoader = config.raw.module.rules\n      .find((rule) => rule.oneOf)\n      ?.oneOf?.find((rule) => rule.test.test('.mdx'))\n      ?.use?.find(({ loader }) => loader.indexOf('/mdx/loader') > -1);\n    if (mdxLoader) {\n      mdxLoader.options.preProcessFile = ({ path: filePath, content }) => {\n        const componentStyleEntry = '../style/index.ts';\n        if (fs.existsSync(path.resolve(path.dirname(filePath), componentStyleEntry))) {\n          return `${content}\\n\\nimport '${componentStyleEntry}';`;\n        }\n        return content;\n      };\n    }\n\n    return config.merge({\n      resolve: {\n        alias: {\n          react: require.resolve('react'),\n        },\n      },\n    });\n  };\n\n  const config = {\n    jest: {\n      jestConfigPath: path.resolve(__dirname, './jest.config.js'),\n    },\n    webpack: {\n      previewConfig: [webpackConfigTransformer],\n      devServerConfig: [webpackConfigTransformer],\n    },\n    typescript: {\n      buildConfig: [\n        (config) => {\n          config.mergeTsConfig({});\n          return config;\n        },\n      ],\n    },\n    less: {\n      lessOptions: {},\n    },\n    sass: {\n      sassOptions: {},\n    },\n  };\n\n  return config;\n};\n"
  },
  {
    "path": "packages/generator/src/templates/react-workspace/arco.workspace.jsonc.tpl.ts",
    "content": "import { GeneratorContext, TemplateFunction } from '../../types';\n\nconst templateFn: TemplateFunction = ({ templateArgs }: GeneratorContext) => {\n  const isMonorepo = templateArgs?.monorepo;\n  const config = {\n    'arco.aspect/workspace': {\n      components: {\n        extends: {\n          rootDir: 'src',\n          entries: {\n            base: './',\n            main: 'index.ts',\n            style: 'style/index.ts',\n            preview: '__docs__/index.mdx',\n            jsdoc: ['interface.ts'],\n          },\n        },\n        members: [],\n      },\n    },\n    'arco.service/generator': {\n      ...(isMonorepo ? {} : { defaultPath: 'src' }),\n      hooks: {\n        afterComponentCreated: './.scripts/workspaceHooks/afterComponentCreated.js',\n      },\n    },\n  };\n\n  return {\n    filename: 'arco.workspace.jsonc',\n    contents: JSON.stringify(config, null, 2),\n  };\n};\n\nexport default templateFn;\n"
  },
  {
    "path": "packages/generator/src/templates/react-workspace/eslintignore.tpl.ts",
    "content": "import { TemplateFunction } from '../../types';\n\nconst TemplateFn: TemplateFunction = function () {\n  return {\n    filename: '.eslintignore',\n    contents: `**/node_modules/**\n*.json\nes\nlib\nartifacts\n`,\n  };\n};\n\nexport default TemplateFn;\n"
  },
  {
    "path": "packages/generator/src/templates/react-workspace/eslintrc.tpl.ts",
    "content": "import { TemplateFunction } from '../../types';\n\nconst TemplateFn: TemplateFunction = function () {\n  const config = {\n    extends: ['plugin:@typescript-eslint/recommended', 'airbnb', 'plugin:prettier/recommended'],\n    env: {\n      browser: true,\n      commonjs: true,\n      es6: true,\n    },\n    parser: '@typescript-eslint/parser',\n    parserOptions: {\n      sourceType: 'module',\n      ecmaFeatures: {\n        jsx: true,\n        experimentalObjectRestSpread: true,\n      },\n    },\n    globals: {\n      describe: 'readonly',\n      it: 'readonly',\n      expect: 'readonly',\n      jest: 'readonly',\n      $: 'readonly',\n      afterEach: 'readonly',\n      beforeEach: 'readonly',\n    },\n    rules: {\n      'class-methods-use-this': 0,\n      'func-names': 0,\n      'global-require': 0,\n      'guard-for-in': 0,\n      'import/no-dynamic-require': 0,\n      'import/no-mutable-exports': 0,\n      'import/no-unresolved': 0,\n      'import/extensions': 0,\n      'import/prefer-default-export': 0,\n      'jsx-a11y/click-events-have-key-events': 0,\n      'jsx-a11y/no-static-element-interactions': 0,\n      'jsx-a11y/no-noninteractive-element-interactions': 0,\n      'linebreak-style': [2, 'unix'],\n      'max-classes-per-file': 0,\n      'no-case-declarations': 0,\n      'no-continue': 0,\n      'no-empty': 0,\n      'no-empty-function': 0,\n      'no-nested-ternary': 0,\n      'no-plusplus': 0,\n      'no-param-reassign': 0,\n      'no-prototype-builtins': 0,\n      'no-restricted-syntax': 0,\n      'no-shadow': 0,\n      'no-underscore-dangle': 0,\n      'no-useless-constructor': 0,\n      'no-useless-escape': 0,\n      'no-use-before-define': 0,\n      'no-unused-vars': [2, { vars: 'all', args: 'none' }],\n      'no-unused-expressions': ['error', { allowShortCircuit: true, allowTernary: true }],\n      'one-var': 0,\n      'prefer-promise-reject-errors': 0,\n      'prefer-regex-literals': 0,\n      'prefer-destructuring': 0,\n      'prettier/prettier': [\n        2,\n        {\n          trailingComma: 'es5',\n          printWidth: 100,\n        },\n      ],\n      radix: 0,\n      'react/button-has-type': 0,\n      'react/destructuring-assignment': 0,\n      'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx', 'ts', 'tsx'] }],\n      'react/jsx-one-expression-per-line': 0,\n      'react/jsx-props-no-spreading': 0,\n      'react/no-array-index-key': 0,\n      'react/no-children-prop': 0,\n      'react/no-multi-comp': 0,\n      'react/prefer-stateless-function': 0,\n      'react/require-default-props': 0,\n      'react/sort-comp': 0,\n      strict: 0,\n      '@typescript-eslint/ban-ts-comment': 0,\n      '@typescript-eslint/explicit-function-return-type': 0,\n      '@typescript-eslint/explicit-module-boundary-types': 0,\n      '@typescript-eslint/no-empty-function': 0,\n      '@typescript-eslint/no-use-before-define': [\n        'error',\n        {\n          functions: false,\n          classes: false,\n        },\n      ],\n    },\n  };\n  return {\n    filename: '.eslintrc.json',\n    contents: JSON.stringify(config, null, 2),\n  };\n};\n\nexport default TemplateFn;\n"
  },
  {
    "path": "packages/generator/src/templates/react-workspace/gitignore.tpl.ts",
    "content": "import { TemplateFunction } from '../../types';\n\nconst TemplateFn: TemplateFunction = function () {\n  return {\n    filename: '.gitignore',\n    contents: `# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Runtime data\npids\n*.pid\n  \n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n.coverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (http://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\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/stylelint cache\n.eslintcache\n.stylelintcache\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\n# next.js build output\n.next\n\n# JetBrain IDE\n.idea\n\n**/.DS_Store\n\n# dist things\n/lib\n/es\n/artifacts\n`,\n  };\n};\n\nexport default TemplateFn;\n"
  },
  {
    "path": "packages/generator/src/templates/react-workspace/jest.config.js",
    "content": "/* eslint-disable @typescript-eslint/no-var-requires */\n// allow IDE to configure Jest config\nconst defaultConfig = require(require.resolve('@arco-cli/react/dist/jest/jest.cjs.config.js'));\n\nmodule.exports = {\n  ...defaultConfig,\n};\n"
  },
  {
    "path": "packages/generator/src/templates/react-workspace/package.json.tpl.ts",
    "content": "import { TemplateFunction } from '../../types';\n\nconst templateFn: TemplateFunction = function ({\n  name = '',\n  version = '0.1.0',\n  description = '',\n  templateArgs,\n}) {\n  const isMonorepo = templateArgs?.monorepo;\n  const sourceEntryDirGlob = `${isMonorepo ? 'packages/*/' : ''}src`;\n  const packageJson = {\n    name,\n    version,\n    description,\n    ...(isMonorepo\n      ? {}\n      : {\n          main: './lib/index.js',\n          module: './es/index.js',\n          types: './es/index.d.ts',\n        }),\n    scripts: {\n      prepare: 'husky install',\n      start: 'arco start',\n      build: 'arco build',\n      test: 'arco test',\n      sync: 'arco sync',\n      ...(isMonorepo\n        ? {}\n        : {\n            clean: 'rm -rf es lib artifacts',\n          }),\n      eslint: `eslint '${sourceEntryDirGlob}/**/*.{js,jsx,ts,tsx}' --fix --cache --quiet`,\n      stylelint: `stylelint '${sourceEntryDirGlob}/**/*.{css,less,scss}' --fix --cache`,\n      format: `prettier '${sourceEntryDirGlob}/**/*.{js,jsx,ts,tsx}' --config .prettierrc --write`,\n    },\n    peerDependencies: {\n      react: '>=16',\n      'react-dom': '>=16',\n    },\n    dependencies: {},\n    devDependencies: {\n      '@arco-cli/arco': '^2.0.0-beta.0',\n      '@babel/runtime': '^7.22.3',\n      '@testing-library/dom': '^8.19.1',\n      '@testing-library/jest-dom': '^5.16.5',\n      '@testing-library/react': '^12.1.5',\n      '@types/jest': '~29',\n      '@types/react': '~17',\n      '@types/react-dom': '~17',\n      '@typescript-eslint/eslint-plugin': '^5.42.0',\n      '@typescript-eslint/parser': '^5.42.0',\n      eslint: '^7.15.0',\n      'eslint-config-airbnb': '^19.0.4',\n      'eslint-config-prettier': '^8.5.0',\n      'eslint-plugin-babel': '^5.3.1',\n      'eslint-plugin-import': '^2.22.1',\n      'eslint-plugin-jsx-a11y': '^6.6.1',\n      'eslint-plugin-prettier': '^4.2.1',\n      'eslint-plugin-react': '^7.31.10',\n      'eslint-plugin-react-hooks': '^4.6.0',\n      husky: '^8.0.3',\n      jsdom: '^16.4.0',\n      'jsdom-global': '^3.0.2',\n      'lint-staged': '^13.1.1',\n      'postcss-less': '^6.0.0',\n      prettier: '^2.7.1',\n      react: '~17',\n      'react-dom': '~17',\n      stylelint: '^15.7.0',\n      'stylelint-config-css-modules': '^4.2.0',\n      'stylelint-config-standard': '^33.0.0',\n    },\n    ...(isMonorepo\n      ? {}\n      : {\n          sideEffects: ['{es,lib,src}/**/style/*', '*.less'],\n          files: ['es', 'lib'],\n        }),\n    license: 'MIT',\n  };\n\n  return {\n    filename: 'package.json',\n    contents: JSON.stringify(packageJson, null, 2),\n  };\n};\n\nexport default templateFn;\n"
  },
  {
    "path": "packages/generator/src/templates/react-workspace/packages/__arco.dir.desc.ts",
    "content": "import { TemplateDirectoryDescriptionFunction, GeneratorContext } from '../../../types';\n\nconst filter: TemplateDirectoryDescriptionFunction = (context: GeneratorContext) => {\n  return {\n    ignore: !context.templateArgs.monorepo,\n  };\n};\n\nexport default filter;\n"
  },
  {
    "path": "packages/generator/src/templates/react-workspace/prettierrc.tpl.ts",
    "content": "import { TemplateFunction } from '../../types';\n\nconst TemplateFn: TemplateFunction = function () {\n  const config = {\n    arrowParens: 'always',\n    jsxBracketSameLine: false,\n    jsxSingleQuote: false,\n    printWidth: 100,\n    semi: true,\n    singleQuote: true,\n    tabWidth: 2,\n    trailingComma: 'es5',\n    useTabs: false,\n  };\n  return {\n    filename: '.prettierrc',\n    contents: JSON.stringify(config, null, 2),\n  };\n};\n\nexport default TemplateFn;\n"
  },
  {
    "path": "packages/generator/src/templates/react-workspace/src/__arco.dir.desc.ts",
    "content": "import { TemplateDirectoryDescriptionFunction, GeneratorContext } from '../../../types';\n\nconst filter: TemplateDirectoryDescriptionFunction = (context: GeneratorContext) => {\n  return {\n    ignore: context.templateArgs.monorepo,\n  };\n};\n\nexport default filter;\n"
  },
  {
    "path": "packages/generator/src/templates/react-workspace/src/index.ts",
    "content": ""
  },
  {
    "path": "packages/generator/src/templates/react-workspace/stylelintignore.tpl.ts",
    "content": "import { TemplateFunction } from '../../types';\n\nconst TemplateFn: TemplateFunction = function () {\n  return {\n    filename: '.stylelintignore',\n    contents: ``,\n  };\n};\n\nexport default TemplateFn;\n"
  },
  {
    "path": "packages/generator/src/templates/react-workspace/stylelintrc.tpl.ts",
    "content": "import { TemplateFunction } from '../../types';\n\nconst TemplateFn: TemplateFunction = function () {\n  const config = {\n    extends: ['stylelint-config-standard', 'stylelint-config-css-modules'],\n    customSyntax: 'postcss-less',\n    rules: {\n      'block-opening-brace-space-before': 'always',\n      'declaration-block-no-duplicate-properties': null,\n      'declaration-block-trailing-semicolon': null,\n      'font-family-no-missing-generic-family-keyword': null,\n      'no-descending-specificity': null,\n      'no-duplicate-selectors': null,\n      'selector-anb-no-unmatchable': null,\n    },\n  };\n  return {\n    filename: '.stylelintrc',\n    contents: JSON.stringify(config, null, 2),\n  };\n};\n\nexport default TemplateFn;\n"
  },
  {
    "path": "packages/generator/src/templates/react-workspace/tsconfig.json.tpl.ts",
    "content": "import { GeneratorContext, TemplateFunction } from '../../types';\n\nconst templateFn: TemplateFunction = function ({ templateArgs }: GeneratorContext) {\n  const config = {\n    compilerOptions: {\n      allowSyntheticDefaultImports: true,\n      downlevelIteration: true,\n      esModuleInterop: true,\n      experimentalDecorators: true,\n      jsx: 'react',\n      lib: ['es5', 'dom'],\n      moduleResolution: 'node',\n      noUnusedLocals: true,\n      noUnusedParameters: true,\n      skipLibCheck: true,\n      target: 'es2015',\n      types: ['node', 'jest', '@testing-library/jest-dom'],\n    },\n    include: [`${templateArgs?.monorepo ? 'packages' : 'src'}/**/*.{ts,tsx}`],\n    exclude: ['node_modules'],\n  };\n  return {\n    filename: 'tsconfig.json',\n    contents: JSON.stringify(config, null, 2),\n  };\n};\n\nexport default templateFn;\n"
  },
  {
    "path": "packages/generator/src/types.ts",
    "content": "export type TemplateType = 'workspace' | 'component' | 'package';\n\nexport type GenerateOptions = {\n  path?: string;\n  packageName?: string;\n  version?: string;\n  description?: string;\n  template?: string;\n  templateArgs?: string;\n};\n\nexport type GeneratorContext = {\n  path: string;\n  name: string;\n  packageName: string;\n  templateArgs: Record<string, any>;\n  version: string;\n  description: string;\n};\n\nexport type ComponentExports = {\n  path: string;\n  modules: Array<{ name: string; type?: boolean }>;\n};\n\nexport type TemplateFunction = (\n  context: GeneratorContext\n) => false | { filename: string; contents: string; exports?: ComponentExports['modules'] };\n\nexport type TemplateDirectoryDescriptionFunction = (context: GeneratorContext) => {\n  ignore: boolean;\n};\n\nexport type TemplateManifest = {\n  type?: TemplateType;\n  // same with ComponentConfig.entries\n  entries?: {\n    main?: string;\n    style?: string;\n    preview?: string;\n    jsdoc?: string | string[];\n    extraDocs?: Array<{ title: string; entry: string }>;\n  };\n};\n"
  },
  {
    "path": "packages/generator/src/utils/execQuick.ts",
    "content": "/* eslint-disable no-console */\nimport chalk from 'chalk';\nimport { spawn } from 'child_process';\n\nfunction consoleInfo(text: string) {\n  console.log(chalk.white(text));\n}\n\nfunction consoleError(text: string) {\n  console.log(chalk.red(text));\n}\n\nexport default async function execQuick(\n  command: string,\n  options: {\n    cwd?: string;\n    time?: boolean;\n    silent?: boolean;\n  } = {}\n): Promise<{ pid: number; code: number; stdout: string; stderr: string }> {\n  return new Promise((resolve) => {\n    const silent = options.silent !== false;\n    const begin = new Date().getTime();\n    const result = {\n      pid: null,\n      code: null,\n      stdout: '',\n      stderr: '',\n    };\n\n    const { stdout, stderr, pid } = spawn(command, [], {\n      shell: true,\n      cwd: options.cwd,\n    }).on('close', (code) => {\n      if (options.time) {\n        const end = new Date().getTime();\n        const waste = ((end - begin) / 1000).toFixed(2);\n        consoleInfo(`execQuick: command [${command}] executed in ${waste} ms.`);\n      }\n\n      if (code !== 0 && !silent) {\n        consoleError(`execQuick: command [${command}] executed failed`);\n      }\n\n      result.code = code;\n      resolve(result);\n    });\n\n    result.pid = pid;\n\n    stdout.on('data', (data) => {\n      const dataStr = data.toString();\n      if (!silent) {\n        consoleInfo(dataStr);\n      }\n      result.stdout += dataStr;\n    });\n\n    stderr.on('data', (data) => {\n      const dataStr = data.toString();\n      if (!silent) {\n        consoleError(dataStr);\n      }\n      result.stderr += dataStr;\n    });\n  });\n}\n"
  },
  {
    "path": "packages/generator/src/utils/installDependencies.ts",
    "content": "import execQuick from './execQuick';\n\nexport async function installDependencies(workspacePath?: string) {\n  let command = 'npm';\n  let args = ['install'];\n\n  // try yarn\n  try {\n    const { stdout } = await execQuick('yarn -v');\n    if (stdout.match(/^\\d+\\.\\d+/)) {\n      command = 'yarn';\n      args = [];\n    }\n  } catch (e) {}\n\n  // try pnpm\n  // try {\n  //   const { stdout } = await execQuick('pnpm -v');\n  //   if (stdout.match(/^\\d+\\.\\d+/)) {\n  //     command = 'pnpm';\n  //     args = ['i'];\n  //   }\n  // } catch (e) {}\n\n  const commandExec = [command].concat(args).join(' ');\n  const { code, stderr } = await execQuick(commandExec, { cwd: workspacePath });\n\n  return { code, stderr, command: commandExec };\n}\n"
  },
  {
    "path": "packages/generator/src/utils/isGitStatusClean.ts",
    "content": "import execQuick from './execQuick';\n\nexport default async () => {\n  try {\n    const { stdout } = await execQuick('git status --short');\n    return stdout.toString() === '';\n  } catch (e) {\n    return true;\n  }\n};\n"
  },
  {
    "path": "packages/generator/src/utils/isInGitRepository.ts",
    "content": "import execQuick from './execQuick';\n\nexport default async () => {\n  const { code, stdout } = await execQuick('git rev-parse --is-inside-work-tree');\n  return code === 0 && /^true/i.test(stdout);\n};\n"
  },
  {
    "path": "packages/generator/src/utils/toFsCompatible.ts",
    "content": "export function toFsCompatible(str: string) {\n  return typeof str === 'string' ? str.replace(/[-\\/.]/g, '_') : str;\n}\n"
  },
  {
    "path": "packages/generator/src/utils/wgetAsync.ts",
    "content": "import wget from 'wget-improved';\n\n/**\n * Use wget to download files\n */\nexport async function wgetAsync(\n  src: string,\n  output: string,\n  options?: Record<string, any>\n): Promise<string> {\n  return new Promise((resolve, reject) => {\n    const download = wget.download(src, output, options);\n    download.on('error', function (err) {\n      reject(err);\n    });\n    download.on('end', function (output) {\n      resolve(output);\n    });\n  });\n}\n"
  },
  {
    "path": "packages/generator/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"],\n  \"compilerOptions\": {\n    \"outDir\": \"dist\",\n    \"baseUrl\": \".\",\n    \"declaration\": false\n  }\n}\n"
  },
  {
    "path": "packages/legacy/package.json",
    "content": "{\n  \"name\": \"@arco-cli/legacy\",\n  \"version\": \"2.3.2\",\n  \"homepage\": \"https://github.com/arco-design/arco-cli\",\n  \"repository\": \"https://github.com/arco-design/arco-cli\",\n  \"main\": \"./dist/index.js\",\n  \"scripts\": {\n    \"dev\": \"sh ../../.scripts/build.sh dev\",\n    \"build\": \"sh ../../.scripts/build.sh\",\n    \"build-type\": \"sh ../../.scripts/build-type.sh\",\n    \"clean\": \"rm -rf dist\",\n    \"clean-type\": \"find dist -name *.d.ts |xargs rm -rf\",\n    \"prepublishOnly\": \"npm run build\"\n  },\n  \"dependencies\": {\n    \"archiver\": \"^5.3.1\",\n    \"axios\": \"^1.5.0\",\n    \"bluebird\": \"^3.7.2\",\n    \"chalk\": \"^4.1.2\",\n    \"cli-spinners\": \"^2.7.0\",\n    \"connect\": \"^3.7.0\",\n    \"find-up\": \"^5.0.0\",\n    \"form-data\": \"^4.0.0\",\n    \"fs-extra\": \"^10.1.0\",\n    \"globby\": \"^11.1.0\",\n    \"ignore\": \"^5.2.1\",\n    \"isbinaryfile\": \"^5.0.0\",\n    \"lodash\": \"^4.17.21\",\n    \"node-fetch\": \"^2.6.7\",\n    \"node-source-walk\": \"^5.0.0\",\n    \"normalize-path\": \"^3.0.0\",\n    \"object-hash\": \"^3.0.0\",\n    \"open\": \"^8.4.0\",\n    \"ora\": \"^5.4.1\",\n    \"p-map\": \"^4.0.0\",\n    \"p-map-series\": \"^2.1.0\",\n    \"parse-gitignore\": \"^1.0.1\",\n    \"pino\": \"^8.7.0\",\n    \"pino-pretty\": \"^9.1.1\",\n    \"prompt\": \"^1.3.0\",\n    \"serialize-error\": \"^8.1.0\",\n    \"string-format\": \"^2.0.0\",\n    \"uniqid\": \"^5.4.0\",\n    \"vinyl\": \"^3.0.0\",\n    \"vinyl-file\": \"^3.0.0\",\n    \"yn\": \"^4.0.0\"\n  },\n  \"devDependencies\": {\n    \"@types/archiver\": \"^5.3.2\",\n    \"@types/prompt\": \"^1.1.4\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "packages/legacy/src/analytics/analytics.ts",
    "content": "import os from 'os';\nimport yn from 'yn';\nimport { isNil, isEmpty, filter } from 'lodash';\nimport uniqid from 'uniqid';\nimport hashObj from 'object-hash';\nimport { serializeError } from 'serialize-error';\n// import path from 'path';\n// import { fork } from 'child_process';\n\nimport { getCliVersion } from '../utils';\nimport { getSync, setSync } from '../globalConfig';\nimport { CLIArgs } from '../cli/command';\nimport {\n  CFG_ANALYTICS_ANONYMOUS_KEY,\n  CFG_ANALYTICS_ENVIRONMENT_KEY,\n  CFG_ANALYTICS_ERROR_REPORTS_KEY,\n  CFG_ANALYTICS_REPORTING_KEY,\n  CFG_ANALYTICS_USERID_KEY,\n  CFG_USER_EMAIL_KEY,\n  CFG_USER_NAME_KEY,\n  DEFAULT_ENV,\n} from '../constants';\nimport { analyticsPrompt, errorReportingPrompt } from '../prompts';\n\nconst LEVEL = {\n  DEBUG: 'debug',\n  INFO: 'info',\n  WARNING: 'warning',\n  ERROR: 'error',\n  FATAL: 'fatal',\n};\n\nclass Breadcrumb {\n  category: string;\n\n  message: string;\n\n  data: Record<string, any>;\n\n  constructor(category: string, message: string, data: Record<string, any>) {\n    this.category = category;\n    this.message = message;\n    this.data = data;\n  }\n}\n\n// TODO analytics data report\nclass Analytics {\n  static username: string;\n\n  static command: string;\n\n  static release: string;\n\n  static args: CLIArgs;\n\n  static flags: Record<string, any> = {};\n\n  static success = true;\n\n  static nodeVersion: string;\n\n  static os: string;\n\n  static extra: Record<string, any> | null | undefined = {};\n\n  static level: keyof typeof LEVEL;\n\n  static error: Error | string | Record<string, any>;\n\n  static breadcrumbs: Array<Breadcrumb> = [];\n\n  static analytics_usage: boolean;\n\n  static error_usage: boolean;\n\n  static anonymous: boolean;\n\n  static environment: string;\n\n  static getID(): string {\n    const id = getSync(CFG_ANALYTICS_USERID_KEY);\n    if (id) return id;\n    const newId = uniqid();\n    setSync({ [CFG_ANALYTICS_USERID_KEY]: newId });\n    return newId;\n  }\n\n  static promptAnalyticsIfNeeded(): Promise<void> {\n    const cmd = process.argv.slice(2);\n\n    function shouldPromptForAnalytics() {\n      // do not prompt analytics approval for arco config command (so you can configure it in CI envs)\n      if (cmd.length && cmd[0] !== 'config' && !process.env.CI) {\n        const analyticsReporting = getSync(CFG_ANALYTICS_REPORTING_KEY);\n        const errorReporting = getSync(CFG_ANALYTICS_ERROR_REPORTS_KEY);\n        return isNil(analyticsReporting) && isNil(errorReporting);\n      }\n      return false;\n    }\n\n    if (shouldPromptForAnalytics()) {\n      const uniqId = uniqid();\n      if (!getSync(CFG_ANALYTICS_USERID_KEY)) {\n        setSync({ CFG_ANALYTICS_USERID_KEY: uniqId });\n      }\n\n      // @ts-ignore\n      return analyticsPrompt().then(({ analyticsResponse }) => {\n        setSync({ [CFG_ANALYTICS_REPORTING_KEY]: yn(analyticsResponse) });\n\n        if (!yn(analyticsResponse)) {\n          return errorReportingPrompt().then(({ errResponse }) => {\n            return setSync({ [CFG_ANALYTICS_ERROR_REPORTS_KEY]: yn(errResponse) });\n          });\n        }\n        return null;\n      });\n    }\n\n    return Promise.resolve();\n  }\n\n  static _maskString(str: string): string {\n    return str.replace(/[A-Za-z]/g, 'x');\n  }\n\n  static _hashLightly(value: any) {\n    switch (typeof value) {\n      case 'undefined':\n      case 'number':\n      case 'boolean':\n        return value;\n      case 'string':\n        return this._maskString(value);\n      case 'object':\n        if (Array.isArray(value)) return value.map((item) => this._hashLightly(item));\n        if (value === null) return value;\n        return hashObj(value);\n      default:\n        return hashObj(value);\n    }\n  }\n\n  static _hashFlags(flags: Record<string, any>) {\n    const hashedFlags = {};\n    const definedFlags = filter(flags, (flag) => typeof flag !== 'undefined');\n    if (this.anonymous && !isEmpty(definedFlags)) {\n      Object.keys(definedFlags).forEach((key) => {\n        hashedFlags[key] = this._hashLightly(flags[key]);\n      });\n      return hashedFlags;\n    }\n    return definedFlags;\n  }\n\n  static _hashArgs(args: CLIArgs): CLIArgs {\n    if (!this.anonymous) return args;\n    return args.map((arg) => this._hashLightly(arg));\n  }\n\n  static init(command: string, flags: Record<string, any>, args: CLIArgs) {\n    this.anonymous = yn(getSync(CFG_ANALYTICS_ANONYMOUS_KEY), { default: true });\n    this.command = command;\n    this.flags = this._hashFlags(flags);\n    this.release = getCliVersion();\n    this.args = this._hashArgs(args);\n    this.nodeVersion = process.version;\n    this.os = process.platform;\n    (this.level as any) = LEVEL.INFO;\n    this.username = !this.anonymous\n      ? getSync(CFG_USER_EMAIL_KEY) || getSync(CFG_USER_NAME_KEY) || os.hostname() || this.getID()\n      : this.getID();\n    this.analytics_usage = yn(getSync(CFG_ANALYTICS_REPORTING_KEY), { default: false });\n    this.error_usage = this.analytics_usage\n      ? true\n      : yn(getSync(CFG_ANALYTICS_ERROR_REPORTS_KEY), { default: false });\n    this.environment = getSync(CFG_ANALYTICS_ENVIRONMENT_KEY) || DEFAULT_ENV;\n  }\n\n  static sendData(): Promise<void> {\n    // return new Promise((resolve, reject) => {\n    //   if (this.analytics_usage || (this.error_usage && !this.success)) {\n    //     const file = path.join(__dirname, 'analyticsSender.js');\n    //     // switch to `false` to debug the child\n    //     const forked = fork(file, { silent: true });\n    //     forked.send(this.toObject());\n    //     forked.on('message', () => {\n    //       // makes sure the data has been sent to the child.\n    //       // without it, when the message is large, it exits before the child got the complete message\n    //       resolve();\n    //     });\n    //     forked.on('error', (err) => {\n    //       reject(err);\n    //     });\n    //   } else {\n    //     resolve();\n    //   }\n    // });\n    return null;\n  }\n\n  static setError(level: string, err: Error): void {\n    (this.level as string) = level;\n    this.error = serializeError(err);\n    this.success = false;\n  }\n\n  /**\n   * eventually goes to the \"ADDITIONAL DATA\" section in Sentry\n   */\n  static setExtraData(key, value) {\n    this.extra[key] = value;\n  }\n\n  static incExtraDataKey(key, value) {\n    if (this.extra[key]) {\n      this.extra[key] += value || 1;\n    } else {\n      this.extra[key] = value || 1;\n    }\n  }\n\n  static hashData(data: any) {\n    if (this.anonymous) {\n      return hashObj(data);\n    }\n    return data;\n  }\n\n  static addBreadCrumb(category: string, message: string, data?: Record<string, any>) {\n    this.breadcrumbs.push(new Breadcrumb(category, message, data));\n  }\n\n  static toObject() {\n    return {\n      username: this.username,\n      command: this.command,\n      flags: this.flags,\n      args: this.args,\n      release: this.release,\n      extra: this.extra,\n      nodeVersion: this.nodeVersion,\n      os: this.os,\n      level: this.level,\n      error: this.error,\n      success: this.success,\n      breadcrumbs: this.breadcrumbs,\n      analytics_usage: this.analytics_usage,\n      error_usage: this.analytics_usage,\n      environment: this.environment,\n    };\n  }\n}\n\nexport { LEVEL, Analytics };\n"
  },
  {
    "path": "packages/legacy/src/analytics/analyticsSender.ts",
    "content": "import fetch from 'node-fetch';\nimport { getSync } from '../globalConfig';\nimport { CFG_ANALYTICS_DOMAIN_KEY, DEFAULT_ANALYTICS_DOMAIN } from '../constants';\n\nconst ANALYTICS_DOMAIN = getSync(CFG_ANALYTICS_DOMAIN_KEY) || DEFAULT_ANALYTICS_DOMAIN;\n\n/**\n * to debug errors here, first, change the parent to have { silent: false }, in analytics.js `fork` call.\n */\nprocess.on('message', (msg) => {\n  // needed for the parent to make sure the child got the message\n  // without it, when the message is large, the parent exits before it totally sent\n  process.send('Got the message');\n\n  const body = JSON.stringify(msg);\n  return fetch(ANALYTICS_DOMAIN, {\n    method: 'post',\n    body,\n    headers: {\n      'Content-Type': 'application/json',\n    },\n  })\n    .then((res) => {\n      if (res.ok) {\n        // res.status >= 200 && res.status < 300\n        console.log('message has been sent');\n        process.exit();\n      } else {\n        console.error('failed to send the message', res.statusText);\n        process.exit();\n      }\n    })\n    .catch((err) => {\n      console.error('failed to send the message', err);\n      process.exit();\n    });\n});\n\nsetTimeout(() => {\n  console.log('exit due to timeout');\n  process.exit();\n}, 5000);\n"
  },
  {
    "path": "packages/legacy/src/bootstrap.ts",
    "content": "import fs from 'fs-extra';\nimport { handleUnhandledRejection } from './cli/handleErrors';\nimport { DIR_GLOBAL_CONFIG, DIR_GLOBAL_LOGS } from './constants';\nimport { printWarning } from './logger';\nimport { getCliVersion } from './utils';\n\n// suppress fs experimental warnings from memfs\nprocess.env.MEMFS_DONT_WARN = 'true';\n\n// set max listeners to a more appropriate number\n// eslint-disable-next-line @typescript-eslint/no-var-requires\nrequire('events').EventEmitter.defaultMaxListeners = 100;\n\nprocess.on('unhandledRejection', async (err) => handleUnhandledRejection(err));\n\nexport async function bootstrap() {\n  printVersionIfAsked();\n  warnIfRunningAsRoot();\n  verifyNodeVersionCompatibility();\n  await ensureDirectories();\n  // await Analytics.promptAnalyticsIfNeeded();\n}\n\nasync function ensureDirectories() {\n  await fs.ensureDir(DIR_GLOBAL_CONFIG);\n  await fs.ensureDir(DIR_GLOBAL_LOGS);\n}\n\nfunction verifyNodeVersionCompatibility() {\n  // const nodeVersion = process.versions.node.split('-')[0];\n  // TODO check node version\n}\n\nfunction warnIfRunningAsRoot() {\n  const isRoot = process.getuid && process.getuid() === 0;\n  if (isRoot) {\n    printWarning('Running cli as root might cause permission issues later');\n  }\n}\n\nfunction printVersionIfAsked() {\n  if (['-V', '-v', '--version'].includes(process.argv[2])) {\n    console.log(getCliVersion());\n    process.exit();\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/cli/command.ts",
    "content": "import type { ReactElement } from 'react';\nimport { Group } from './commandGroups';\n\nexport type Flags = { [flagName: string]: string | boolean | undefined | any };\nexport type CLIArgs = Array<string[] | string>;\nexport type GenericObject = { [k: string]: any };\nexport type Report = { data: string; code: number };\nexport type RenderResult = { data: ReactElement; code: number };\nexport type Example = { cmd: string; description: string };\nexport type CommandArg = { name: string; description?: string };\nexport type CommandOption = [string, string, string];\nexport type CommandOptions = Array<CommandOption>;\n\nexport interface Command {\n  /**\n   * name of command with arguments:\n   * <> for mandatory arguments.\n   * [] for optional arguments.\n   * e.g. 'add <path>'\n   */\n  name: string;\n\n  /**\n   * command alias (for example: 't' for 'tag')\n   */\n  alias?: string;\n\n  /**\n   * The description of the command. Being used in the commands summery and the help\n   * should be short and precise. not more than one line. (use extendedDescription for more info).\n   */\n  description?: string;\n\n  /**\n   * The extended description of the command. Will be seen in only in the command help, just after the description.\n   */\n  extendedDescription?: string;\n\n  /**\n   * url to a doc page explaining the command. shown in the command help just after the extendedDescription.\n   */\n  helpUrl?: string;\n\n  /**\n   * allow grouping of commands to hint summery renderer\n   * Places in default automatic help\n   */\n  group?: Group | string;\n\n  /**\n   * should a command be exposed to the user (by arco help).\n   * e.g. experimental commands or commands created for the ssh communication should not be exposed\n   */\n  private?: boolean;\n\n  /**\n   * command that is not running on the terminal, such as \"_fetch\", \"_put\".\n   * in case an error is thrown, it is serialized so it's easier to parse it later\n   */\n  internal?: boolean;\n\n  /**\n   * should turn on Loader.\n   * the default is false for internal-commands and true for others.\n   * @see cliMain.setDefaults()\n   */\n  loader?: boolean;\n\n  /**\n   * Array of command options where each element is a tuple.\n   * ['flag alias', 'flag name', 'flag description']\n   * for example:\n   * ['j', 'json', 'output json format']\n   */\n  options: CommandOptions;\n\n  /**\n   * arguments are defined in the \"name\" property, and that's where the source of truth is.\n   * this prop is optional and provides a way to describe the args. later, it'll support more fields, such as defaultValue.\n   * if this is set, it'll be shown in the command help under \"Arguments\" section.\n   */\n  arguments?: CommandArg[];\n\n  /**\n   * sub commands for example:\n   * arco capsule list to list active capsules.\n   */\n  commands?: Command[];\n\n  /**\n   * interact with a remote\n   * for now, the only difference is that they get a \"token\" flag to authenticate anonymously.\n   */\n  remoteOp?: boolean;\n\n  /**\n   * if true, it indicates that it doesn't need the workspace to work and can be executed outside a\n   * workspace\n   */\n  skipWorkspace?: boolean;\n\n  /**\n   * optionally, give some examples how to use the command.\n   */\n  examples?: Example[];\n\n  /**\n   * do not set this. it is being set once the command run.\n   * the values are those followed `--` in the command line. (e.g. `arco import -- --no-optional`)\n   */\n  _packageManagerArgs?: string[];\n\n  /**\n   * Main command handler which is called when invoking new commands\n   * @param args  - arguments object as defined in name.\n   * @param flags - command flags as described in options.\n   * @return - JSX element which is rendered with ink\n   */\n  render?(args: CLIArgs, flags: Flags): Promise<RenderResult | ReactElement>;\n\n  /**\n   * render method from ink\n   * https://www.npmjs.com/package/ink\n   * package ink depends on react\n   * mount its render method on Command instance to ensure that there is only one copy of React\n   */\n  inkRender?: (element: ReactElement) => { waitUntilExit: () => Promise<void> };\n\n  /**\n   * Command handler which is called for legacy commands or when process.isTTY is false\n   * @param args  - arguments object as defined in name.\n   * @param flags - command flags as described in options.\n   * @return - Report object. The Report.data is printed to the stdout as is.\n   */\n  report?(args: CLIArgs, flags: Flags): Promise<string | Report>;\n\n  /**\n   * Optional handler to provide a raw result of the command.\n   * Will be go called if '-j'/'--json' option is provided by user.\n   * @param args  - arguments object as defined in name.\n   * @param flags - command flags as described in options.\n   * @return a GenericObject to be rendered to string (by json.stringify) in the console.\n   */\n  json?(args: CLIArgs, flags: Flags): Promise<GenericObject>;\n}\n"
  },
  {
    "path": "packages/legacy/src/cli/commandGroups.ts",
    "content": "/**\n * these are the main group. legacy commands use only these groups.\n * CLI commands can create new groups by calling `cliMain.registerGroup()`.\n */\nexport const groups = {\n  general: 'General commands',\n  start: 'Start a working area',\n  development: 'Develop components',\n  collaborate: 'Collaborate on components',\n  discover: 'Explore components',\n  ungrouped: 'Ungrouped',\n};\n\nexport type Group = keyof typeof groups;\n\nexport type GroupsType = { [groupName: string]: string };\n"
  },
  {
    "path": "packages/legacy/src/cli/commandRegistry.ts",
    "content": "import { LegacyCommand } from './legacyCommand';\n\nexport function parseCommandName(commandName: string): string {\n  return commandName?.split(' ')?.[0] || '';\n}\n\nexport default class CommandRegistry {\n  version: string;\n\n  usage: string;\n\n  description: string;\n\n  commands: LegacyCommand[];\n\n  constructor(usage: string, description: string, version: string, commands: LegacyCommand[]) {\n    this.usage = usage;\n    this.description = description;\n    this.version = version;\n    this.commands = commands;\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/cli/commands/host/host.ts",
    "content": "import chalk from 'chalk';\nimport { LegacyCommand } from '../../legacyCommand';\nimport { Group } from '../../commandGroups';\nimport { setSync, getSync, delSync } from '../../../globalConfig';\nimport { CFG_HOST_ARCO_KEY, DEFAULT_HOST_ARCO } from '../../../constants';\nimport { CommandOptions } from '../../command';\n\nexport class Host implements LegacyCommand {\n  name = 'host [host-name]';\n\n  description = 'set host of Arco';\n\n  arguments = [\n    {\n      name: 'host-name',\n      description: `switch host of Arco, depends on the version of material market you want to use (defaults to ${DEFAULT_HOST_ARCO})`,\n    },\n  ];\n\n  options = [['', 'reset', `reset host of Arco to ${DEFAULT_HOST_ARCO}`]] as CommandOptions;\n\n  group: Group = 'general';\n\n  alias = '';\n\n  skipWorkspace = true;\n\n  async action([hostName]: [string], options: { reset: boolean }) {\n    if (hostName) {\n      setSync({ [CFG_HOST_ARCO_KEY]: hostName });\n      return hostName;\n    }\n\n    if (options.reset) {\n      delSync(CFG_HOST_ARCO_KEY);\n    }\n\n    return null;\n  }\n\n  report(newHostName: string): string {\n    const currentHostName = newHostName || getSync(CFG_HOST_ARCO_KEY);\n    const resetHostTip =\n      currentHostName === DEFAULT_HOST_ARCO ? '' : `, reset it to default via 'arco host --reset'`;\n    return chalk.green(`host of Arco has been set to ${currentHostName}${resetHostTip}`);\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/cli/commands/host/index.ts",
    "content": "export { Host } from './host';\n"
  },
  {
    "path": "packages/legacy/src/cli/commands/login/index.ts",
    "content": "export { Login } from './login';\n"
  },
  {
    "path": "packages/legacy/src/cli/commands/login/login.ts",
    "content": "import http from 'http';\nimport chalk from 'chalk';\nimport connect from 'connect';\nimport open from 'open';\nimport uniqid from 'uniqid';\n\nimport logger from '../../../logger';\nimport request from '../../request';\nimport { LegacyCommand } from '../../legacyCommand';\nimport { Group } from '../../commandGroups';\nimport { setSync } from '../../../globalConfig';\nimport { loginSuccessPage } from './loginSuccessPage';\nimport { checkUserLogin, getUserInfoFromAPI, UserFromAPI } from '../../user';\nimport {\n  CFG_USER_NAME_KEY,\n  CFG_USER_TOKEN_KEY,\n  CFG_USER_EMAIL_KEY,\n  CFG_USER_ACCOUNT_TYPE_KET,\n} from '../../../constants';\n\ntype LoginActionResult = {\n  isLoggedIn?: boolean;\n  isWaiting?: boolean;\n  username?: string;\n};\n\nconst LOCAL_LISTEN_SERVER_PATH = '/login_result';\nconst LOCAL_LISTEN_SERVER_PORT = 3333;\n\nexport class Login implements LegacyCommand {\n  // Avoid calling this function in a loop to report errors\n  static isWaiting = false;\n\n  private successHTMLString = loginSuccessPage();\n\n  name = 'login';\n\n  description = 'log in to Arco';\n\n  group: Group = 'general';\n\n  alias = '';\n\n  skipWorkspace = true;\n\n  options = [];\n\n  async action(): Promise<LoginActionResult> {\n    if (Login.isWaiting) return { isWaiting: true };\n\n    const { loggedIn, user } = await checkUserLogin();\n    if (loggedIn) {\n      return {\n        isLoggedIn: true,\n        username: user.username,\n      };\n    }\n\n    Login.isWaiting = true;\n\n    let httpServer;\n    const userInfo: UserFromAPI = await new Promise((resolve, reject) => {\n      const app = connect();\n      const token = uniqid();\n\n      app.use(LOCAL_LISTEN_SERVER_PATH, async (_, res, next) => {\n        try {\n          setSync({ [CFG_USER_TOKEN_KEY]: token });\n          const { user } = await getUserInfoFromAPI();\n          res.end(this.successHTMLString);\n          resolve(user);\n        } catch (err) {\n          next(err);\n        }\n      });\n\n      httpServer = http.createServer(app).listen(LOCAL_LISTEN_SERVER_PORT);\n\n      request\n        .get('login', {\n          headers: {\n            [CFG_USER_TOKEN_KEY]: token,\n            referer: `http://localhost:${LOCAL_LISTEN_SERVER_PORT}${LOCAL_LISTEN_SERVER_PATH}`,\n          },\n        })\n        .then((res) => {\n          const { result } = res;\n          console.log(\n            chalk.cyan(\n              `\\nPlease complete the authentication in the browser: ${result.redirectUrl}\\n`\n            )\n          );\n          open(result.redirectUrl);\n        })\n        .catch((err) => {\n          reject(err);\n          logger.error('get an error from command login', err);\n        });\n    });\n\n    setSync({\n      [CFG_USER_NAME_KEY]: userInfo.username,\n      [CFG_USER_EMAIL_KEY]: userInfo.email,\n      [CFG_USER_ACCOUNT_TYPE_KET]: userInfo.accountType,\n    });\n    httpServer?.close();\n\n    return { username: userInfo.username };\n  }\n\n  report({ isWaiting, isLoggedIn = false, username }: LoginActionResult): string {\n    return isWaiting\n      ? chalk.yellow('a login process is already running')\n      : isLoggedIn\n      ? chalk.yellow(`${username || 'you'} already logged in`)\n      : chalk.green(`successfully logged in as ${username}`);\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/cli/commands/login/loginSuccessPage.ts",
    "content": "export function loginSuccessPage() {\n  return `\n<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Arco CLI login succeeded</title>\n  </head>\n  <body style=\"background-color: #1d2129\">\n    <div\n      style=\"\n        position: absolute;\n        top: 50%;\n        left: 50%;\n        transform: translate(-50%, -50%);\n        padding: 40px 60px;\n        font-size: 16px;\n        border-radius: 30px;\n        background-color: #165dff;\n        color: #fff;\n      \"\n    >\n      <span\n        style=\"\n          position: absolute;\n          display: block;\n          width: 4px;\n          height: 62%;\n          left: 40px;\n          top: 19%;\n          background-color: rgba(255, 255, 255, 0.8);\n        \"\n      ></span>\n      <p style=\"font-size: 32px; font-weight: 500; margin-top: 12px\">Arco CLI Login Succeeded</p>\n      <p>You can close this page now</p>\n      <p>\n        Enter\n        <code\n          style=\"\n            background-color: rgba(255, 255, 255, 0.2);\n            margin: 0 6px;\n            padding: 3px 8px;\n            border-radius: 4px;\n          \"\n          >arco -h</code\n        >\n        on the command line to view the help information\n      </p>\n    </div>\n  </body>\n</html>\n`;\n}\n"
  },
  {
    "path": "packages/legacy/src/cli/commands/logout/index.ts",
    "content": "export { Logout } from './logout';\n"
  },
  {
    "path": "packages/legacy/src/cli/commands/logout/logout.ts",
    "content": "import chalk from 'chalk';\nimport { LegacyCommand } from '../../legacyCommand';\nimport { Group } from '../../commandGroups';\nimport { delSync, getSync } from '../../../globalConfig';\nimport { CFG_USER_NAME_KEY, CFG_USER_TOKEN_KEY } from '../../../constants';\n\ntype LogoutActionResult = {\n  isNotLoggedIn?: boolean;\n  username?: string;\n};\n\nexport class Logout implements LegacyCommand {\n  name = 'logout';\n\n  description = 'log out from Arco';\n\n  group: Group = 'general';\n\n  alias = '';\n\n  skipWorkspace = true;\n\n  options = [];\n\n  async action(): Promise<LogoutActionResult> {\n    if (getSync(CFG_USER_TOKEN_KEY)) {\n      delSync(CFG_USER_TOKEN_KEY);\n      return { username: getSync(CFG_USER_NAME_KEY) };\n    }\n\n    return { isNotLoggedIn: true };\n  }\n\n  report({ isNotLoggedIn = false, username }: LogoutActionResult): string {\n    return isNotLoggedIn\n      ? chalk.yellow('you are not logged yet')\n      : chalk.green(`${username || 'you'} successfully logged out`);\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/cli/defaultErrorHandler.ts",
    "content": "import chalk from 'chalk';\nimport ArcoError from '../error/arcoError';\n// import { Analytics, LEVEL } from '../analytics/analytics';\n// import hashErrorIfNeeded from '../error/hashErrorObject';\n\nconst errorsMap: Array<[Error, (err: Error) => string]> = [];\n\nfunction findErrorDefinition(err: Error) {\n  return errorsMap.find(([ErrorType]) => {\n    // in some cases, such as forked process, the received err is serialized.\n    return err instanceof (ErrorType as any) || (err && err.name === ErrorType.name);\n  });\n}\n\nfunction getErrorFunc(errorDefinition) {\n  if (!errorDefinition) return null;\n  const [, func] = errorDefinition;\n  return func;\n}\n\nfunction getErrorMessage(\n  error: Error | null | undefined,\n  func: ((err: Error) => string) | null | undefined\n): string {\n  if (!error || !func) return '';\n  return func(error);\n}\n\n/**\n * if err.userError is set, it inherits from AbstractError, which are user errors not Arco errors\n * and should not be reported to Sentry.\n * reason why we don't check (err instanceof AbstractError) is that it could be thrown from a fork,\n * in which case, it loses its class and has only the fields.\n */\n// function sendToAnalyticsAndSentry(err: Error) {\n//   const possiblyHashedError = hashErrorIfNeeded(err);\n//   // @ts-ignore\n//   const shouldNotReportToSentry = Boolean(err.isUserError || err.code === 'EACCES');\n//   // only level FATAL are reported to Sentry.\n//   const level = shouldNotReportToSentry ? LEVEL.INFO : LEVEL.FATAL;\n//   Analytics.setError(level, possiblyHashedError);\n// }\n\nfunction handleNonArcoCustomErrors(err: Error): string {\n  const { code, path } = err as any;\n  if (code === 'EACCES' && path) {\n    return chalk.red(\n      `error: you do not have permissions to access '${path}', were you running arco, npm or git as root?`\n    );\n  }\n  return chalk.red(err.message || err);\n}\n\nexport default (err: Error): { message: string; error: Error } => {\n  const errorDefinition = findErrorDefinition(err);\n  const getErrMsg = (): string => {\n    if (err instanceof ArcoError) {\n      return err.report();\n    }\n    if (!errorDefinition) {\n      return handleNonArcoCustomErrors(err);\n    }\n    const func = getErrorFunc(errorDefinition);\n    const errorMessage = getErrorMessage(err, func) || 'unknown error';\n    err.message = errorMessage;\n    return errorMessage;\n  };\n\n  // sendToAnalyticsAndSentry(err);\n  const errorMessage = getErrMsg();\n  return {\n    message: chalk.red([errorMessage, `use the '--log' flag for the full error.`].join('\\n\\n')),\n    error: err,\n  };\n};\n"
  },
  {
    "path": "packages/legacy/src/cli/globalFlags.ts",
    "content": "class GlobalFlags {\n  private _token: string | undefined;\n\n  get token(): string | undefined {\n    return this._token;\n  }\n\n  set token(token: string | undefined) {\n    this._token = token;\n  }\n}\n\nconst globalFlags = new GlobalFlags();\n\nexport default globalFlags;\n"
  },
  {
    "path": "packages/legacy/src/cli/handleErrors.ts",
    "content": "import { serializeError } from 'serialize-error';\nimport logger from '../logger/logger';\nimport { buildCommandMessage, isNumeric, packCommand } from '../utils';\nimport defaultHandleError from './defaultErrorHandler';\nimport loader from './loader';\n\nexport async function handleErrorAndExit(\n  err: Error,\n  commandName: string,\n  shouldSerialize = false\n): Promise<void> {\n  try {\n    loader.off();\n    logger.error(`got an error from command ${commandName}: ${err}`);\n    logger.error(err.stack || '<no error stack was found>');\n\n    const { message, error } = defaultHandleError(err);\n\n    if (shouldSerialize) {\n      serializeErrAndExit(error, commandName);\n    } else {\n      await logErrAndExit(message, commandName);\n    }\n  } catch (e: any) {\n    console.error('failed to log the error properly, failure error', e);\n    console.error('failed to log the error properly, original error', err);\n    process.exit(1);\n  }\n}\n\nexport async function handleUnhandledRejection(\n  err: Error | null | undefined | Record<string, never>\n) {\n  console.error(\n    '** unhandled rejection found, please make sure the promise is resolved/rejected correctly! **'\n  );\n  if (err instanceof Error) {\n    return handleErrorAndExit(err, process.argv[2]);\n  }\n  console.error(err);\n  return handleErrorAndExit(new Error(`unhandledRejections found. err ${err}`), process.argv[2]);\n}\n\nasync function logErrAndExit(err: Error | string, commandName: string) {\n  if (!err) {\n    throw new Error(`logErrAndExit expects to get either an Error or a string, got nothing`);\n  }\n\n  console.error(err);\n  await logger.exitAfterFlush(1, commandName, err.toString());\n}\n\nfunction serializeErrAndExit(err, commandName: string) {\n  const data = packCommand(\n    buildCommandMessage(serializeError(err), undefined, false),\n    false,\n    false\n  );\n  const code = err.code && isNumeric(err.code) ? err.code : 1;\n  return process.stderr.write(data, () => logger.exitAfterFlush(code, commandName));\n}\n"
  },
  {
    "path": "packages/legacy/src/cli/legacyCommand.ts",
    "content": "import { Group } from './commandGroups';\nimport { CommandOptions } from './command';\n\nexport interface LegacyCommand {\n  name: string;\n  // for help command\n  description: string;\n  // for the command itself\n  extendedDescription?: string;\n  helpUrl?: string;\n  alias: string;\n  options?: CommandOptions;\n  commands?: LegacyCommand[];\n  private?: boolean;\n  loader?: boolean;\n  skipWorkspace?: boolean;\n  migration?: boolean;\n  internal?: boolean;\n  // Used for adding the token option globally\n  remoteOp?: boolean;\n  // for grouping in the \"arco help\" page\n  group?: Group;\n\n  action(params: any, options: { [key: string]: any }, packageManagerArgs?: string[]): Promise<any>;\n\n  report(data: any, params: any, options: { [key: string]: any }): string;\n}\n"
  },
  {
    "path": "packages/legacy/src/cli/loader/index.ts",
    "content": "import loader from './loader';\n\nexport default loader;\n"
  },
  {
    "path": "packages/legacy/src/cli/loader/loader.ts",
    "content": "import ora, { Ora, PersistOptions } from 'ora';\n\nimport { SPINNER_TYPE } from '../../constants';\n\nexport class Loader {\n  private spinner: Ora | null;\n\n  private createNewSpinner(): Ora {\n    return ora({\n      spinner: SPINNER_TYPE,\n      text: '',\n      stream: process.stdout,\n      discardStdin: false,\n      hideCursor: false,\n    });\n  }\n\n  get isStarted() {\n    return !!this.spinner;\n  }\n\n  on(): Loader {\n    if (!this.spinner) {\n      this.spinner = this.createNewSpinner();\n    }\n    return this;\n  }\n\n  off(): Loader {\n    this.stop();\n    this.spinner = null;\n    return this;\n  }\n\n  start(text?: string): Loader {\n    if (this.spinner) {\n      this.spinner.start(text);\n    }\n    return this;\n  }\n\n  setText(text: string): Loader {\n    if (this.spinner) this.spinner.text = text;\n    return this;\n  }\n\n  setTextAndRestart(text: string): Loader {\n    if (this.spinner) {\n      this.spinner.stop();\n      this.spinner.text = text;\n      this.spinner.start();\n    }\n    return this;\n  }\n\n  get(): Ora | null {\n    return this.spinner;\n  }\n\n  stop(): Loader {\n    if (this.spinner) this.spinner.stop();\n    return this;\n  }\n\n  succeed(text?: string): Loader {\n    if (this.spinner) this.spinner.succeed(text);\n    return this;\n  }\n\n  fail(text?: string): Loader {\n    if (this.spinner) this.spinner.fail(text);\n    return this;\n  }\n\n  warn(text?: string): Loader {\n    if (this.spinner) this.spinner.warn(text);\n    return this;\n  }\n\n  info(text?: string): Loader {\n    if (this.spinner) this.spinner.info(text);\n    return this;\n  }\n\n  stopAndPersist(options?: PersistOptions): Loader {\n    if (this.spinner) this.spinner.stopAndPersist(options);\n    return this;\n  }\n}\n\nconst loader = new Loader();\n\nexport default loader;\n"
  },
  {
    "path": "packages/legacy/src/cli/registerCommands.ts",
    "content": "import { CLI_USAGE, CLI_DESCRIPTION } from '../constants';\nimport CommandRegistry from './commandRegistry';\nimport { Login } from './commands/login';\nimport { Logout } from './commands/logout';\nimport { Host } from './commands/host';\nimport { getCliVersion } from '../utils';\n\nexport default function registerCommands(): CommandRegistry {\n  return new CommandRegistry(CLI_USAGE, CLI_DESCRIPTION, getCliVersion(), [\n    new Login(),\n    new Logout(),\n    new Host(),\n  ]);\n}\n"
  },
  {
    "path": "packages/legacy/src/cli/request.ts",
    "content": "import axios from 'axios';\nimport logger from '../logger';\nimport { getSync } from '../globalConfig';\nimport { CFG_HOST_ARCO_KEY, CFG_ACCESS_TOKEN_KEY, CFG_USER_TOKEN_KEY } from '../constants';\n\nconst TIMEOUT_REQUEST = 1000 * 60;\n\nconst request = (\n  method: 'all' | 'get' | 'delete' | 'post' | 'put',\n  {\n    url,\n    data = {},\n    option = {},\n  }: { url: string; data?: { [key: string]: any }; option?: { [key: string]: any } }\n) => {\n  const hostArco = getSync(CFG_HOST_ARCO_KEY);\n  const userToken = getSync(CFG_USER_TOKEN_KEY);\n  const accessToken = getSync(CFG_ACCESS_TOKEN_KEY);\n  const baseURL = `http${\n    hostArco.indexOf('localhost') > -1 ? '' : 's'\n  }://${hostArco}/material/api/`;\n\n  const instance = axios.create({\n    baseURL,\n    timeout: TIMEOUT_REQUEST,\n  });\n\n  option.headers = {\n    ...option.headers,\n    [CFG_USER_TOKEN_KEY]: option.headers?.[CFG_USER_TOKEN_KEY] || userToken || '',\n    [CFG_ACCESS_TOKEN_KEY]: accessToken,\n  };\n\n  const req =\n    method === 'get' || method === 'delete'\n      ? instance[method](url, option)\n      : instance[method](url, data, option);\n\n  return req\n    .then((res) => {\n      return res.data;\n    })\n    .catch((err) => {\n      logger.error(`failed to request ${baseURL}${url}`, err);\n      return Promise.reject(err);\n    });\n};\n\nexport default {\n  all: (arr) => {\n    return axios.all(arr);\n  },\n  get: (url, option?) => request('get', { url, option }),\n  delete: (url, option?) => request('delete', { url, option }),\n  post: (url, data?, option?) => request('post', { url, option, data }),\n  put: (url, data?, option?) => request('put', { url, option, data }),\n};\n"
  },
  {
    "path": "packages/legacy/src/cli/uploadFile.ts",
    "content": "import fs from 'fs-extra';\nimport axios from 'axios';\nimport FormData from 'form-data';\n\nimport { getSync } from '../globalConfig';\nimport { CFG_ACCESS_TOKEN_KEY, CFG_HOST_ARCO_KEY, CFG_USER_TOKEN_KEY } from '../constants';\n\ntype FileUploadResult = {\n  code: number;\n  msg: string;\n  data?: {\n    zip: string;\n    files: Record<string, string>;\n  };\n};\n\nexport async function uploadFile(options: {\n  filePath: string;\n  manifest?: Record<string, string>;\n  cdnGlobs?: string[];\n}): Promise<FileUploadResult> {\n  const hostArco = getSync(CFG_HOST_ARCO_KEY);\n  const userToken = getSync(CFG_USER_TOKEN_KEY);\n  const accessToken = getSync(CFG_ACCESS_TOKEN_KEY);\n  const { filePath, manifest, cdnGlobs } = options;\n\n  const form = new FormData();\n  const result: FileUploadResult = {\n    code: 1,\n    msg: '',\n  };\n\n  form.append('file', fs.createReadStream(filePath));\n  if (manifest) {\n    form.append('manifest', JSON.stringify(manifest));\n  }\n  if (Array.isArray(cdnGlobs) && cdnGlobs.length) {\n    form.append('cdnGlobs', JSON.stringify(cdnGlobs));\n  }\n\n  try {\n    const {\n      data: { code, msg, data },\n    } = await axios.post(`https://${hostArco}/files/uploadFiles`, form, {\n      timeout: 1000 * 60 * 10,\n      headers: {\n        ...form.getHeaders(),\n        [CFG_USER_TOKEN_KEY]: userToken,\n        [CFG_ACCESS_TOKEN_KEY]: accessToken,\n      },\n    });\n\n    result.msg = msg;\n    result.code = code;\n    result.data = data;\n  } catch (err) {\n    result.msg = err.toString();\n  }\n\n  return result;\n}\n"
  },
  {
    "path": "packages/legacy/src/cli/user/checkUserLogin.ts",
    "content": "import { getSync } from '../../globalConfig';\nimport { getUserInfoFromAPI, UserFromAPI } from './getUserInfoFromAPI';\nimport { CFG_ACCESS_TOKEN_KEY, CFG_USER_TOKEN_KEY } from '../../constants';\n\nexport async function checkUserLogin(): Promise<{ loggedIn: boolean; user?: UserFromAPI }> {\n  if (!getSync(CFG_USER_TOKEN_KEY) && !getSync(CFG_ACCESS_TOKEN_KEY)) {\n    return { loggedIn: false };\n  }\n\n  const { ok, user } = await getUserInfoFromAPI();\n  return ok && user ? { loggedIn: true, user } : { loggedIn: false };\n}\n"
  },
  {
    "path": "packages/legacy/src/cli/user/getUserInfoFromAPI.ts",
    "content": "import request from '../request';\nimport logger from '../../logger';\n\nexport type UserFromAPI = {\n  accountType: 'sso' | 'github';\n  name: string;\n  username: string;\n  nickname: string;\n  email: string;\n  avatarUrl: string;\n};\n\nexport async function getUserInfoFromAPI(): Promise<{\n  ok: boolean;\n  user?: UserFromAPI;\n  msg?: string;\n}> {\n  try {\n    const { ok, msg, result: user } = await request.get('userInfo');\n\n    if (!ok && msg) {\n      logger.error('get error while get user info from API', msg);\n    }\n\n    return { ok, msg, user };\n  } catch (error) {\n    return { ok: false, msg: error.toString() };\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/cli/user/index.ts",
    "content": "export { checkUserLogin } from './checkUserLogin';\nexport { getUserInfoFromAPI, UserFromAPI } from './getUserInfoFromAPI';\n"
  },
  {
    "path": "packages/legacy/src/constants.ts",
    "content": "import os from 'os';\nimport path from 'path';\nimport cliSpinners from 'cli-spinners';\n\nconst userHome = os.homedir();\n\nfunction getDirectory(): string {\n  if (process.platform === 'win32' && process.env.LOCALAPPDATA) {\n    return path.join(process.env.LOCALAPPDATA, 'Arco');\n  }\n  return path.join(userHome, '.arco');\n}\n\nexport const ENV_GLOBAL_CACHE_DIR = 'ARCO_GLOBAL_CACHE_DIR';\n\nfunction getCacheDirectory(): string {\n  const fromEnvVar = process.env[ENV_GLOBAL_CACHE_DIR];\n  if (fromEnvVar && typeof fromEnvVar === 'string') {\n    return fromEnvVar;\n  }\n  if (process.platform === 'darwin' || process.platform === 'linux') {\n    return path.join(userHome, 'Library', 'Caches', 'Arco');\n  }\n  return getDirectory();\n}\n\nexport const ENV_VARIABLE_CONFIG_PREFIX = 'ARCO_CONFIG_';\n\nexport const ENV_BUNDLE_SIZE_ANALYZER = 'BUNDLE_SIZE_ANALYZER';\n\nexport const ENV_BUNDLE_SPEED_ANALYZER = 'BUNDLE_SPEED_ANALYZER';\n\nexport const MATERIAL_GENERATION = 2;\n\n/**\n * Dir or file path\n */\nexport const DIR_CACHE_ROOT = getCacheDirectory();\n\nexport const DIR_GLOBAL_CONFIG = path.join(DIR_CACHE_ROOT, 'config');\n\nexport const DIR_GLOBAL_LOGS = path.join(DIR_CACHE_ROOT, 'logs');\n\n/**\n * A folder to write artifacts generated during a build task\n * This folder is used in the core envs and excluded by default from the package tar file\n */\nexport const DIR_ARTIFACTS = 'artifacts';\n\nexport const DIR_ARTIFACTS_PREVIEW = path.join(DIR_ARTIFACTS, 'preview');\n\nexport const DIR_ARTIFACTS_DOCS = path.join(DIR_ARTIFACTS, 'docs');\n\nexport const DIR_SOURCE = 'source';\n\nexport const FILE_GLOBAL_CONFIG = 'config.json';\n\nexport const FILE_WORKSPACE_JSONC = 'arco.workspace.jsonc';\n\nexport const FILE_WORKSPACE_JS = 'arco.workspace.js';\n\nexport const PATH_DEBUG_LOGS = path.join(DIR_CACHE_ROOT, 'debug.log');\n\n/**\n * Global config keys\n */\nexport const CFG_LOG_JSON_FORMAT = 'log_json_format';\n\nexport const CFG_LOG_LEVEL = 'log_level';\n\nexport const CFG_NO_WARNINGS = 'no_warnings';\n\nexport const CFG_USER_EMAIL_KEY = 'user.email';\n\nexport const CFG_USER_TOKEN_KEY = 'x-arco-token';\n\nexport const CFG_ACCESS_TOKEN_KEY = 'x-arco-access-token';\n\nexport const CFG_USER_NAME_KEY = 'user.name';\n\nexport const CFG_USER_ACCOUNT_TYPE_KET = 'user.accountType';\n\nexport const CFG_HOST_NPM_KEY = 'host.npm';\n\nexport const CFG_HOST_ARCO_KEY = 'host.arco';\n\nexport const CFG_ANALYTICS_DOMAIN_KEY = 'analytics_domain';\n\nexport const CFG_ANALYTICS_ANONYMOUS_KEY = 'anonymous_reporting';\n\nexport const CFG_ANALYTICS_REPORTING_KEY = 'analytics_reporting';\n\nexport const CFG_ANALYTICS_ERROR_REPORTS_KEY = 'error_reporting';\n\nexport const CFG_ANALYTICS_ENVIRONMENT_KEY = 'arco_environment';\n\nexport const CFG_ANALYTICS_USERID_KEY = 'analytics_id';\n\n/**\n * Aspect info\n */\nexport const CORE_ASPECT_PACKAGE_NAME_MAP = {\n  APP_ARCO: '@arco-cli/arco',\n  ENV_REACT: '@arco-cli/react',\n};\n\nexport const CORE_ASPECT_ID_MAP = {\n  APP_ARCO: 'arco.app/arco',\n  ENV_REACT: 'arco.env/react',\n};\n\n/**\n * Domain info\n */\nexport const BASE_WEB_DOMAIN = 'arco.design';\n\nexport const BASE_DOCS_DOMAIN = `${BASE_WEB_DOMAIN}/material`;\n\n/**\n * Default values\n */\nexport const DEFAULT_ENV = CORE_ASPECT_ID_MAP.ENV_REACT;\n\nexport const DEFAULT_ENV_CONFIG_PATH = 'arco.env.config.js';\n\nexport const DEFAULT_ANALYTICS_DOMAIN = `TODO: date analytics`;\n\nexport const DEFAULT_DIST_DIRNAME = 'dist';\n\nexport const DEFAULT_BUILD_IGNORE_PATTERNS = ['**/__test__/**/*', '**/__docs__/**/*'];\n\nexport const DEFAULT_LANGUAGE = 'javascript';\n\nexport const DEFAULT_HOST_ARCO = 'arco.design';\n\nexport const DEFAULT_MATERIAL_GROUP_ID = 0;\n\nexport const DEFAULT_TEST_FILE_PATTERNS = ['**/?(*.)+(spec|test).[jt]s?(x)'];\n\n/**\n * Others\n */\nexport const IS_WINDOWS = os.platform() === 'win32';\n\nexport const SPINNER_TYPE = IS_WINDOWS ? cliSpinners.dots : cliSpinners.dots12;\n\nexport const GIT_IGNORE = '.gitignore';\n\nexport const PACKAGE_JSON = 'package.json';\n\nexport const IGNORE_LIST = [\n  '**/.gitignore',\n  '**/node_modules/**',\n  '**/package-lock.json',\n  '**/yarn.lock',\n  '**/LICENSE',\n  '*/tsconfig.json',\n];\n\n/**\n * CLI help infos\n */\nexport const CLI_DESCRIPTION = '';\n\nexport const CLI_USAGE = '[--version] [--help] <command> [<args>]';\n\nexport const CLI_COMPONENT_PATTERN_HELP = `component name, package name, or component pattern. use component pattern to select multiple components.\nuse comma to separate patterns and \"!\" to exclude. e.g. \"ui/**, !ui/button\"\nwrap the pattern with quotes`;\n\nexport const CLI_TASK_NAME_HELP = `build the specified task(s) only. for multiple tasks, separate by a comma.\nspecify the task-name (e.g. \"TSCompilerESM\") or the task-aspect-id (e.g. \"arco.service/compiler\");`;\n\nexport const CLI_LOGIN_FIRST_TIP = `please use 'arco login' to login in first`;\n\n/**\n * Build task names\n */\nexport const BUILD_TASK_NAME_DOCS = 'HandleDocuments';\n\nexport const BUILD_TASK_NAME_PREVIEW = 'GeneratePreview';\n\nexport const BUILD_TASK_NAME_COMPILER_ESM = 'TSCompilerESM';\n\nexport const BUILD_TASK_NAME_COMPILER_CJS = 'TSCompilerCJS';\n"
  },
  {
    "path": "packages/legacy/src/error/abstractError.ts",
    "content": "export default class AbstractError extends Error {\n  isUserError: boolean;\n\n  constructor() {\n    super();\n    this.name = this.constructor.name;\n    this.isUserError = true;\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/error/arcoError.ts",
    "content": "export default class ArcoError extends Error {\n  isUserError = true;\n\n  constructor(msg?: string) {\n    super(msg || '');\n    this.name = this.constructor.name; // otherwise, the \"name\" is just Error.\n  }\n\n  /**\n   * override if you want your error to be pretty (e.g. with color with chalk).\n   * eventually, the error shown to the user is the output of this method\n   */\n  report(): string {\n    return this.message;\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/error/cloneErrorObject.ts",
    "content": "import { cloneDeep } from 'lodash';\n\nexport const systemFields = ['stack', 'code', 'errno', 'syscall'];\n\nexport default function cloneErrorObject(error: Error): Error {\n  // @ts-ignore\n  const err = new error.constructor(error.message);\n\n  systemFields.forEach((field) => {\n    if (error[field]) err[field] = error[field];\n  });\n  Object.keys(error).forEach((key) => {\n    err[key] = cloneDeep(error[key]);\n  });\n  return err;\n}\n"
  },
  {
    "path": "packages/legacy/src/error/generalError.ts",
    "content": "import AbstractError from './abstractError';\n\nexport default class GeneralError extends AbstractError {\n  msg: string;\n\n  constructor(msg: string) {\n    super();\n    this.msg = msg;\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/error/hashErrorObject.ts",
    "content": "import yn from 'yn';\nimport hash from 'object-hash';\n\nimport logger from '../logger/logger';\nimport { getSync } from '../globalConfig';\nimport { CFG_ANALYTICS_ANONYMOUS_KEY } from '../constants';\nimport cloneErrorObject, { systemFields } from './cloneErrorObject';\n\nexport default function hashErrorIfNeeded(error: Error) {\n  let clonedError = error;\n  try {\n    clonedError = cloneErrorObject(error);\n  } catch (e: any) {\n    logger.warn('could not clone error', error);\n  }\n\n  const shouldHash = yn(getSync(CFG_ANALYTICS_ANONYMOUS_KEY), { default: true });\n  if (!shouldHash) return clonedError;\n  const fields = Object.getOwnPropertyNames(clonedError);\n  const fieldToHash = fields.filter(\n    (field) => !systemFields.includes(field) && field !== 'message'\n  );\n  if (!fieldToHash.length) return clonedError;\n\n  fieldToHash.forEach((field) => {\n    try {\n      clonedError[field] = hashValue(clonedError[field]);\n    } catch (e: any) {\n      logger.debug(`could not hash field ${field}`);\n    }\n  });\n\n  return clonedError;\n}\n\nfunction hashValue(value: any): string {\n  if (!value) return value;\n  const type = typeof value;\n  switch (type) {\n    case 'undefined':\n    case 'number':\n    case 'boolean':\n      return value;\n    case 'object':\n      // @ts-ignore\n      if (Array.isArray(value)) return value.map((v) => hash(v));\n      // ignoreUnknown helps to not throw error for some errors with custom props.\n      return hash(value, { ignoreUnknown: true });\n    default:\n      return hash(value);\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/globalConfig/config.ts",
    "content": "import fs from 'fs-extra';\nimport * as path from 'path';\n\nimport { mapToObject } from '../utils';\nimport {\n  CFG_HOST_ARCO_KEY,\n  DEFAULT_HOST_ARCO,\n  DIR_GLOBAL_CONFIG,\n  FILE_GLOBAL_CONFIG,\n} from '../constants';\n\nfunction getPath() {\n  return path.join(DIR_GLOBAL_CONFIG, FILE_GLOBAL_CONFIG);\n}\n\nexport default class Config extends Map<string, string | boolean> {\n  toPlainObject() {\n    return mapToObject(this);\n  }\n\n  toJson() {\n    return JSON.stringify(this.toPlainObject());\n  }\n\n  write() {\n    return fs.outputFile(getPath(), this.toJson());\n  }\n\n  writeSync() {\n    return fs.outputFileSync(getPath(), this.toJson());\n  }\n\n  get(key) {\n    const value = super.get(key);\n    if (value !== undefined) return value;\n\n    switch (key) {\n      case CFG_HOST_ARCO_KEY:\n        return DEFAULT_HOST_ARCO;\n\n      default:\n        return undefined;\n    }\n  }\n\n  static loadSync(): Config {\n    const configPath = getPath();\n    if (!fs.existsSync(configPath)) {\n      const config = new Config([]);\n      config.writeSync();\n      return config;\n    }\n    const contents = fs.readJsonSync(configPath);\n    return new Config(Object.entries(contents));\n  }\n\n  static async load(): Promise<Config> {\n    const configPath = getPath();\n    const exists = await fs.pathExists(configPath);\n    if (!exists) {\n      const config = new Config([]);\n      await config.write();\n      return config;\n    }\n    const contents = await fs.readJson(configPath);\n    return new Config(Object.entries(contents));\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/globalConfig/index.ts",
    "content": "import { ENV_VARIABLE_CONFIG_PREFIX } from '../constants';\nimport Config from '../globalConfig/config';\n\nexport function set(newConfig: Record<string, string | boolean>): Promise<Config> {\n  return Config.load().then((config) => {\n    if (Object.keys(newConfig).length === 0) return config;\n    Object.entries(newConfig).forEach(([key, value]) => config.set(key, value));\n    invalidateCache();\n    return config.write().then(() => config);\n  });\n}\n\nexport function setSync(newConfig: Record<string, string | boolean>): Config {\n  const config = Config.loadSync();\n  if (Object.keys(newConfig).length === 0) return config;\n  Object.entries(newConfig).forEach(([key, value]) => config.set(key, value));\n  invalidateCache();\n  config.writeSync();\n  return config;\n}\n\nexport function del(keys: string | string[]): Promise<Config> {\n  keys = Array.isArray(keys) ? keys : [keys];\n  return Config.load().then((config) => {\n    for (const k of keys) {\n      config.delete(k);\n    }\n    invalidateCache();\n    return config.write().then(() => config);\n  });\n}\n\nexport function delSync(keys: string | string[]): Config {\n  keys = Array.isArray(keys) ? keys : [keys];\n  const config = Config.loadSync();\n  for (const k of keys) {\n    config.delete(k);\n  }\n  config.writeSync();\n  invalidateCache();\n  return config;\n}\n\nexport async function get(key: string): Promise<string | undefined> {\n  const envVarName = toEnvVariableName(key);\n  if (process.env[envVarName]) {\n    return process.env[envVarName];\n  }\n\n  const config = await (async () => {\n    const configFromCache = cache().get();\n    if (configFromCache) return configFromCache;\n    const config = await Config.load();\n    cache().set(config);\n    return config;\n  })();\n\n  return config ? config.get(key) : null;\n}\n\nexport function getSync(key: string): string | undefined {\n  const envVarName = toEnvVariableName(key);\n  if (process.env[envVarName]) {\n    return process.env[envVarName];\n  }\n\n  const config = (() => {\n    const configFromCache = cache().get();\n    if (configFromCache) return configFromCache;\n    const config = Config.loadSync();\n    cache().set(config);\n    return config;\n  })();\n\n  return config ? config.get(key) : null;\n}\n\nexport function list(): Promise<any> {\n  return Config.load().then((config) => config.toPlainObject());\n}\n\nexport function listSync(): any {\n  const config = Config.loadSync();\n  return config.toPlainObject();\n}\n\nfunction cache() {\n  return {\n    get: () => {\n      // @ts-ignore\n      return cache.config;\n    },\n    set: (config) => {\n      // @ts-ignore\n      cache.config = config;\n    },\n  };\n}\n\nfunction invalidateCache() {\n  cache().set(null);\n}\n\nfunction toEnvVariableName(configName: string): string {\n  return `${ENV_VARIABLE_CONFIG_PREFIX}${configName.replace(/[.-]/g, '_').toUpperCase()}`;\n}\n"
  },
  {
    "path": "packages/legacy/src/logger/getPinoLogger.ts",
    "content": "import pino, { Logger as PinoLogger } from 'pino';\nimport { PATH_DEBUG_LOGS } from '../constants';\n\nexport default function getPinoLogger(\n  logLevel: string,\n  jsonFormat: boolean\n): { pinoLogger: PinoLogger; pinoLoggerConsole: PinoLogger } {\n  // https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#logseverity\n  const PinoLevelToSeverityLookup = {\n    trace: 'DEBUG',\n    debug: 'DEBUG',\n    info: 'INFO',\n    warn: 'WARNING',\n    error: 'ERROR',\n    fatal: 'CRITICAL',\n  };\n\n  const formatters = {\n    level(label: string, number: number) {\n      return {\n        severity: PinoLevelToSeverityLookup[label] || PinoLevelToSeverityLookup.info,\n        level: number,\n      };\n    },\n  };\n\n  /**\n   * by default, Pino expects the first parameter to be an object and the second to be the message\n   * string. since all current log messages were written using Winston, they're flipped - message\n   * first and then other data.\n   * this hook flips the first two arguments, so then it's fine to have the message as the first arg.\n   */\n  const hooks = {\n    logMethod(inputArgs, method) {\n      if (inputArgs.length >= 2 && inputArgs[1] !== undefined) {\n        const arg1 = inputArgs.shift();\n        const arg2 = inputArgs.shift();\n        return method.apply(this, [arg2, arg1]);\n      }\n      return method.apply(this, inputArgs);\n    },\n  };\n\n  const pinoLogger: PinoLogger = pino({\n    hooks,\n    formatters,\n    transport: jsonFormat\n      ? undefined\n      : {\n          target: 'pino-pretty',\n          options: {\n            colorize: true,\n            translateTime: 'SYS:standard',\n            ignore: 'hostname',\n            destination: PATH_DEBUG_LOGS,\n            sync: true,\n          },\n        },\n  });\n  pinoLogger.level = logLevel;\n\n  const pinoLoggerConsole = pino({\n    hooks,\n    formatters,\n    transport: jsonFormat\n      ? undefined\n      : {\n          target: 'pino-pretty',\n          options: {\n            colorize: true,\n            ignore: 'hostname,pid,time,level',\n          },\n        },\n  });\n  pinoLoggerConsole.level = logLevel;\n\n  return { pinoLogger, pinoLoggerConsole };\n}\n"
  },
  {
    "path": "packages/legacy/src/logger/index.ts",
    "content": "import logger from './logger';\nimport printWarning from './printWarning';\n\nexport type { IArcoLogger, LoggerLevel } from './interface';\nexport { printWarning };\nexport default logger;\n"
  },
  {
    "path": "packages/legacy/src/logger/interface.ts",
    "content": "import { Level } from 'pino';\n\nexport interface IArcoLogger {\n  trace(message: string, ...meta: any[]): void;\n\n  debug(message: string, ...meta: any[]): void;\n\n  warn(message: string, ...meta: any[]): void;\n\n  info(message: string, ...meta: any[]): void;\n\n  error(message: string, ...meta: any[]): void;\n\n  fatal(message: string, ...meta: any[]): void;\n\n  console(msg: string): void;\n\n  clearConsole(): void;\n}\n\nexport { Level as LoggerLevel };\n"
  },
  {
    "path": "packages/legacy/src/logger/logger.ts",
    "content": "import yn from 'yn';\nimport chalk from 'chalk';\nimport format from 'string-format';\nimport { Logger as PinoLogger, Level } from 'pino';\n// import { serializeError } from 'serialize-error';\n// import { Analytics } from '../analytics/analytics';\nimport { getSync } from '../globalConfig';\nimport defaultHandleError from '../cli/defaultErrorHandler';\nimport { CFG_LOG_JSON_FORMAT, CFG_LOG_LEVEL } from '../constants';\nimport { Profiler } from './profiler';\nimport getPinoLogger from './getPinoLogger';\nimport { IArcoLogger } from './interface';\n\nconst LEVELS = ['fatal', 'error', 'warn', 'info', 'debug', 'trace'];\n\nfunction isLevel(maybeLevel: Level | string): maybeLevel is Level {\n  return LEVELS.includes(maybeLevel);\n}\n\nfunction getLogLevel(): Level {\n  const defaultLevel = 'debug';\n  const level = getSync(CFG_LOG_LEVEL) || defaultLevel;\n  if (isLevel(level)) return level;\n  const levelsStr = LEVELS.join(', ');\n  console.error(\n    `fatal: level \"${level}\" coming from ${CFG_LOG_LEVEL} configuration is invalid. permitted levels are: ${levelsStr}`\n  );\n  return defaultLevel;\n}\n\n// function addBreadCrumb(category: string, message: string, data: Record<string, any>, extraData) {\n//   data = data || {};\n//   const hashedData = {};\n//   Object.keys(data).forEach((key) => {\n//     hashedData[key] = Analytics.hashData(data[key]);\n//   });\n//   const messageWithHashedData = format(message, hashedData);\n//   extraData = extraData instanceof Error ? serializeError(extraData) : extraData;\n//   Analytics.addBreadCrumb(category, messageWithHashedData, extraData);\n// }\n\nconst logLevel = getLogLevel();\nconst jsonFormat =\n  yn(getSync(CFG_LOG_JSON_FORMAT), { default: false }) ||\n  yn(process.env.JSON_LOGS, { default: false });\n\nconst { pinoLogger, pinoLoggerConsole } = getPinoLogger(logLevel, jsonFormat);\n\n/**\n * the method signatures of debug/info/error/etc are similar to Winston.logger.\n * the way how it is formatted in the log file is according to the `customPrint` function above.\n *\n * Note about logging Error objects (with stacktrace).\n * when throwing an error in the code, it shows it formatted nicely in the log. and also in the console when\n * ARCO_LOG is used.\n * when using logger.error(error), it shows undefined, because it expects a message as the first parameter.\n * when using logger.error(message, error), it shows the error serialized and unclear.\n * normally, no need to call logger.error(). once an error is thrown, it is already logged.\n */\nclass ArcoLogger implements IArcoLogger {\n  private profiler: Profiler;\n\n  logger: PinoLogger;\n\n  /**\n   * CLI is a daemon as it should never exit the process, unless the user kills it\n   */\n  isDaemon = false;\n\n  /**\n   * being set on command-registrar, once the flags are parsed. here, it's a workaround to have\n   * it set before the command-registrar is loaded. at this stage we don't know for sure the \"-j\"\n   * is actually \"json\". that's why this variable is overridden once the command-registrar is up.\n   */\n  shouldWriteToConsole = !process.argv.includes('--json') && !process.argv.includes('-j');\n\n  constructor(logger: PinoLogger) {\n    this.logger = logger;\n    this.profiler = new Profiler();\n  }\n\n  trace(message: string, ...meta: any[]) {\n    this.logger.trace(message, ...meta);\n  }\n\n  debug(message: string, ...meta: any[]) {\n    this.logger.debug(message, ...meta);\n  }\n\n  warn(message: string, ...meta: any[]) {\n    this.logger.warn(message, ...meta);\n  }\n\n  info(message: string, ...meta: any[]) {\n    this.logger.info(message, ...meta);\n  }\n\n  error(message: string, ...meta: any[]) {\n    this.logger.error(message, ...meta);\n  }\n\n  fatal(message: string, ...meta: any[]) {\n    this.logger.fatal(message, ...meta);\n  }\n\n  get isJsonFormat() {\n    return jsonFormat;\n  }\n\n  /**\n   * use this instead of calling `console.log()`, this way it won't break commands that don't\n   * expect output during the execution.\n   */\n  console(msg?: string | Error, level?: Level, color?: string) {\n    level = level || 'info';\n    if (!msg) return;\n\n    let messageStr: string;\n    if (msg instanceof Error) {\n      const { message } = defaultHandleError(msg);\n      messageStr = message;\n    } else {\n      messageStr = msg;\n    }\n\n    if (!this.shouldWriteToConsole) {\n      this[level](messageStr);\n      return;\n    }\n\n    if (color) {\n      try {\n        messageStr = chalk[color](messageStr);\n      } catch (err) {\n        this.trace('a wrong color provided to logger.console method');\n      }\n    }\n    pinoLoggerConsole[level](messageStr);\n  }\n\n  clearConsole() {\n    process.stdout.write(process.platform === 'win32' ? '\\x1B[2J\\x1B[0f' : '\\x1B[2J\\x1B[3J\\x1B[H');\n  }\n\n  /**\n   * useful to get an idea how long it takes from one point in the code to another point.\n   * to use it, choose an id and call `logger.profile(your-id)` before and after the code you want\n   * to measure. e.g.\n   * ```\n   * logger.profile('loadingComponent');\n   * consumer.loadComponent(id);\n   * logger.profile('loadingComponent');\n   * ```\n   * once done, the log writes the time it took to execute the code between the two calls.\n   * if this is a repeated code it also shows how long this code was executed in total.\n   * an example of the output:\n   * [2020-12-04 16:24:46.100 -0500] INFO\t (31641): loadingComponent: 14ms. (total repeating 14ms)\n   * [2020-12-04 16:24:46.110 -0500] INFO\t (31641): loadingComponent: 18ms. (total repeating 32ms)\n   */\n  profile(id: string, console?: boolean) {\n    const msg = this.profiler.profile(id);\n    if (!msg) return;\n    const fullMsg = `${id}: ${msg}`;\n    console ? this.console(fullMsg) : this.info(fullMsg);\n  }\n\n  async exitAfterFlush(code, commandName: string, cliOutput = '') {\n    // await Analytics.sendData();\n    const isSuccess = code === 0;\n    const level = isSuccess ? 'info' : 'error';\n    if (cliOutput) {\n      this.logger.info(`[+] CLI-OUTPUT: ${cliOutput}`);\n    }\n    const msg = isSuccess\n      ? `[*] the command \"${commandName}\" has been completed successfully`\n      : `[*] the command \"${commandName}\" has been terminated with an error code ${code}`;\n    this.logger[level](msg);\n    if (!this.isDaemon) process.exit(code);\n  }\n\n  debugAndAddBreadCrumb(\n    category: string,\n    message: string,\n    data?: Record<string, any>,\n    extraData?: Record<string, any>\n  ) {\n    this.addToLoggerAndToBreadCrumb('debug', category, message, data, extraData);\n  }\n\n  warnAndAddBreadCrumb(\n    category: string,\n    message: string,\n    data?: Record<string, any>,\n    extraData?: Record<string, any>\n  ) {\n    this.addToLoggerAndToBreadCrumb('warn', category, message, data, extraData);\n  }\n\n  errorAndAddBreadCrumb(\n    category: string,\n    message: string,\n    data?: Record<string, any>,\n    extraData?: Record<string, any>\n  ) {\n    this.addToLoggerAndToBreadCrumb('error', category, message, data, extraData);\n  }\n\n  private addToLoggerAndToBreadCrumb(\n    level: string,\n    category: string,\n    message: string,\n    data?: Record<string, any>,\n    extraData?: Record<string, any> | null | undefined\n  ) {\n    if (!category) throw new TypeError('addToLoggerAndToBreadCrumb, category is missing');\n    if (!message) throw new TypeError('addToLoggerAndToBreadCrumb, message is missing');\n    const messageWithData = data ? format(message, data) : message;\n    this.logger[level](`${category}, ${messageWithData}`, extraData);\n    // addBreadCrumb(category, message, data, extraData);\n  }\n\n  switchToConsoleLogger(level?: Level) {\n    this.logger = pinoLoggerConsole;\n    this.logger.level = level || 'debug';\n  }\n}\n\nconst logger = new ArcoLogger(pinoLogger);\n\nexport function writeLogToScreen(levelOrPrefix = '') {\n  if (isLevel(levelOrPrefix)) {\n    logger.switchToConsoleLogger(levelOrPrefix);\n  }\n}\n\n(function determineWritingLogToScreen() {\n  /**\n   * prefix ARCO_LOG to the command, provides the ability to log into the console.\n   * two options are available here:\n   * 1) use the level. e.g. `ARCO_LOG=error arco import`.\n   * 2) use the message prefix, e.g. `ARCO_LOG=ssh arco import`.\n   * 3) use multiple message prefixes, e.g. `ARCO_LOG=ssh,env arco import`.\n   */\n  if (process.env.ARCO_LOG) {\n    writeLogToScreen(process.env.ARCO_LOG);\n    return;\n  }\n\n  // more common scenario is when the user enters `--log` flag. It can be just \"--log\", which defaults to info.\n  // or it can have a level: `--log=error` or `--log error`: both syntaxes are supported\n  if (process.argv.includes('--log')) {\n    const level = process.argv.find((arg) => LEVELS.includes(arg)) as Level | undefined;\n    logger.switchToConsoleLogger(level || 'info');\n    return;\n  }\n  LEVELS.forEach((level) => {\n    if (process.argv.includes(`--log=${level}`)) {\n      logger.switchToConsoleLogger(level as Level);\n    }\n  });\n})();\n\nexport default logger;\n"
  },
  {
    "path": "packages/legacy/src/logger/printWarning.ts",
    "content": "import chalk from 'chalk';\nimport { getSync } from '../globalConfig';\nimport { CFG_NO_WARNINGS } from '../constants';\n\nexport default function printWarning(msg: string) {\n  const cfgNoWarnings = getSync(CFG_NO_WARNINGS);\n  if (cfgNoWarnings !== 'true') {\n    console.log(chalk.yellow(`Warning: ${msg}`));\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/logger/profiler.ts",
    "content": "export class Profiler {\n  profilers: { [id: string]: { current?: number; total?: number } } = {};\n\n  profile(id: string): string {\n    if (!this.profilers[id]) this.profilers[id] = {};\n    const currentProfiler = this.profilers[id];\n    const now = Date.now();\n    if (currentProfiler.current) {\n      const sinceLastCall = now - currentProfiler.current;\n      const total = currentProfiler.total ? currentProfiler.total + sinceLastCall : sinceLastCall;\n      currentProfiler.total = total;\n      delete currentProfiler.current;\n      return `${sinceLastCall}ms. (total repeating ${total}ms)`;\n    }\n    currentProfiler.current = now;\n    return '';\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/prompts/exceptions/index.ts",
    "content": "export { default as PromptCanceled } from './promptCanceled';\n"
  },
  {
    "path": "packages/legacy/src/prompts/exceptions/promptCanceled.ts",
    "content": "import AbstractError from '../../error/abstractError';\n\nexport default class PromptCanceled extends AbstractError {}\n"
  },
  {
    "path": "packages/legacy/src/prompts/index.ts",
    "content": "import prompt from './prompt';\nimport analyticsSchema from './schemas/analyticsReporting';\nimport errorReportingSchema from './schemas/errorReporting';\n\nconst analyticsPrompt = prompt(analyticsSchema);\nconst errorReportingPrompt = prompt(errorReportingSchema);\n\nexport { analyticsPrompt, errorReportingPrompt };\n"
  },
  {
    "path": "packages/legacy/src/prompts/prompt.ts",
    "content": "import prompt, { Properties } from 'prompt';\n\nimport loader from '../cli/loader';\nimport { PromptCanceled } from './exceptions';\n\nconst DEFAULT_PROMPT_MSG = '';\nconst CANCEL_ERROR_MSG = 'canceled';\n\nexport default function (schema: Record<string, any>): () => Promise<Properties> {\n  return function (): Promise<Properties> {\n    return new Promise((resolve, reject) => {\n      loader.stop();\n      prompt.start();\n      prompt.message = DEFAULT_PROMPT_MSG;\n\n      prompt.get(schema, (err, res) => {\n        if (err) {\n          if (err.message === CANCEL_ERROR_MSG) {\n            reject(new PromptCanceled());\n          }\n          return reject(err);\n        }\n        loader.start();\n        return resolve(res);\n      });\n    });\n  };\n}\n"
  },
  {
    "path": "packages/legacy/src/prompts/schemas/analyticsReporting.ts",
    "content": "export default {\n  properties: {\n    analyticsResponse: {\n      required: true,\n      default: 'yes',\n      description: `help us prioritize new features and bug fixes by enabling us to collect anonymous statistics about your usage.\nwould you like to help Arco with anonymous usage analytics? [yes(y)/no(n)]`,\n      message: 'please choose yes or no.',\n      type: 'string',\n      conform(value: string) {\n        return (\n          value.toLowerCase() === 'y' ||\n          value.toLowerCase() === 'n' ||\n          value.toLowerCase() === 'yes' ||\n          value.toLowerCase() === 'no'\n        );\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "packages/legacy/src/prompts/schemas/errorReporting.ts",
    "content": "/**\n * schema for analytics.\n */\nexport default {\n  properties: {\n    errResponse: {\n      required: true,\n      default: 'yes',\n      description:\n        'would you like to share error information to Arco’s error reporting platform? [yes/no]',\n      message: 'please choose yes or no.',\n      type: 'string',\n      conform(value: string) {\n        return (\n          value.toLowerCase() === 'y' ||\n          value.toLowerCase() === 'n' ||\n          value.toLowerCase() === 'yes' ||\n          value.toLowerCase() === 'no'\n        );\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "packages/legacy/src/types.ts",
    "content": "export type APIProperty = {\n  name: string;\n  description: string;\n  required: boolean;\n  type: string;\n  defaultValue?: string;\n  version?: string;\n};\n\nexport type Doclet = {\n  filePath: string;\n  name: string;\n  description?: string;\n  type?: string;\n  args?: Record<string, any>[];\n  returns?: Record<string, any>;\n  properties?: APIProperty[];\n};\n"
  },
  {
    "path": "packages/legacy/src/utils/buildCommandMessage.ts",
    "content": "import { getCliVersion } from './cliVersion';\nimport { PackData } from './packCommand';\n\nexport default function buildCommandMessage(\n  payload: any,\n  context,\n  compress = true,\n  extraHeaders = {}\n): PackData {\n  return {\n    payload,\n    headers: {\n      version: getCliVersion(),\n      compressed: compress,\n      ...extraHeaders,\n      context,\n    },\n  };\n}\n"
  },
  {
    "path": "packages/legacy/src/utils/cliVersion.ts",
    "content": "let cliVersion = null;\n\nexport function setCliVersion(version) {\n  cliVersion = version;\n}\n\nexport function getCliVersion() {\n  return cliVersion;\n}\n"
  },
  {
    "path": "packages/legacy/src/utils/concurrency.ts",
    "content": "const CONCURRENT_IO_LIMIT = 100;\nconst CONCURRENT_COMPONENTS_LIMIT = 50;\nconst CONCURRENT_FETCH_LIMIT = 15;\n\n/**\n * limit number of files to read/write/delete/symlink at the same time\n */\nexport function concurrentIOLimit(): number {\n  return CONCURRENT_IO_LIMIT;\n}\n\n/**\n * limit number of components to load at the same time\n */\nexport function concurrentComponentsLimit(): number {\n  return CONCURRENT_COMPONENTS_LIMIT;\n}\n\n/**\n * limit number of scopes to fetch from at the same time\n */\nexport function concurrentFetchLimit(): number {\n  return CONCURRENT_FETCH_LIMIT;\n}\n"
  },
  {
    "path": "packages/legacy/src/utils/encryption/sha1.ts",
    "content": "import * as crypto from 'crypto';\n\n/**\n * encrypt `data` buffer or string into a sha1 hash\n * @example\n * ```js\n *  sha1('foo bar') // => '3773dea65156909838fa6c22825cafe090ff8030'\n * ```\n */\nexport default function sha1(\n  data: string | Buffer,\n  encoding: crypto.BinaryToTextEncoding = 'hex'\n): string {\n  return crypto.createHash('sha1').update(data).digest(encoding);\n}\n"
  },
  {
    "path": "packages/legacy/src/utils/eol.ts",
    "content": "import { isBinaryFileSync } from 'isbinaryfile';\n\nconst isWindows = typeof process !== 'undefined' && process.platform === 'win32';\nconst lineBreak = isWindows ? '\\r\\n' : '\\n';\nconst newline = /\\r\\n|\\r|\\n/g;\n\nfunction converts(text: string | Buffer, to: string) {\n  if (Buffer.isBuffer(text)) {\n    if (isBinaryFileSync(text)) return text; // don't touch binary files\n    const str = text.toString();\n    const strReplaced = str.replace(newline, to);\n    if (str !== strReplaced) return Buffer.from(strReplaced);\n    return text;\n  }\n  return text.toString().replace(newline, to);\n}\n\nexport function lf(text: string | Buffer) {\n  return converts(text, '\\n');\n}\n\nexport function auto(text: string | Buffer) {\n  return converts(text, lineBreak);\n}\n\nexport function cr(text: string | Buffer) {\n  return converts(text, '\\r');\n}\n\nexport function crlf(text: string | Buffer) {\n  return converts(text, '\\r\\n');\n}\n"
  },
  {
    "path": "packages/legacy/src/utils/fs/isDirEmpty.ts",
    "content": "import readDirIgnoreDsStore from './readDirIgnoreDsStore';\n\nexport default async function isDirEmpty(dirPath: string): Promise<boolean> {\n  const files = await readDirIgnoreDsStore(dirPath);\n  return !files.length;\n}\n"
  },
  {
    "path": "packages/legacy/src/utils/fs/readDirIgnoreDsStore.ts",
    "content": "import fs from 'fs-extra';\n\nexport default async function readDirIgnoreDsStore(dirPath: string): Promise<string[]> {\n  const files = await fs.readdir(dirPath);\n  return files.filter((file) => file !== '.DS_Store');\n}\n\nexport function readDirSyncIgnoreDsStore(dirPath: string): string[] {\n  const files = fs.readdirSync(dirPath);\n  return files.filter((file) => file !== '.DS_Store');\n}\n"
  },
  {
    "path": "packages/legacy/src/utils/fs/removeEmptyDir.ts",
    "content": "import fs from 'fs-extra';\nimport isDirEmpty from './isDirEmpty';\nimport logger from '../../logger/logger';\n\nexport default async function removeEmptyDir(dirPath: string): Promise<boolean> {\n  let isEmpty: boolean;\n  try {\n    isEmpty = await isDirEmpty(dirPath);\n  } catch (err: any) {\n    if (err.code === 'ENOENT') return false;\n    throw err;\n  }\n  if (isEmpty) {\n    logger.info(`remove-empty-dir, deleting ${dirPath}`);\n    await fs.remove(dirPath);\n    return true;\n  }\n  return false;\n}\n"
  },
  {
    "path": "packages/legacy/src/utils/fs/removeFilesAndEmptyDirsRecursively.ts",
    "content": "import fs from 'fs-extra';\nimport pMap from 'p-map';\nimport mapSeries from 'p-map-series';\nimport * as path from 'path';\nimport logger from '../../logger/logger';\nimport removeEmptyDir from './removeEmptyDir';\nimport { concurrentIOLimit } from '../concurrency';\n\n/**\n * This function will remove the list of files from fs\n * Then go to the folder of each file and remove it as well if it's empty\n */\nexport default async function removeFilesAndEmptyDirsRecursively(\n  filesPaths: string[]\n): Promise<boolean> {\n  const dirs = filesPaths.map((filePath) => path.dirname(filePath));\n  logger.info(\n    `remove-files-and-empty-dirs-recursively deleting the following paths: ${filesPaths.join(', ')}`\n  );\n  const concurrency = concurrentIOLimit();\n  await pMap(filesPaths, (filePath) => fs.remove(filePath), { concurrency });\n  // Sorting it to make sure we will delete the inner dirs first\n  const sortedDirs = dirs.sort().reverse();\n  await mapSeries(sortedDirs, (dir) => removeEmptyDir(dir));\n  return true;\n}\n"
  },
  {
    "path": "packages/legacy/src/utils/fs/zipFiles.ts",
    "content": "import fs from 'fs-extra';\nimport archiver from 'archiver';\n\nexport function zipFiles(options: {\n  sourceDir?: string;\n  sourceGlob?: string;\n  targetPath: string;\n}): Promise<{ size: number; path: string }> {\n  return new Promise((resolve, reject) => {\n    const { sourceDir, sourceGlob, targetPath } = options;\n    const output = fs.createWriteStream(targetPath);\n    const archive = archiver('zip', {\n      zlib: { level: 9 },\n    });\n\n    output.on('close', () => {\n      const size = archive.pointer();\n      resolve({\n        size,\n        path: targetPath,\n      });\n    });\n\n    archive.on('error', (error) => reject(error));\n    archive.pipe(output);\n\n    if (sourceDir) {\n      if (fs.existsSync(sourceDir)) {\n        archive.directory(sourceDir, false);\n      } else {\n        reject(new Error(`source directory ${sourceDir} does not exist`));\n      }\n    }\n\n    sourceGlob && archive.glob(sourceGlob);\n    archive.finalize();\n  });\n}\n"
  },
  {
    "path": "packages/legacy/src/utils/ignore.ts",
    "content": "import ignore from 'ignore';\nimport fs from 'fs-extra';\nimport findUp from 'find-up';\nimport parseGitignore from 'parse-gitignore';\nimport { GIT_IGNORE, IGNORE_LIST, PACKAGE_JSON } from '../constants';\n\nfunction getIgnoreListForArco(consumerPath: string): string[] {\n  const ignoreList = retrieveIgnoreList(consumerPath);\n  ignoreList.push(PACKAGE_JSON);\n  return ignoreList;\n}\n\nexport function getGitIgnoreFile(dir: string) {\n  const gitIgnoreFile = findUp.sync([GIT_IGNORE], { cwd: dir });\n  return gitIgnoreFile ? parseGitignore(fs.readFileSync(gitIgnoreFile)) : [];\n}\n\nexport function retrieveIgnoreList(cwd: string) {\n  const ignoreList = getGitIgnoreFile(cwd).concat(IGNORE_LIST);\n  return ignoreList;\n}\n\nexport function getGitIgnoreForArco(consumerPath: string): any {\n  const ignoreList = getIgnoreListForArco(consumerPath);\n  return ignore().add(ignoreList);\n}\n"
  },
  {
    "path": "packages/legacy/src/utils/index.ts",
    "content": "import mapToObject from './map/toObject';\nimport isNumeric from './number/isNumeric';\nimport toBase64 from './string/toBase64';\nimport toFsCompatible from './string/toFsCompatible';\nimport buildCommandMessage from './buildCommandMessage';\nimport packCommand from './packCommand';\nimport sha1 from './encryption/sha1';\nimport { getCliVersion, setCliVersion } from './cliVersion';\nimport { TaskManager } from './taskManager';\nimport * as eol from './eol';\n\nexport {\n  mapToObject,\n  isNumeric,\n  toBase64,\n  toFsCompatible,\n  buildCommandMessage,\n  packCommand,\n  sha1,\n  eol,\n  setCliVersion,\n  getCliVersion,\n  TaskManager,\n};\n"
  },
  {
    "path": "packages/legacy/src/utils/map/toObject.ts",
    "content": "/**\n * Cast a `Map` to a plain object.\n * Keys are being cast by invoking `toString` on each key.\n */\nexport default function mapToObject(map: Map<any, any>): Record<string, any> {\n  const object = {};\n  map.forEach((val, key) => {\n    object[key.toString()] = val;\n  });\n  return object;\n}\n"
  },
  {
    "path": "packages/legacy/src/utils/mapToObject.ts",
    "content": ""
  },
  {
    "path": "packages/legacy/src/utils/network/port.ts",
    "content": "import net from 'net';\n\nclass PortLockedError extends Error {\n  constructor(port: number) {\n    super(`${port} is locked`);\n  }\n}\n\nexport class Port {\n  async get(options: { port: number | Iterable<number>; usedPort?: number[] }): Promise<number> {\n    const lockedPorts = {\n      old: new Set(),\n      young: new Set(),\n    };\n\n    const portCheckSequence = function* (ports: any) {\n      if (ports) {\n        yield* ports;\n      }\n\n      yield 0;\n    };\n\n    let ports: any;\n    const releaseOldLockedPortsIntervalMs = 1000 * 15;\n\n    // Lazily create interval on first use\n    let interval: any;\n\n    if (options) {\n      ports = typeof options.port === 'number' ? [options.port] : options.port;\n    }\n\n    if (interval === undefined) {\n      interval = setInterval(() => {\n        lockedPorts.old = lockedPorts.young;\n        lockedPorts.young = new Set();\n      }, releaseOldLockedPortsIntervalMs);\n\n      // Does not exist in some environments (Electron, Jest jsdom env, browser, etc).\n      if (interval.unref) {\n        interval.unref();\n      }\n    }\n\n    for (const port of portCheckSequence(ports)) {\n      try {\n        if (options.usedPort?.includes(port)) throw new PortLockedError(port);\n        let availablePort = await this.getAvailablePort({ ...options, port }); // eslint-disable-line no-await-in-loop\n        while (lockedPorts.old.has(availablePort) || lockedPorts.young.has(availablePort)) {\n          if (port !== 0) {\n            throw new PortLockedError(port);\n          }\n\n          availablePort = await this.getAvailablePort({ ...options, port }); // eslint-disable-line no-await-in-loop\n        }\n\n        lockedPorts.young.add(availablePort);\n\n        return availablePort;\n      } catch (error: any) {\n        if (!['EADDRINUSE', 'EACCES'].includes(error.code) && !(error instanceof PortLockedError)) {\n          throw error;\n        }\n      }\n    }\n\n    throw new Error('No available ports found');\n  }\n\n  private async getAvailablePort(options: any): Promise<number> {\n    return new Promise((resolve, reject) => {\n      const server = net.createServer();\n      server.unref();\n      server.on('error', reject);\n      server.listen(options, () => {\n        const serverInfo = server.address();\n        server.close(() => {\n          // @ts-ignore\n          resolve(serverInfo?.port);\n        });\n      });\n    });\n  }\n\n  private makeRange(from: number, to: number) {\n    if (!Number.isInteger(from) || !Number.isInteger(to)) {\n      throw new TypeError('`from` and `to` must be integer numbers');\n    }\n\n    if (from < 1024 || from > 65535) {\n      throw new RangeError('`from` must be between 1024 and 65535');\n    }\n\n    if (to < 1024 || to > 65536) {\n      throw new RangeError('`to` must be between 1024 and 65536');\n    }\n\n    if (to < from) {\n      throw new RangeError('`to` must be greater than or equal to `from`');\n    }\n\n    const generator = function* (f: number, t: number) {\n      for (let port = f; port <= t; port += 1) {\n        yield port;\n      }\n    };\n\n    return generator(from, to);\n  }\n\n  static getPort(from: number, to: number, usedPort?: number[]) {\n    const port = new Port();\n    const range = port.makeRange(from, to);\n    return port.get({ port: range, usedPort });\n  }\n\n  static getPortFromRange(range: number[] | number, usedPort?: number[]) {\n    const port = new Port();\n    const portsRange = typeof range === 'number' ? [range] : port.makeRange(range[0], range[1]);\n    return port.get({ port: portsRange, usedPort });\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/utils/number/isNumeric.ts",
    "content": "/**\n * determines whether `val` is a numeric value\n */\nexport default function isNumeric(val: any) {\n  return !Number.isNaN(parseFloat(val)) && Number.isFinite(val);\n}\n"
  },
  {
    "path": "packages/legacy/src/utils/packCommand.ts",
    "content": "import zlib from 'zlib';\nimport toBase64 from './string/toBase64';\n\nexport type PackData = { payload: any; headers: any };\n\nexport default function packCommand(obj: PackData, base64 = true, compress = true): string {\n  if (compress) {\n    if (obj.payload) {\n      obj.payload = zlib.deflateSync(JSON.stringify(obj.payload));\n    }\n\n    if (obj.headers && obj.headers.context) {\n      obj.headers.context = zlib.deflateSync(JSON.stringify(obj.headers.context));\n    }\n  }\n\n  return base64 ? toBase64(JSON.stringify(obj)) : JSON.stringify(obj);\n}\n"
  },
  {
    "path": "packages/legacy/src/utils/path.ts",
    "content": "import normalize from 'normalize-path';\nimport { sep as pathSep } from 'path';\n\nexport function pathNormalizeToLinux(pathToNormalize?: string): string {\n  return pathToNormalize ? normalize(pathToNormalize) : pathToNormalize;\n}\n\nexport function toWindowsCompatiblePath(path: string): string {\n  return typeof path === 'string' ? path.replace(/\\\\/g, '\\\\\\\\') : '';\n}\n\nexport function isParentDir(parent: string, child: string) {\n  parent = parent.replace(/^\\/$/, '');\n  child = child.replace(/^\\/$/, '');\n  return parent && child && parent !== child && child.startsWith(parent);\n}\n\nexport function buildPropagationPaths(absPath: string, endPath?: string): string[] {\n  endPath = endPath?.replace(/\\/$/, '') || '';\n\n  const paths: string[] = [];\n  const pathParts = absPath.split(pathSep);\n\n  pathParts.forEach((_, index) => {\n    const part = pathParts.slice(0, index + 1).join('/');\n    if (!part || isParentDir(part, endPath)) return;\n    paths.push(part);\n  });\n\n  return paths.reverse();\n}\n"
  },
  {
    "path": "packages/legacy/src/utils/regexp/style.ts",
    "content": "// style files regexps\n\n// css\nexport const cssRegex = /\\.css$/;\n// css regex - will catch .css but not .module.css\nexport const cssNoModulesRegex = /(?<!\\.module)\\.css$/;\nexport const cssModuleRegex = /\\.module\\.css$/;\n\n// sass | scss\nexport const sassRegex = /\\.(scss|sass)$/;\n// scss|sass regex - will catch .scss|sass but not .module.scss|sass\nexport const sassNoModuleRegex = /(?<!\\.module)\\.(scss|sass)$/;\nexport const sassModuleRegex = /\\.module\\.(scss|sass)$/;\n\n// less\nexport const lessRegex = /\\.less$/;\n// less regex - will catch .less but not .module.less\nexport const lessNoModuleRegex = /(?<!\\.module)\\.less$/;\nexport const lessModuleRegex = /\\.module\\.less$/;\n"
  },
  {
    "path": "packages/legacy/src/utils/string/toBase64.ts",
    "content": "/**\n * encode a string or a buffer to base64\n * @example\n * ```js\n *  toBase64('foo bar') // => Zm9vIGJhcg==\n *  toBase64(Buffer.from('foo bar')) // => Zm9vIGJhcg==\n * ```\n */\nexport default function toBase64(val: string | Buffer) {\n  return (val instanceof Buffer ? val : Buffer.from(val)).toString('base64');\n}\n"
  },
  {
    "path": "packages/legacy/src/utils/string/toFsCompatible.ts",
    "content": "export default function toFsCompatible(str: string) {\n  return typeof str === 'string' ? str.replace(/[-\\/.]/g, '_') : str;\n}\n"
  },
  {
    "path": "packages/legacy/src/utils/taskManager.ts",
    "content": "type TaskType = () => Promise<any>;\n\nexport class TaskManager {\n  parallelTaskCount = 1;\n\n  runningTaskCount = 0;\n\n  tasks: TaskType[] = [];\n\n  triggerQueue: ((_?) => void)[] = [];\n\n  triggerEnd = (_?) => {};\n\n  constructor(params: { parallelTaskCount?: number; tasks?: TaskType[] }) {\n    const { parallelTaskCount, tasks } = params;\n    this.tasks = tasks;\n    this.parallelTaskCount = parallelTaskCount;\n  }\n\n  runAll() {\n    return new Promise((resolve) => {\n      while (this.tasks.length) {\n        this.next();\n      }\n      this.triggerEnd = resolve;\n      this.runAll = () => null;\n    });\n  }\n\n  private next() {\n    const task = this.tasks.shift();\n    if (task) {\n      if (this.runningTaskCount < this.parallelTaskCount) {\n        this.runningTaskCount++;\n        task().finally(() => this.onTaskDone());\n      } else {\n        new Promise((resolve) => {\n          this.triggerQueue.push(resolve);\n        })\n          .then(() => {\n            return task();\n          })\n          .finally(() => this.onTaskDone());\n      }\n    }\n  }\n\n  private onTaskDone() {\n    this.runningTaskCount--;\n    const nextTrigger = this.triggerQueue.shift();\n\n    if (nextTrigger) {\n      this.runningTaskCount++;\n      nextTrigger();\n    }\n\n    if (this.runningTaskCount === 0) {\n      this.triggerEnd();\n    }\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/utils/timer/exceptions/index.ts",
    "content": "export { TimerAlreadyRunningError } from './timerAlreadyRunningError';\nexport { TimerNotStartedError } from './timerNotStartedError';\n"
  },
  {
    "path": "packages/legacy/src/utils/timer/exceptions/timerAlreadyRunningError.ts",
    "content": "export class TimerAlreadyRunningError extends Error {\n  constructor() {\n    super('timer already running');\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/utils/timer/exceptions/timerNotStartedError.ts",
    "content": "export class TimerNotStartedError extends Error {\n  constructor() {\n    super('timer not started');\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/utils/timer/index.ts",
    "content": "export { Timer } from './timer';\nexport { TimerResponse } from './response';\n"
  },
  {
    "path": "packages/legacy/src/utils/timer/response.ts",
    "content": "export class TimerResponse {\n  constructor(\n    /**\n     * elapsed time in milliseconds.\n     */\n    readonly elapsed: number\n  ) {}\n\n  /**\n   * elapsed time in seconds\\.\n   */\n  get seconds() {\n    return this.elapsed / 1000;\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/utils/timer/timer.ts",
    "content": "import { TimerAlreadyRunningError, TimerNotStartedError } from './exceptions';\nimport { TimerResponse } from './response';\n\nexport class Timer {\n  private startTime: number | null = null;\n\n  start(): Timer {\n    if (this.startTime) throw new TimerAlreadyRunningError();\n    this.startTime = Date.now();\n    return this;\n  }\n\n  stop(): TimerResponse {\n    if (!this.startTime) throw new TimerNotStartedError();\n    const endTime = Date.now();\n    return new TimerResponse(this.calculateElapsed(this.startTime, endTime));\n  }\n\n  private calculateElapsed(startTime: number, endTime: number) {\n    return endTime - startTime;\n  }\n\n  static create() {\n    return new Timer();\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/workspace/component/dependencies/detectives/detectiveEs6.ts",
    "content": "import { Specifier } from '../types/dependencyTreeType';\nimport {\n  getDependenciesFromCallExpression,\n  getDependenciesFromMemberExpression,\n  getSpecifierValueForImportDeclaration,\n} from './parserHelper';\n\n// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst Walker = require('node-source-walk');\n\n/**\n * Extracts the dependencies of the supplied es6 module\n *\n * @param  {String|Object} src - File's content or AST\n * @return {String[]}\n */\nexport default function (src): { [dependency: string]: { importSpecifiers: Specifier[] } } {\n  const walker = new Walker();\n\n  const dependencies = {};\n  const addDependency = (dependency: string) => {\n    if (!dependencies[dependency]) {\n      dependencies[dependency] = {};\n    }\n  };\n  const addImportSpecifier = (dependency: string, importSpecifier: Specifier) => {\n    if (dependencies[dependency].importSpecifiers) {\n      dependencies[dependency].importSpecifiers.push(importSpecifier);\n    } else {\n      dependencies[dependency].importSpecifiers = [importSpecifier];\n    }\n  };\n  const addExportedToImportSpecifier = (name: string) => {\n    Object.keys(dependencies).forEach((dependency) => {\n      if (!dependencies[dependency].importSpecifiers) return;\n      const specifier = dependencies[dependency].importSpecifiers.find((i) => i.name === name);\n      if (specifier) specifier.exported = true;\n    });\n  };\n\n  if (typeof src === 'undefined') {\n    throw new Error('src not given');\n  }\n\n  if (src === '') {\n    return dependencies;\n  }\n\n  walker.walk(src, function (node) {\n    switch (node.type) {\n      case 'ImportDeclaration':\n        if (node.source && node.source.value) {\n          const dependency = node.source.value;\n          addDependency(dependency);\n          node.specifiers.forEach((specifier) => {\n            const specifierValue = getSpecifierValueForImportDeclaration(specifier);\n            addImportSpecifier(dependency, specifierValue);\n          });\n        }\n        break;\n      case 'ExportNamedDeclaration':\n      case 'ExportAllDeclaration':\n        if (node.source && node.source.value) {\n          const dependency = node.source.value;\n          addDependency(dependency);\n          if (node.specifiers) {\n            // in case of \"export * from\" there are no node.specifiers\n            node.specifiers.forEach((specifier) => {\n              const specifierValue = {\n                isDefault: !specifier.local || specifier.local.name === 'default', // e.g. export { default as isArray } from './is-array';\n                name: specifier.exported.name,\n                exported: true,\n              };\n              addImportSpecifier(dependency, specifierValue);\n            });\n          }\n        } else if (node.specifiers && node.specifiers.length) {\n          node.specifiers.forEach((exportSpecifier) => {\n            addExportedToImportSpecifier(exportSpecifier.exported.name);\n          });\n        }\n        break;\n      case 'ExportDefaultDeclaration':\n        addExportedToImportSpecifier(node.declaration.name);\n        break;\n      case 'ImportExpression': {\n        // node represents Dynamic Imports such as import(source)\n        if (node.source?.value) addDependency(node.source?.value);\n        break;\n      }\n      case 'CallExpression':\n        {\n          const value = getDependenciesFromCallExpression(node);\n          if (value) addDependency(value);\n        }\n        break;\n      case 'MemberExpression':\n        {\n          const value = getDependenciesFromMemberExpression(node);\n          if (value) addDependency(value);\n        }\n        break;\n      default:\n        break;\n    }\n  });\n\n  return dependencies;\n}\n"
  },
  {
    "path": "packages/legacy/src/workspace/component/dependencies/detectives/index.ts",
    "content": "export { default as detectiveEs6 } from './detectiveEs6';\n"
  },
  {
    "path": "packages/legacy/src/workspace/component/dependencies/detectives/parserHelper.ts",
    "content": "import { Specifier } from '../types/dependencyTreeType';\n\nexport function getDependenciesFromMemberExpression(node) {\n  if (\n    node.object.type === 'CallExpression' &&\n    node.object.callee.type === 'Identifier' &&\n    node.object.callee.name === 'require' &&\n    node.object.arguments &&\n    node.object.arguments.length\n  ) {\n    return getStringValue(node.object.arguments[0]);\n  }\n  return null;\n}\n\nexport function getDependenciesFromCallExpression(node) {\n  if (node.callee.type === 'Import' && node.arguments.length && node.arguments[0].value) {\n    return node.arguments[0].value;\n  }\n  if (\n    node.callee.type === 'Identifier' && // taken from detective-cjs\n    node.callee.name === 'require' &&\n    node.arguments &&\n    node.arguments.length\n  ) {\n    return getStringValue(node.arguments[0]);\n  }\n  return null;\n}\n\nexport function getSpecifierValueForImportDeclaration(specifier): Specifier {\n  return {\n    isDefault: specifier.type === 'ImportDefaultSpecifier',\n    // syntax of `import x from 'file'` doesn't have specifier.imported, only specifier.local\n    // syntax of `import { x as y } from 'file'`, has `x` as specifier.imported and `y` as\n    // specifier.local. we interested in `x` in this case.\n    name: specifier.imported ? specifier.imported.name : specifier.local.name,\n  };\n}\n\nfunction getStringValue(node) {\n  // using single or double quotes (', \")\n  if (node.type === 'Literal' || node.type === 'StringLiteral') {\n    return node.value;\n  }\n  // using apostrophe (`)\n  if (\n    node.type === 'TemplateLiteral' &&\n    node.quasis &&\n    node.quasis.length &&\n    node.quasis[0].type === 'TemplateElement'\n  ) {\n    return node.quasis[0].value.raw;\n  }\n  return null;\n}\n"
  },
  {
    "path": "packages/legacy/src/workspace/component/dependencies/types/dependencyTreeType.ts",
    "content": "/**\n * Import Specifier data.\n * For example, `import foo from './bar' `, \"foo\" is the import-specifier and is default.\n * Conversely, `import { foo } from './bar' `, here, \"foo\" is non-default.\n */\nexport type Specifier = {\n  isDefault: boolean;\n  name: string;\n  exported?: boolean;\n};\n"
  },
  {
    "path": "packages/legacy/src/workspace/component/exceptions/componentNotFoundInPathError.ts",
    "content": "import chalk from 'chalk';\nimport ArcoError from '../../../error/arcoError';\n\nexport class ComponentNotFoundInPathError extends ArcoError {\n  path: string;\n\n  code: number;\n\n  constructor(path: string) {\n    super(`error: component in path \"${chalk.bold(path)}\" was not found`);\n    this.code = 127;\n    this.path = path;\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/workspace/component/exceptions/fileSourceNotFoundError.ts",
    "content": "import AbstractError from '../../../error/abstractError';\n\nexport class FileSourceNotFoundError extends AbstractError {\n  path: string;\n\n  constructor(path: string) {\n    super();\n    this.path = path;\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/workspace/component/exceptions/index.ts",
    "content": "export { FileSourceNotFoundError } from './fileSourceNotFoundError';\nexport { ComponentNotFoundInPathError } from './componentNotFoundInPathError';\n"
  },
  {
    "path": "packages/legacy/src/workspace/component/sources/abstractVinyl.ts",
    "content": "import fs from 'fs-extra';\nimport Vinyl from 'vinyl';\nimport * as path from 'path';\n\nimport { FileConstructor } from './vinylTypes';\nimport { eol } from '../../../utils';\nimport logger from '../../../logger/logger';\n\ntype AbstractVinylProps = {\n  cwd: string;\n  path: string;\n  base: string;\n  contents: Buffer;\n};\n\nexport default class AbstractVinyl extends (Vinyl as FileConstructor) {\n  override = true;\n\n  verbose = false;\n\n  static fromVinyl(vinyl: Vinyl): AbstractVinyl {\n    if (vinyl instanceof AbstractVinyl) return vinyl;\n    return new AbstractVinyl(vinyl);\n  }\n\n  get relativeDir() {\n    return path.dirname(this.relative);\n  }\n\n  // Update the base path and keep the relative value to be the same\n  updatePaths({\n    newBase,\n    newRelative,\n    newCwd,\n  }: {\n    newBase?: string;\n    newRelative?: string;\n    newCwd?: string;\n  }) {\n    const relative = newRelative || this.relative;\n    const base = newBase || this.base;\n    if (newCwd) this.cwd = newCwd;\n    this.base = base;\n    this.path = path.join(this.base, relative);\n  }\n\n  async write(\n    writePath?: string,\n    override: boolean = this.override,\n    verbose: boolean = this.verbose\n  ): Promise<string | null | undefined> {\n    const filePath = writePath || this.path;\n    const msg = _verboseMsg(filePath, override);\n    if (verbose) {\n      console.log(msg);\n    }\n    logger.debug(msg);\n    if (!override && fs.existsSync(filePath)) return null;\n    await fs.outputFile(filePath, eol.auto(this.contents));\n    return filePath;\n  }\n\n  toReadableString() {\n    return {\n      relativePath: this.relative,\n      content: this.contents.toString(),\n    };\n  }\n\n  static loadFromParsedStringBase(parsedString: any): AbstractVinylProps {\n    const contents = Buffer.isBuffer(parsedString._contents)\n      ? parsedString._contents\n      : Buffer.from(parsedString._contents);\n    return {\n      cwd: parsedString._cwd,\n      path: parsedString.history[parsedString.history.length - 1],\n      base: parsedString._base,\n      contents,\n    };\n  }\n\n  async _getStatIfFileExists(): Promise<fs.Stats | null | undefined> {\n    try {\n      return await fs.lstat(this.path);\n    } catch (err: any) {\n      return null; // probably file does not exist\n    }\n  }\n}\n\n/**\n * Generate message for the logs and for output in case of verbose\n * this function is exported for testing purposes\n */\nexport function _verboseMsg(filePath: string, force: boolean) {\n  const msg = `writing a file to the file-system at ${filePath}, force: ${force.toString()}`;\n  return msg;\n}\n"
  },
  {
    "path": "packages/legacy/src/workspace/component/sources/dataToPersist.ts",
    "content": "import Bluebird from 'bluebird';\nimport * as path from 'path';\nimport logger from '../../../logger/logger';\nimport AbstractVinyl from './abstractVinyl';\nimport RemovePath from './removePath';\nimport { concurrentIOLimit } from '../../../utils/concurrency';\nimport removeFilesAndEmptyDirsRecursively from '../../../utils/fs/removeFilesAndEmptyDirsRecursively';\n\nexport default class DataToPersist {\n  files: AbstractVinyl[];\n\n  remove: RemovePath[];\n\n  constructor() {\n    this.files = [];\n    this.remove = [];\n  }\n\n  addFile(file: AbstractVinyl) {\n    if (!file) throw new Error('failed adding an empty file into DataToPersist');\n    if (!file.path) {\n      throw new Error(\n        'failed adding a file into DataToPersist as it does not have a path property'\n      );\n    }\n    const existingFileIndex = this.files.findIndex(\n      (existingFile) => existingFile.path === file.path\n    );\n    if (existingFileIndex !== -1) {\n      if (file.override) {\n        this.files.splice(existingFileIndex, 1);\n      } else {\n        // don't push this one. keep the existing file\n        return;\n      }\n    }\n    this.throwForDirectoryCollision(file);\n    this.files.push(file);\n  }\n\n  addManyFiles(files: AbstractVinyl[] = []) {\n    files.forEach((file) => this.addFile(file));\n  }\n\n  removePath(pathToRemove: RemovePath) {\n    if (!pathToRemove) throw new Error('failed adding a path to remove into DataToPersist');\n    if (!this.remove.includes(pathToRemove)) {\n      this.remove.push(pathToRemove);\n    }\n  }\n\n  removeManyPaths(pathsToRemove: RemovePath[] = []) {\n    pathsToRemove.forEach((pathToRemove) => this.removePath(pathToRemove));\n  }\n\n  merge(dataToPersist: DataToPersist | null | undefined) {\n    if (!dataToPersist) return;\n    this.addManyFiles(dataToPersist.files);\n    this.removeManyPaths(dataToPersist.remove);\n  }\n\n  async persistAllToFS() {\n    this.log();\n    this.validateAbsolute();\n    // the order is super important. first remove, then create and finally symlink\n    await this.deletePathsFromFS();\n    await this.persistFilesToFS();\n  }\n\n  addBasePath(basePath: string) {\n    this.files.forEach((file) => {\n      this.assertRelative(file.base);\n      file.updatePaths({ newBase: path.join(basePath, file.base) });\n    });\n    this.remove.forEach((removePath) => {\n      this.assertRelative(removePath.path);\n      removePath.path = path.join(basePath, removePath.path);\n    });\n  }\n\n  /**\n   * helps for debugging\n   */\n  toConsole() {\n    console.log(`\\nfiles: ${this.files.map((f) => f.path).join('\\n')}`);\n    console.log(`remove: ${this.remove.map((r) => r.path).join('\\n')}`);\n  }\n\n  filterByPath(filterFunc: (p: string) => boolean): DataToPersist {\n    const dataToPersist = new DataToPersist();\n    dataToPersist.addManyFiles(this.files.filter((f) => filterFunc(f.path)));\n    dataToPersist.removeManyPaths(this.remove.filter((r) => filterFunc(r.path)));\n    return dataToPersist;\n  }\n\n  private async persistFilesToFS() {\n    const concurrency = concurrentIOLimit();\n    return Bluebird.map(this.files, (file) => file.write(), { concurrency });\n  }\n\n  private async deletePathsFromFS() {\n    const pathWithRemoveItsDirIfEmptyEnabled = this.remove\n      .filter((p) => p.removeItsDirIfEmpty)\n      .map((p) => p.path);\n    const restPaths = this.remove.filter((p) => !p.removeItsDirIfEmpty);\n    if (pathWithRemoveItsDirIfEmptyEnabled.length) {\n      await removeFilesAndEmptyDirsRecursively(pathWithRemoveItsDirIfEmptyEnabled);\n    }\n    const concurrency = concurrentIOLimit();\n    return Bluebird.map(restPaths, (removePath) => removePath.persistToFS(), { concurrency });\n  }\n\n  private validateAbsolute() {\n    // it's important to make sure that all paths are absolute before writing them to the\n    // filesystem. relative paths won't work when running arco commands from an inner dir\n    const validateAbsolutePath = (pathToValidate) => {\n      if (!path.isAbsolute(pathToValidate)) {\n        throw new Error(`DataToPersist expects ${pathToValidate} to be absolute, got relative`);\n      }\n    };\n    this.files.forEach((file) => {\n      validateAbsolutePath(file.path);\n    });\n    this.remove.forEach((removePath) => {\n      validateAbsolutePath(removePath.path);\n    });\n  }\n\n  private log() {\n    if (this.remove.length) {\n      const pathToDeleteStr = this.remove.map((r) => r.path).join('\\n');\n      logger.debug(`DataToPersist, paths-to-delete:\\n${pathToDeleteStr}`);\n    }\n    if (this.files.length) {\n      const filesToWriteStr = this.files.map((f) => f.path).join('\\n');\n      logger.debug(`DataToPersist, paths-to-write:\\n${filesToWriteStr}`);\n    }\n  }\n\n  private assertRelative(pathToCheck: string) {\n    if (path.isAbsolute(pathToCheck)) {\n      throw new Error(`DataToPersist expects ${pathToCheck} to be relative, but found it absolute`);\n    }\n  }\n\n  /**\n   * prevent adding a file which later on will cause an error \"EEXIST: file already exists, mkdir {dirname}\".\n   * this happens one a file is a directory name of the other file.\n   * e.g. adding these two files, will cause the error above: \"bar/foo\" and \"bar\"\n   *\n   * to check for this possibility, we need to consider two scenarios:\n   * 1) \"bar/foo\" is there and now adding \"bar\" => check whether one of the files starts with \"bar/\"\n   * 2) \"bar\" is there and now adding \"bar/foo\" => check whether this file \"bar/foo\" starts with one of the files with '/'\n   * practically, it runs `(\"bar/foo\".startsWith(\"bar/\"))` for both cases above.\n   */\n  private throwForDirectoryCollision(file: AbstractVinyl) {\n    const directoryCollision = this.files.find(\n      (f) =>\n        f.path.startsWith(`${file.path}${path.sep}`) ||\n        `${file.path}`.startsWith(`${f.path}${path.sep}`)\n    );\n    if (directoryCollision) {\n      throw new Error(`unable to add the file \"${file.path}\", because another file \"${directoryCollision.path}\" is going to be written.\none of them is a directory of the other one, and is not possible to have them both`);\n    }\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/workspace/component/sources/dist.ts",
    "content": "import AbstractVinyl from './abstractVinyl';\n\nexport default class Dist extends AbstractVinyl {\n  static loadFromParsedString(parsedString: Record<string, any>): Dist | null {\n    if (!parsedString) return null;\n    const opts = super.loadFromParsedStringBase(parsedString);\n    return new Dist(opts);\n  }\n\n  static loadFromParsedStringArray(arr: Record<string, any>[]): Dist[] | null {\n    return arr ? arr.map(this.loadFromParsedString) : null;\n  }\n\n  clone(_opts?: { contents?: boolean; deep?: boolean } | boolean): this {\n    // @ts-ignore\n    return new Dist(this);\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/workspace/component/sources/index.ts",
    "content": "import AbstractVinyl from './abstractVinyl';\nimport Dist from './dist';\nimport DataToPersist from './dataToPersist';\nimport RemovePath from './removePath';\nimport SourceFile from './sourceFile';\n\nexport { AbstractVinyl, Dist, DataToPersist, RemovePath, SourceFile };\n"
  },
  {
    "path": "packages/legacy/src/workspace/component/sources/removePath.ts",
    "content": "import fs from 'fs-extra';\nimport removeFilesAndEmptyDirsRecursively from '../../../utils/fs/removeFilesAndEmptyDirsRecursively';\n\nexport default class RemovePath {\n  path: string;\n\n  removeItsDirIfEmpty: boolean;\n\n  constructor(path: string, removeItsDirIfEmpty = false) {\n    this.path = path;\n    this.removeItsDirIfEmpty = removeItsDirIfEmpty;\n  }\n\n  async persistToFS() {\n    if (this.removeItsDirIfEmpty) {\n      return removeFilesAndEmptyDirsRecursively([this.path]);\n    }\n    return fs.remove(this.path);\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/workspace/component/sources/sourceFile.ts",
    "content": "import vinylFile from 'vinyl-file';\nimport AbstractVinyl from './abstractVinyl';\nimport logger from '../../../logger/logger';\nimport { FileSourceNotFoundError } from '../exceptions';\n\nexport default class SourceFile extends AbstractVinyl {\n  static load(\n    filePath: string,\n    base: string,\n    consumerPath: string,\n    extendedProps: Record<string, any>\n  ): SourceFile {\n    try {\n      const file = new SourceFile(vinylFile.readSync(filePath, { base, cwd: consumerPath }));\n      Object.entries(extendedProps).forEach(([key, value]) => {\n        file[key] = value;\n      });\n      return file;\n    } catch (err: any) {\n      logger.errorAndAddBreadCrumb(\n        'source-file.load',\n        'failed loading file {filePath}. Error: {message}',\n        { filePath, message: err.message },\n        err\n      );\n      if (err.code === 'ENOENT' && err.path) {\n        throw new FileSourceNotFoundError(err.path);\n      }\n      throw err;\n    }\n  }\n\n  static loadFromParsedString(parsedString: Record<string, any>): SourceFile | null {\n    if (!parsedString) return null;\n    const opts = super.loadFromParsedStringBase(parsedString);\n    return new SourceFile(opts);\n  }\n\n  static loadFromParsedStringArray(arr: Record<string, any>[]): SourceFile[] | null | undefined {\n    if (!arr) return null;\n    return arr.map(this.loadFromParsedString);\n  }\n\n  clone(): this {\n    // @ts-ignore\n    return new SourceFile(this);\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/workspace/component/sources/vinylTypes.ts",
    "content": "import * as fs from 'fs';\n\n// See https://github.com/Microsoft/TypeScript/issues/11796\n\ninterface File {\n  /**\n   * Gets and sets the contents of the file. If set to a `Stream`, it is wrapped in\n   * a `cloneable-readable` stream.\n   *\n   * Throws when set to any value other than a `Stream`, a `Buffer` or `null`.\n   */\n  contents: Buffer | NodeJS.ReadableStream | null;\n\n  /**\n   * Gets and sets current working directory. Will always be normalized and have trailing\n   * separators removed.\n   *\n   * Throws when set to any value other than non-empty strings.\n   */\n  cwd: string;\n\n  //\n  /**\n   * Gets and sets base directory. Used for relative pathing (typically where a glob starts).\n   * When `null` or `undefined`, it simply proxies the `file.cwd` property. Will always be\n   * normalized and have trailing separators removed.\n   *\n   * Throws when set to any value other than non-empty strings or `null`/`undefined`.\n   *\n   * The setter's type is actually `string | null | undefined`, but TypeScript doesn't allow\n   * get/set accessors to be of different type. The property is declared as `string` for the\n   * compiler not to require useless null checks for the getter. (Hopefully, noone will need\n   * to assign `null` to this property.)\n   */\n  base: string;\n\n  /**\n   * Gets and sets the absolute pathname string or `undefined`. Setting to a different value\n   * appends the new path to `file.history`. If set to the same value as the current path, it\n   * is ignored. All new values are normalized and have trailing separators removed.\n   *\n   * Throws when set to any value other than a string.\n   *\n   * The getter is actually of type `string | undefined` whereas the setter is just `string`,\n   * however TypeScript doesn't allow get/set accessors to be of different type. See the\n   * comment for the `base` properties.\n   */\n  path: string;\n\n  /**\n   * Array of `file.path` values the Vinyl object has had, from `file.history[0]` (original)\n   * through `file.history[file.history.length - 1]` (current). `file.history` and its elements\n   * should normally be treated as read-only and only altered indirectly by setting `file.path`.\n   */\n  readonly history: ReadonlyArray<string>;\n\n  /**\n   * Gets the result of `path.relative(file.base, file.path)`.\n   *\n   * Throws when set or when `file.path` is not set.\n   *\n   * Example:\n   *\n   * ```js\n   * var file = new File({\n   *   cwd: '/',\n   *   base: '/test/',\n   *   path: '/test/file.js'\n   * });\n   *\n   * console.log(file.relative); // file.js\n   * ```\n   */\n  relative: string;\n\n  /**\n   * Gets and sets the dirname of `file.path`. Will always be normalized and have trailing\n   * separators removed.\n   *\n   * Throws when `file.path` is not set.\n   *\n   * Example:\n   *\n   * ```js\n   * var file = new File({\n   *   cwd: '/',\n   *   base: '/test/',\n   *   path: '/test/file.js'\n   * });\n   *\n   * console.log(file.dirname); // /test\n   *\n   * file.dirname = '/specs';\n   *\n   * console.log(file.dirname); // /specs\n   * console.log(file.path); // /specs/file.js\n   * ```\n   */\n  dirname: string;\n\n  /**\n   * Gets and sets the basename of `file.path`.\n   *\n   * Throws when `file.path` is not set.\n   *\n   * Example:\n   *\n   * ```js\n   * var file = new File({\n   *   cwd: '/',\n   *   base: '/test/',\n   *   path: '/test/file.js'\n   * });\n   *\n   * console.log(file.basename); // file.js\n   *\n   * file.basename = 'file.txt';\n   *\n   * console.log(file.basename); // file.txt\n   * console.log(file.path); // /test/file.txt\n   * ```\n   */\n  basename: string;\n\n  /**\n   * Gets and sets stem (filename without suffix) of `file.path`.\n   *\n   * Throws when `file.path` is not set.\n   *\n   * Example:\n   *\n   * ```js\n   * var file = new File({\n   *   cwd: '/',\n   *   base: '/test/',\n   *   path: '/test/file.js'\n   * });\n   *\n   * console.log(file.stem); // file\n   *\n   * file.stem = 'foo';\n   *\n   * console.log(file.stem); // foo\n   * console.log(file.path); // /test/foo.js\n   * ```\n   */\n  stem: string;\n\n  /**\n   * Gets and sets extname of `file.path`.\n   *\n   * Throws when `file.path` is not set.\n   *\n   * Example:\n   *\n   * ```js\n   * var file = new File({\n   *   cwd: '/',\n   *   base: '/test/',\n   *   path: '/test/file.js'\n   * });\n   *\n   * console.log(file.extname); // .js\n   *\n   * file.extname = '.txt';\n   *\n   * console.log(file.extname); // .txt\n   * console.log(file.path); // /test/file.txt\n   * ```\n   */\n  extname: string;\n\n  /**\n   * Gets and sets the path where the file points to if it's a symbolic link. Will always\n   * be normalized and have trailing separators removed.\n   *\n   * Throws when set to any value other than a string.\n   */\n  symlink: string | null;\n\n  stat: fs.Stats | null;\n\n  [customProperty: string]: any;\n\n  /**\n   * Returns `true` if the file contents are a `Buffer`, otherwise `false`.\n   */\n  // eslint-disable-next-line no-use-before-define\n  isBuffer(): this is BufferFile;\n\n  /**\n   * Returns `true` if the file contents are a `Stream`, otherwise `false`.\n   */\n  // eslint-disable-next-line no-use-before-define\n  isStream(): this is StreamFile;\n\n  /**\n   * Returns `true` if the file contents are `null`, otherwise `false`.\n   */\n  // eslint-disable-next-line no-use-before-define\n  isNull(): this is NullFile;\n\n  /**\n   * Returns `true` if the file represents a directory, otherwise `false`.\n   *\n   * A file is considered a directory when:\n   *\n   * - `file.isNull()` is `true`\n   * - `file.stat` is an object\n   * - `file.stat.isDirectory()` returns `true`\n   *\n   * When constructing a Vinyl object, pass in a valid `fs.Stats` object via `options.stat`.\n   * If you are mocking the `fs.Stats` object, you may need to stub the `isDirectory()` method.\n   */\n  // eslint-disable-next-line no-use-before-define\n  isDirectory(): this is DirectoryFile;\n\n  /**\n   * Returns `true` if the file represents a symbolic link, otherwise `false`.\n   *\n   * A file is considered symbolic when:\n   *\n   * - `file.isNull()` is `true`\n   * - `file.stat` is an object\n   * - `file.stat.isSymbolicLink()` returns `true`\n   *\n   * When constructing a Vinyl object, pass in a valid `fs.Stats` object via `options.stat`.\n   * If you are mocking the `fs.Stats` object, you may need to stub the `isSymbolicLink()` method.\n   */\n  // eslint-disable-next-line no-use-before-define\n  isSymbolic(): this is SymbolicFile;\n\n  /**\n   * Returns a new Vinyl object with all attributes cloned.\n   *\n   * __By default custom attributes are cloned deeply.__\n   *\n   * If `options` or `options.deep` is `false`, custom attributes will not be cloned deeply.\n   *\n   * If `file.contents` is a `Buffer` and `options.contents` is `false`, the `Buffer` reference\n   * will be reused instead of copied.\n   */\n  clone(opts?: { contents?: boolean; deep?: boolean } | boolean): this;\n\n  /**\n   * Returns a formatted-string interpretation of the Vinyl object.\n   * Automatically called by node's `console.log`.\n   */\n  inspect(): string;\n\n  /**\n   * @deprecated This method was removed in v2.0.\n   * If file.contents is a Buffer, it will write it to the stream.\n   * If file.contents is a Stream, it will pipe it to the stream.\n   * If file.contents is null, it will do nothing.\n   */\n  pipe<T extends NodeJS.WritableStream>(\n    stream: T,\n    opts?: {\n      /**\n       * If false, the destination stream will not be ended (same as node core).\n       */\n      end?: boolean;\n    }\n  ): T;\n}\n\ninterface NullFile extends File {\n  contents: null;\n  isStream(): this is never;\n  isBuffer(): this is never;\n  isNull(): true;\n  // eslint-disable-next-line no-use-before-define\n  isDirectory(): this is DirectoryFile;\n  // eslint-disable-next-line no-use-before-define\n  isSymbolic(): this is SymbolicFile;\n}\n\ninterface BufferFile extends File {\n  contents: Buffer;\n  isStream(): this is never;\n  isBuffer(): true;\n  isNull(): this is never;\n  isDirectory(): this is never;\n  isSymbolic(): this is never;\n}\n\ninterface StreamFile extends File {\n  contents: NodeJS.ReadableStream;\n  isStream(): true;\n  isBuffer(): this is never;\n  isNull(): this is never;\n  isDirectory(): this is never;\n  isSymbolic(): this is never;\n}\n\ninterface DirectoryFile extends NullFile {\n  isDirectory(): true;\n  isSymbolic(): this is never;\n}\n\ninterface SymbolicFile extends NullFile {\n  isDirectory(): this is never;\n  isSymbolic(): true;\n}\n\ninterface ConstructorOptions {\n  /**\n   * The current working directory of the file. Default: process.cwd()\n   */\n  cwd?: string;\n\n  /**\n   * Used for relative pathing. Typically where a glob starts. Default: options.cwd\n   */\n  base?: string;\n\n  /**\n   * Full path to the file.\n   */\n  path?: string;\n\n  /**\n   * Stores the path history. If `options.path` and `options.history` are both passed,\n   * `options.path` is appended to `options.history`. All `options.history` paths are\n   * normalized by the `file.path` setter.\n   * Default: `[]` (or `[options.path]` if `options.path` is passed)\n   */\n  history?: string[];\n\n  /**\n   * The result of an fs.stat call. This is how you mark the file as a directory or\n   * symbolic link. See `isDirectory()`, `isSymbolic()` and `fs.Stats` for more information.\n   * http://nodejs.org/api/fs.html#fs_class_fs_stats\n   */\n  stat?: fs.Stats;\n\n  /**\n   * File contents.\n   * Type: `Buffer`, `Stream`, or null\n   * Default: null\n   */\n  contents?: Buffer | NodeJS.ReadableStream | null;\n\n  /**\n   * Any custom option properties will be directly assigned to the new Vinyl object.\n   */\n  [customOption: string]: any;\n}\n\nexport interface FileConstructor {\n  // new (options: ConstructorOptions & { contents: null }): File.NullFile;\n  new (options: ConstructorOptions & { contents: Buffer }): BufferFile;\n  // new (\n  //     options: ConstructorOptions & { contents: NodeJS.ReadableStream }\n  // ): File.StreamFile;\n  // new (options?: ConstructorOptions): File;\n\n  /**\n   * Checks if a given object is a vinyl file.\n   */\n  isVinyl(obj: any): obj is File;\n\n  /**\n   * Checks if a property is not managed internally.\n   */\n  isCustomProp(name: string): boolean;\n\n  prototype: File;\n}\n"
  },
  {
    "path": "packages/legacy/src/workspace/componentIdTo.ts",
    "content": "import toFsCompatible from '../utils/string/toFsCompatible';\n\ntype ComponentChunkType = 'component' | 'preview';\n\nconst PREVIEW_CHUNK_SUFFIX = 'preview';\n\nconst MANIFEST_FILENAME = 'manifest.json';\n\nconst FORK_CONFIG_FILENAME = 'config.json';\n\nexport function toComponentChunkFilename(componentId: string, type: ComponentChunkType) {\n  const fsCompatibleId = toFsCompatible(componentId);\n  const fileNameSuffix = type === 'preview' ? `-${PREVIEW_CHUNK_SUFFIX}` : '';\n  return `${fsCompatibleId}${fileNameSuffix}.js`;\n}\n\nexport function toComponentManifestFilename(componentId: string) {\n  const fsCompatibleId = toFsCompatible(componentId);\n  return `${fsCompatibleId}-${MANIFEST_FILENAME}`;\n}\n\nexport function toComponentForkConfigFilename(componentId: string) {\n  const fsCompatibleId = toFsCompatible(componentId);\n  return `${fsCompatibleId}-${FORK_CONFIG_FILENAME}`;\n}\n\nexport function toComponentChunkId(componentId: string, type: ComponentChunkType) {\n  return type === 'component' ? componentId : `${componentId}-${PREVIEW_CHUNK_SUFFIX}`;\n}\n\nexport function toComponentPackageName(componentId: string) {\n  return componentId.replace(/\\/[^/]+$/, '');\n}\n"
  },
  {
    "path": "packages/legacy/src/workspace/componentInfo.ts",
    "content": "import fs from 'fs-extra';\nimport path from 'path';\nimport { buildPropagationPaths } from '../utils/path';\nimport { DEFAULT_TEST_FILE_PATTERNS, PACKAGE_JSON } from '../constants';\n\nexport type ComponentConfig = {\n  /**\n   * root dir of package source code, relative path to workspace\n   */\n  rootDir: string;\n  /**\n   * name of component\n   */\n  name: string;\n  /**\n   * author of component\n   */\n  author?: string;\n  /**\n   * labels of component\n   */\n  labels?: string[];\n  /**\n   * material group id of component\n   */\n  group?: number;\n  /**\n   * url of code repository\n   */\n  repository?: string;\n  /**\n   * url of ui resource, like a figma address\n   */\n  uiResource?: string;\n  /**\n   * additional page styles that can be added\n   */\n  extraStyles?: Array<{ title: string; href: string }>;\n  /**\n   * entry file info of component\n   */\n  entries: {\n    /**\n     * component dir. \"./\" by default, but in library-project this path should be \"./ComponentName\"\n     */\n    base?: string;\n    /**\n     * component main entry, should be path.join(rootDir, entries.base, entries.main)\n     */\n    main?: string;\n    /**\n     * main entry for component style\n     */\n    style?: string;\n    /**\n     * main entry for component preview\n     */\n    preview?: string;\n    /**\n     * file path of ContextProvider for component preview\n     */\n    previewContextProvider?: string;\n    /**\n     * entries for component TS document parsing\n     */\n    jsdoc?: string | string[];\n    /**\n     * file path pattern for unit test\n     */\n    testFilePatterns?: string[];\n    /**\n     * slot for extra document other than component preview, like document for changelog or quick-start\n     */\n    extraDocs?: Array<{ title: string; entry: string }>;\n  };\n  /**\n   * whether this component is allowed to fork\n   */\n  forkable?:\n    | boolean\n    | {\n        sources: string[];\n      };\n};\n\nexport type ComponentInfoFiles = {\n  name: string;\n  relativePath: string;\n  test: boolean;\n};\n\nexport class ComponentInfo {\n  name: string;\n\n  group: number;\n\n  author: string;\n\n  labels: string[];\n\n  repository: string;\n\n  uiResource: string;\n\n  extraStyles: ComponentConfig['extraStyles'];\n\n  files: ComponentInfoFiles[];\n\n  entries: ComponentConfig['entries'];\n\n  forkable: ComponentConfig['forkable'];\n\n  rootDir: string;\n\n  noFilesError?: Error;\n\n  readonly packageJson: Record<string, any>;\n\n  readonly packageDir: string;\n\n  readonly packageDirAbs: string;\n\n  constructor(\n    readonly rawConfig: ComponentConfig,\n    workspacePath: string,\n    files?: ComponentInfoFiles[]\n  ) {\n    const {\n      name,\n      group,\n      author,\n      labels,\n      repository,\n      uiResource,\n      entries,\n      rootDir,\n      extraStyles,\n      forkable,\n    } = rawConfig;\n\n    // set entry to empty string to avoid path.resolve errors\n    entries.base ||= './';\n    entries.main ||= '';\n    entries.style ||= '';\n    entries.preview ||= '';\n    entries.previewContextProvider ||= '';\n    entries.jsdoc ||= '';\n    entries.testFilePatterns ||= DEFAULT_TEST_FILE_PATTERNS;\n    entries.extraDocs ||= [];\n\n    this.entries = entries;\n    this.rootDir = rootDir;\n    this.name = name || '';\n    this.labels = labels || [];\n    this.files = files || [];\n    this.group = group || 0;\n    this.author = author || '';\n    this.repository = repository || '';\n    this.uiResource = uiResource || '';\n    this.extraStyles = extraStyles || [];\n    this.forkable = forkable || false;\n\n    const dirsToSearchPkgJson = buildPropagationPaths(\n      path.resolve(workspacePath, rootDir),\n      workspacePath\n    );\n\n    for (const dirPath of dirsToSearchPkgJson) {\n      const packageJsonPath = path.join(dirPath, PACKAGE_JSON);\n      if (fs.existsSync(packageJsonPath)) {\n        this.packageDir = path.relative(workspacePath, dirPath) || './';\n        this.packageDirAbs = dirPath;\n        this.packageJson = fs.readJSONSync(packageJsonPath);\n        break;\n      }\n    }\n  }\n\n  get id(): string {\n    return this.packageName ? `${this.packageName}/${this.name}` : this.name;\n  }\n\n  get version(): string {\n    return this.packageJson?.version || '';\n  }\n\n  get packageName(): string {\n    return this.packageJson?.name || '';\n  }\n\n  get dependencies(): Record<string, string> {\n    return this.packageJson?.dependencies || {};\n  }\n\n  get devDependencies(): Record<string, string> {\n    return this.packageJson?.devDependencies || {};\n  }\n\n  get peerDependencies(): Record<string, string> {\n    return this.packageJson?.peerDependencies || {};\n  }\n\n  // test if a component name match a given component id\n  // name: Button, id: library/Button => true\n  // name: Tag, id: library/Button => false\n  static nameMatchId(name = '', id = '') {\n    return id.endsWith(`/${name}`);\n  }\n\n  static fromJson(json: ComponentConfig, workspacePath: string) {\n    return new ComponentInfo(json, workspacePath);\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/workspace/componentOps/addComponents/addComponents.ts",
    "content": "import path from 'path';\nimport globby from 'globby';\nimport { ComponentNotFoundInPathError } from '../../component/exceptions';\nimport { IgnoredDirectoryError } from './exceptions';\nimport { pathNormalizeToLinux } from '../../../utils/path';\n\nexport type ComponentMapFile = {\n  name: string;\n  relativePath: string;\n  test: boolean;\n};\n\nexport async function getFilesByDir(\n  dir: string,\n  workspacePath: string,\n  gitIgnore: any\n): Promise<ComponentMapFile[]> {\n  const matches = await globby(dir, {\n    cwd: workspacePath,\n    onlyFiles: true,\n  });\n  if (!matches.length) throw new ComponentNotFoundInPathError(dir);\n  const filteredMatches = gitIgnore.filter(matches);\n  if (!filteredMatches.length) throw new IgnoredDirectoryError(dir);\n  return filteredMatches.map((match: string) => {\n    const normalizedPath = pathNormalizeToLinux(match);\n    // the path is relative to workspace. remove the rootDir.\n    const relativePath = normalizedPath.replace(`${dir}/`, '');\n    return { relativePath, test: false, name: path.basename(match) };\n  });\n}\n"
  },
  {
    "path": "packages/legacy/src/workspace/componentOps/addComponents/exceptions/ignoredDirectoryError.ts",
    "content": "import chalk from 'chalk';\nimport ArcoError from '../../../../error/arcoError';\n\nexport class IgnoredDirectoryError extends ArcoError {\n  constructor(dir: string) {\n    super(chalk.yellow(`directory \"${dir}\" or its files are git-ignored`));\n  }\n}\n"
  },
  {
    "path": "packages/legacy/src/workspace/componentOps/addComponents/exceptions/index.ts",
    "content": "export { IgnoredDirectoryError } from './ignoredDirectoryError';\n"
  },
  {
    "path": "packages/legacy/src/workspace/componentOps/addComponents/index.ts",
    "content": "export { getFilesByDir } from './addComponents';\n"
  },
  {
    "path": "packages/legacy/src/workspace/componentResult.ts",
    "content": "import chalk from 'chalk';\n\nexport type Serializable = {\n  toString(): string;\n};\n\nexport type TaskMetadata = { [key: string]: Serializable };\n\nexport type ComponentResult = {\n  /**\n   * component id\n   */\n  id: string;\n\n  /**\n   * metadata generated during task\n   */\n  metadata?: TaskMetadata;\n\n  /**\n   * returning errors from tasks will cause a pipeline failure and logs all returned errors.\n   */\n  errors?: Array<Error | string>;\n\n  /**\n   * warnings generated throughout the build task.\n   */\n  warnings?: string[];\n\n  /**\n   * timestamp in milliseconds when the task started\n   */\n  startTime?: number;\n\n  /**\n   * timestamp in milliseconds when the task ended\n   */\n  endTime?: number;\n};\n\n/**\n * Format component errors to human-readable\n */\nexport function formatComponentResultError(componentResults: ComponentResult[]): string {\n  const componentErrors: string[] = [];\n  let totalErrors = 0;\n  let totalFailed = 0;\n\n  componentResults.forEach((result) => {\n    const { id, errors } = result;\n    if (!errors.length) return;\n\n    totalErrors += errors.length;\n    totalFailed += 1;\n    const title = chalk.bold(`Failed component ${totalFailed}: \"${id}\"\\n`);\n    componentErrors.push(`${title}${errors.join('\\n')}`);\n  });\n\n  if (!componentErrors.length) return null;\n\n  const title = `\\nThe following errors were found\\n`;\n  const errorsStr = componentErrors.join('\\n\\n');\n  const totalSucceed = componentResults.length - totalFailed;\n  const summery = `\\n\\n\\n✖ Total ${componentResults.length} components. ${totalSucceed} succeed. ${totalFailed} failed. Total errors: ${totalErrors}`;\n\n  return title + errorsStr + summery;\n}\n"
  },
  {
    "path": "packages/legacy/src/workspace/workspaceLocator.ts",
    "content": "import fs from 'fs-extra';\nimport { join } from 'path';\nimport { FILE_WORKSPACE_JSONC, FILE_WORKSPACE_JS } from '../constants';\nimport { buildPropagationPaths } from '../utils/path';\n\nexport type WorkspaceInfo = {\n  path: string;\n  configFilename: string;\n};\n\n/**\n * propagate from the given directory up to the root to find the consumer\n */\nexport async function getWorkspaceInfo(absPath: string): Promise<WorkspaceInfo | null> {\n  const searchPaths = buildPropagationPaths(absPath);\n  searchPaths.unshift(absPath);\n\n  for (let i = 0; i < searchPaths.length; i += 1) {\n    const path = searchPaths[i];\n    const jsFilePath = join(path, FILE_WORKSPACE_JS);\n    const jsonFilePath = join(path, FILE_WORKSPACE_JSONC);\n\n    const configFilename = fs.existsSync(jsFilePath)\n      ? FILE_WORKSPACE_JS\n      : fs.existsSync(jsonFilePath)\n      ? FILE_WORKSPACE_JSONC\n      : null;\n\n    if (configFilename) {\n      return {\n        path,\n        configFilename,\n      };\n    }\n  }\n\n  return null;\n}\n"
  },
  {
    "path": "packages/legacy/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"dist\",\n    \"paths\": {\n      \"@arco-cli/stone\": [\"../stone/src\"],\n      \"@arco-cli/legacy/dist/*\": [\"../legacy/src/*\"],\n      \"@arco-cli/core/dist/*\": [\"../core/src/*\"],\n      \"@arco-cli/aspect/dist/*\": [\"../aspect/src/*\"],\n      \"@arco-cli/service/dist*\": [\"../service/src/*\"],\n      \"@arco-cli/ui-foundation-react\": [\"../ui-foundation-react/src\"],\n      \"@arco-cli/ui-foundation-react/dist/*\": [\"../ui-foundation-react/src/*\"]\n    }\n  }\n}\n"
  },
  {
    "path": "packages/migrator/bin/arco-migrate",
    "content": "#!/usr/bin/env node\nrequire('../dist/app');\n"
  },
  {
    "path": "packages/migrator/package.json",
    "content": "{\n  \"name\": \"@arco-cli/migration-helper\",\n  \"version\": \"2.1.0\",\n  \"main\": \"./dist/index.js\",\n  \"bin\": {\n    \"arco-migrate\": \"./bin/arco-migrate\"\n  },\n  \"scripts\": {\n    \"dev\": \"sh ../../.scripts/build.sh dev\",\n    \"build\": \"sh ../../.scripts/build.sh\",\n    \"build-type\": \"sh ../../.scripts/build-type.sh\",\n    \"clean\": \"rm -rf dist\",\n    \"clean-type\": \"find dist -name *.d.ts |xargs rm -rf\",\n    \"prepublishOnly\": \"npm run build\"\n  },\n  \"dependencies\": {\n    \"@arco-cli/generator\": \"^2.1.0\",\n    \"comment-json\": \"^4.2.3\",\n    \"doctrine\": \"^3.0.0\",\n    \"fs-extra\": \"^11.1.0\",\n    \"glob\": \"^10.3.3\",\n    \"lodash\": \"^4.17.21\",\n    \"ora\": \"^5.4.1\",\n    \"parse-es-import\": \"^0.6.0\",\n    \"yargs\": \"^17.6.2\"\n  },\n  \"devDependencies\": {\n    \"@types/yargs\": \"^17.0.13\"\n  },\n  \"files\": [\n    \"bin\",\n    \"dist\"\n  ],\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "packages/migrator/src/adapters/componentAdapter.ts",
    "content": "import path from 'path';\nimport { sync as globSync } from 'glob';\nimport fs from 'fs-extra';\nimport doctrine from 'doctrine';\nimport parseEsImport from 'parse-es-import';\n\nimport { PACKAGE_JSON } from '../constant';\nimport { AdapterOptions, ComponentInfo } from '../types';\nimport { buildPropagationPaths } from '../utils';\n\nconst DEFAULT_NEW_DEMO_DIR = '__docs__';\n\nexport interface ComponentAdapterOptions extends AdapterOptions {\n  demoDir: string;\n}\n\ntype DemoInfo = { path: string; moduleName: string; isDefault?: boolean };\n\nexport class ComponentAdapter {\n  static parseDemoModules(entryContent: string): DemoInfo[] {\n    // Get demo source code\n    const demoInfoList: DemoInfo[] = [];\n    const { exports } = parseEsImport(entryContent);\n\n    exports.forEach(({ type, moduleName, value, startIndex, endIndex }) => {\n      switch (type) {\n        case 'ExportSpecifier': {\n          const statement = entryContent.slice(startIndex, endIndex);\n          demoInfoList.push({\n            path: value,\n            moduleName,\n            isDefault: /default\\s+as\\s+/.test(statement),\n          });\n          break;\n        }\n\n        default:\n          break;\n      }\n    });\n\n    return demoInfoList;\n  }\n\n  static parseRawComment(fileContent) {\n    const commentList = [];\n    fileContent.replace(/\\/\\*{2}\\s*\\n(\\s*\\*.*\\n)+\\s*\\*\\//g, (match) => {\n      const comment = {\n        kind: 'member',\n      };\n\n      doctrine\n        .parse(match, { unwrap: true, recoverable: true })\n        .tags.forEach(({ title, name, description }) => {\n          const value = name || description;\n          if (value) {\n            comment[title] = value;\n          }\n          if (title === 'file') {\n            comment.kind = 'file';\n          }\n        });\n\n      commentList.push(comment);\n    });\n\n    return commentList;\n  }\n\n  static parseComponentInfo(workspaceRoot: string, componentDir: string, demoDir: string) {\n    const componentName = componentDir\n      .split('/')\n      .pop()\n      .replace(/^\\w/, (match) => match.toUpperCase());\n    const componentInfo: ComponentInfo = {\n      path: componentDir,\n      name: componentName,\n      demos: [],\n      package: {\n        path: '',\n      },\n    };\n\n    // get package dir of current component\n    const dirsToSearchPkgJson = buildPropagationPaths(componentDir, workspaceRoot);\n    for (const dirPath of dirsToSearchPkgJson) {\n      const packageJsonPath = path.join(dirPath, PACKAGE_JSON);\n      if (fs.existsSync(packageJsonPath)) {\n        componentInfo.package.path = dirPath;\n        // component dir has a relative path like src/\n        if (componentDir.replace(path.join(dirPath, '/'), '').split('/').length === 1) {\n          const packageJson = fs.readJSONSync(packageJsonPath);\n          // transform name from package-name to PackageName\n          componentInfo.name = packageJson.name\n            .split('/')\n            .pop()\n            .replace(/(^\\w)|(-\\w)/g, (match) => match.replace('-', '').toUpperCase());\n        }\n        break;\n      }\n    }\n\n    // parse demo infos of current component\n    const originDemoDir = path.resolve(componentDir, demoDir);\n    const [originDemoEntry] = globSync(path.resolve(originDemoDir, 'index.{js,ts,jsx,tsx}'));\n    if (originDemoEntry) {\n      const originDemoContent = fs.readFileSync(originDemoEntry, 'utf8');\n      const commentList = ComponentAdapter.parseRawComment(originDemoContent);\n      const demoModules: DemoInfo[] = [];\n      try {\n        demoModules.push(...ComponentAdapter.parseDemoModules(originDemoContent));\n      } catch (err) {\n        console.error(\n          `Failed to parse component demos from ${originDemoEntry}.\\n${err.toString()}`\n        );\n      }\n\n      for (const comment of commentList) {\n        const { kind, title, description, memberOf, memberof, author } = comment;\n        if (kind === 'file') {\n          Object.assign(componentInfo, {\n            title,\n            description,\n            author,\n            labels: [memberOf || memberof],\n          });\n        }\n        if (kind === 'member') {\n          const module = demoModules.shift();\n          componentInfo.demos.push({\n            moduleName: module.moduleName,\n            path: module.path,\n            isDefault: module.isDefault,\n            title,\n            description,\n          });\n        }\n      }\n    }\n\n    return componentInfo;\n  }\n\n  private readonly options: ComponentAdapterOptions;\n\n  public readonly info: ComponentInfo = null;\n\n  constructor(options: ComponentAdapterOptions) {\n    this.options = options;\n    this.info = ComponentAdapter.parseComponentInfo(\n      options.workspaceRoot,\n      options.path,\n      options.demoDir\n    );\n  }\n\n  private generateNewDocEntry() {\n    const componentInfo = this.info;\n    const markdownMeta = `---\n${componentInfo.title ? `title: ${componentInfo.title}\\n` : ''}${\n      componentInfo.description\n        ? `description: ${componentInfo.description.replace(/[\\n\\r]/g, ' ')}\\n`\n        : ''\n    }${\n      componentInfo.labels?.length\n        ? `labels: [${componentInfo.labels.map((label) => `'${label}'`).join(', ')}]`\n        : ''\n    }\n---`;\n\n    const importStatement = `${componentInfo.demos\n      .map(\n        (info) =>\n          `import ${info.isDefault ? info.moduleName : `{ ${info.moduleName} }`} from '${\n            info.path\n          }';`\n      )\n      .join('\\n')}`;\n\n    const docContent = componentInfo.demos\n      .map((info, index) => {\n        return `# ${info.title || `Demo ${index}`}${\n          info.description ? `\\n\\n${info.description}` : ''\n        }\n\n<div data-arco-demo=\"${info.moduleName}\">\n  <${info.moduleName}/>\n</div>`;\n      })\n      .join('\\n\\n');\n\n    return `${markdownMeta}\\n\\n${importStatement}\\n\\n${docContent}`;\n  }\n\n  private adaptDemos() {\n    const { path: componentDir } = this.info;\n    const originDemoDir = path.resolve(componentDir, this.options.demoDir);\n    if (fs.existsSync(originDemoDir)) {\n      const targetDemoDir = path.resolve(componentDir, DEFAULT_NEW_DEMO_DIR);\n      const targetDemoEntry = path.resolve(targetDemoDir, 'index.mdx');\n      const newDocContent = this.generateNewDocEntry();\n\n      fs.copySync(originDemoDir, targetDemoDir, {\n        filter: (filePath) => !/^\\/?index\\.[jt]sx?$/.test(filePath.replace(originDemoDir, '')),\n      });\n      fs.writeFileSync(targetDemoEntry, newDocContent);\n    }\n  }\n\n  private deleteUselessFiles() {\n    globSync(\n      this.options.uselessFilePatterns.map((filePattern) =>\n        path.resolve(this.options.path, filePattern)\n      )\n    ).forEach((filePath) => fs.removeSync(filePath));\n  }\n\n  run() {\n    if (!this.options.noEmit) {\n      this.adaptDemos();\n      this.deleteUselessFiles();\n    }\n  }\n}\n"
  },
  {
    "path": "packages/migrator/src/adapters/packageAdapter.ts",
    "content": "import path from 'path';\nimport fs from 'fs-extra';\nimport { omit } from 'lodash';\nimport { sync as globSync } from 'glob';\nimport { PACKAGE_JSON, TIP_CHECK_MIGRATION, TSCONFIG_JSON } from '../constant';\nimport { AdapterOptions } from '../types';\n\nexport type PackageAdapterOptions = AdapterOptions;\n\nexport class PackageAdapter {\n  private readonly isRootPackage: boolean;\n\n  private readonly options: PackageAdapterOptions;\n\n  constructor(options: PackageAdapterOptions) {\n    this.options = options;\n    this.isRootPackage = options.workspaceRoot === options.path;\n  }\n\n  private adaptPackageJSON() {\n    const packageJsonPath = path.join(this.options.path, PACKAGE_JSON);\n    if (fs.existsSync(packageJsonPath)) {\n      const packageJson = fs.readJSONSync(packageJsonPath);\n\n      // delete useless properties\n      delete packageJson.umd;\n      delete packageJson.arcoMeta;\n\n      // handle scripts\n      if (!this.isRootPackage) {\n        packageJson.scripts ||= {};\n        packageJson.scripts = omit(packageJson.scripts, [\n          'dev',\n          'build',\n          'docgen',\n          'test:client',\n          'test:node',\n          'test',\n          'show:config',\n          'clean',\n          'prepublishOnly',\n          'generate',\n          'sync',\n          'preview',\n        ]);\n        Object.assign(packageJson.scripts, {\n          READ_THIS: `${TIP_CHECK_MIGRATION} All scripts depend on [arco-scripts] is deleted, please check these scripts`,\n          clean: 'rm -rf es lib artifacts',\n        });\n      }\n\n      // handle devDeps\n      if (packageJson.devDependencies) {\n        delete packageJson.devDependencies['arco-cli'];\n        delete packageJson.devDependencies['arco-cli-dev-utils'];\n        delete packageJson.devDependencies['arco-scripts'];\n        delete packageJson.devDependencies['@arco-design/arco-scripts'];\n      }\n\n      // handle files\n      packageJson.files = ['es', 'lib', 'artifacts'];\n      fs.writeJSONSync(packageJsonPath, packageJson, { spaces: 2 });\n    }\n  }\n\n  private adaptTsconfig() {\n    const tsconfigPath = path.join(this.options.path, TSCONFIG_JSON);\n    if (fs.existsSync(tsconfigPath)) {\n      const tsconfig = fs.readJSONSync(tsconfigPath);\n      tsconfig.compilerOptions ||= {};\n      delete tsconfig.compilerOptions.declaration;\n      fs.writeJSONSync(tsconfigPath, tsconfig, { spaces: 2 });\n    }\n  }\n\n  private deleteUselessFiles() {\n    globSync(\n      this.options.uselessFilePatterns.map((filePattern) =>\n        path.resolve(this.options.path, filePattern)\n      )\n    ).forEach((filePath) => fs.removeSync(filePath));\n  }\n\n  run() {\n    if (!this.options.noEmit) {\n      this.adaptPackageJSON();\n      this.adaptTsconfig();\n      this.deleteUselessFiles();\n    }\n  }\n}\n"
  },
  {
    "path": "packages/migrator/src/adapters/workspaceAdapter.ts",
    "content": "import path from 'path';\nimport fs from 'fs-extra';\n\nimport { sync as globSync } from 'glob';\nimport { PACKAGE_JSON, TSCONFIG_JSON, TIP_CHECK_MIGRATION } from '../constant';\nimport { AdapterOptions } from '../types';\n\nexport type WorkspaceAdapterOptions = AdapterOptions;\n\nexport class WorkspaceAdapter {\n  private readonly options: WorkspaceAdapterOptions;\n\n  private readonly templateDirPath = path.resolve(\n    path.dirname(require.resolve('@arco-cli/generator')),\n    'templates/react-workspace'\n  );\n\n  private templateFnContext = {\n    path: '',\n    name: '',\n    packageName: '',\n    version: '',\n    description: '',\n  };\n\n  constructor(options: WorkspaceAdapterOptions) {\n    this.options = options;\n\n    // init templateFnContext\n    this.templateFnContext.path = this.options.path;\n    try {\n      // eslint-disable-next-line @typescript-eslint/no-var-requires\n      const packageInfo = require(path.join(this.options.path, PACKAGE_JSON));\n      Object.assign(this.templateFnContext, {\n        name: packageInfo.name,\n        packageName: packageInfo.name,\n        version: packageInfo.version,\n        description: packageInfo.description,\n      });\n    } catch (err) {}\n  }\n\n  private adaptPackageJSON() {\n    const packageJsonPath = path.join(this.options.path, PACKAGE_JSON);\n\n    if (!fs.existsSync(packageJsonPath)) {\n      console.error('No package.json found in the project root directory');\n      process.exit(1);\n      return;\n    }\n\n    const packageJson = fs.readJSONSync(packageJsonPath);\n\n    // handle scripts\n    packageJson.scripts ||= {};\n    delete packageJson.scripts['add:package'];\n    delete packageJson.scripts.generate;\n    delete packageJson.scripts.sync;\n    delete packageJson.scripts.preview;\n    Object.assign(packageJson.scripts, {\n      start: 'arco start',\n      build: 'arco build',\n      test: 'arco test',\n      sync: 'arco sync',\n    });\n\n    // handle devDependencies\n    packageJson.devDependencies ||= {};\n    Object.keys(packageJson.devDependencies).forEach((dep) => {\n      if (\n        dep.endsWith('arco-scripts') ||\n        dep.startsWith('@storybook/') ||\n        dep.startsWith('enzyme') ||\n        [\n          'arco-cli',\n          'less-loader',\n          'react-test-renderer',\n          'typescript',\n          'typescript-json-schema',\n        ].indexOf(dep) > -1\n      ) {\n        delete packageJson.devDependencies[dep];\n      }\n    });\n    Object.assign(packageJson.devDependencies, {\n      '@arco-cli/arco': '^2.0.0-beta.6',\n      '@testing-library/dom': '~8',\n      '@testing-library/jest-dom': '~5',\n      '@testing-library/react': '~12',\n      react: '~17',\n      'react-dom': '~17',\n    });\n\n    // handle lint-staged, remove rules depend on arco-scripts\n    // \"lint-staged\": {\n    //   \"*.{js,jsx,ts,tsx}\": [\n    //     \"yarn eslint\",\n    //     \"arco-scripts test:node --bail --findRelatedTests --passWithNoTests\",\n    //     \"git add\"\n    //   ],\n    // },\n    Object.entries(packageJson['lint-staged'] || {}).forEach(\n      ([match, rules]: [string, string | string[]]) => {\n        packageJson['lint-staged'][match] = Array.isArray(rules)\n          ? rules.filter((rule) => rule.indexOf('arco-scripts') === -1)\n          : typeof rules === 'string'\n          ? rules.indexOf('arco-scripts') > -1\n            ? ''\n            : rules\n          : rules;\n      }\n    );\n\n    fs.writeJSONSync(packageJsonPath, packageJson, { spaces: 2 });\n  }\n\n  private adaptTsconfig() {\n    const tsconfigPath = path.join(this.options.path, TSCONFIG_JSON);\n\n    if (fs.existsSync(tsconfigPath)) {\n      const tsconfig = fs.readJSONSync(tsconfigPath);\n      tsconfig.compilerOptions ||= {};\n      tsconfig.compilerOptions.types = [\n        ...tsconfig.compilerOptions.types,\n        '@testing-library/jest-dom',\n      ];\n      fs.writeJSONSync(tsconfigPath, tsconfig, { spaces: 2 });\n    }\n  }\n\n  private adaptGitIgnore() {\n    const configPath = path.join(this.options.path, '.gitignore');\n\n    if (fs.existsSync(configPath)) {\n      const config = fs.readFileSync(configPath);\n      const artifactsDirName = '\\nartifacts';\n      if (config.indexOf(artifactsDirName) === -1) {\n        fs.writeFileSync(\n          configPath,\n          `${config}\n\n# ${TIP_CHECK_MIGRATION}\n# dist file dirs of [arco build] command\n# all the dist dirs are [/es, /lib, /artifacts]\n# you can update your .gitignore by yourself\n${artifactsDirName}`\n        );\n      }\n    }\n  }\n\n  private generateProjectFileFromTemplate(options: { filePath: string; prepend?: string }) {\n    const { filePath, prepend = '' } = options;\n    const tplFilePath = path.join(this.templateDirPath, filePath);\n\n    let fileContents: string | Buffer = null;\n    let targetFilePath: string = null;\n\n    // file ends with .tpl.js should execute the tpl function\n    if (tplFilePath.endsWith('.tpl.js')) {\n      try {\n        // eslint-disable-next-line @typescript-eslint/no-var-requires\n        const tplFn = require(tplFilePath).default;\n        if (typeof tplFn === 'function') {\n          const { filename, contents } = tplFn(this.templateFnContext);\n          targetFilePath = path.join(this.options.path, path.dirname(filePath), filename);\n          fileContents = contents;\n        }\n      } catch (err) {\n        console.error(`Failed to generate project file\\n${err.toString()}`);\n      }\n    } else {\n      fileContents = fs.readFileSync(tplFilePath);\n      targetFilePath = path.join(this.options.path, filePath);\n    }\n\n    if (!fs.existsSync(targetFilePath)) {\n      fs.ensureDirSync(path.dirname(targetFilePath));\n      fs.writeFileSync(targetFilePath, `${prepend}${fileContents}`);\n    }\n  }\n\n  private ejectConfigFiles() {\n    // these file paths depend on @arco-cli/generator's templates\n    // so the version of @arco-cli/generator is locked in package.json\n    const tplFilePathMap = {\n      workspaceConfig: 'arco.workspace.jsonc.tpl.js',\n      envConfig: 'arco.env.config.js',\n      jestConfig: 'jest.config.js',\n      workspaceHook: '.scripts/workspaceHooks/afterComponentCreated.js',\n    };\n\n    Object.entries(tplFilePathMap).forEach(([, filePath]) => {\n      this.generateProjectFileFromTemplate({\n        filePath,\n        prepend:\n          filePath === tplFilePathMap.jestConfig\n            ? `/**\n * ${TIP_CHECK_MIGRATION}\n * component's Jest config is defined in this file, please move the previous Jest config here\n */\n`\n            : '',\n      });\n    });\n  }\n\n  private deleteUselessFiles() {\n    globSync(\n      this.options.uselessFilePatterns.map((filePattern) =>\n        path.resolve(this.options.path, filePattern)\n      )\n    ).forEach((filePath) => fs.removeSync(filePath));\n  }\n\n  run() {\n    this.adaptPackageJSON();\n    this.adaptTsconfig();\n    this.adaptGitIgnore();\n    this.ejectConfigFiles();\n    this.deleteUselessFiles();\n  }\n}\n"
  },
  {
    "path": "packages/migrator/src/app.ts",
    "content": "/* eslint-disable no-console */\nimport yargs from 'yargs';\nimport { Migrator } from './migrator';\n\nfunction migrate(options: { noEmit: boolean; include: string }) {\n  const migrator = new Migrator({\n    componentDirPatterns: options.include,\n    noEmit: options.noEmit,\n  });\n  migrator.run();\n}\n\n// eslint-disable-next-line no-unused-expressions\nyargs\n  .scriptName('arco-migrate')\n  .command(\n    'migrate',\n    'migrate project to arco cli v2',\n    (yargs) => {\n      const includeExample = '\"packages/*/src\" \"components/*\"';\n      return yargs\n        .option('noEmit', { type: 'boolean', describe: 'skip writing files' })\n        .options('include', {\n          type: 'string',\n          demandOption: `option [include] is required, pass the glob pattern of component directories that need to be migrated. e.g. ${includeExample}`,\n          describe: `glob patterns to the component directories, e.g. ${includeExample}`,\n        });\n    },\n    (options) => migrate(options)\n  )\n  .help().argv;\n"
  },
  {
    "path": "packages/migrator/src/constant.ts",
    "content": "export const TIP_CHECK_MIGRATION = 'TODO: AUTO MIGRATION CHECK';\n\nexport const PACKAGE_JSON = 'package.json';\n\nexport const TSCONFIG_JSON = 'tsconfig.json';\n\nexport const WORKSPACE_JSONC = 'arco.workspace.jsonc';\n"
  },
  {
    "path": "packages/migrator/src/index.ts",
    "content": "export { Migrator } from './migrator';\n"
  },
  {
    "path": "packages/migrator/src/migrator.ts",
    "content": "import { sync as globSync } from 'glob';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport ora from 'ora';\nimport { clone } from 'lodash';\n\nimport { loadConfig, writeConfig } from './utils';\nimport type { ComponentInfo, MigratorOptions } from './types';\nimport { ComponentAdapter } from './adapters/componentAdapter';\nimport { WorkspaceAdapter } from './adapters/workspaceAdapter';\nimport { PackageAdapter } from './adapters/packageAdapter';\n\nexport class Migrator {\n  private readonly options: MigratorOptions;\n\n  private readonly componentDirs: string[] = [];\n\n  private readonly componentInfoList: ComponentInfo[] = [];\n\n  constructor(options: MigratorOptions) {\n    this.options = options;\n    this.options.root ||= process.cwd();\n    this.options.demoDir ||= 'demo';\n    this.options.uselessComponentFilePatterns ||= [\n      'TEMPLATE.md',\n      'README.md',\n      'demo',\n      '__test__/demo.test.{js,jsx,ts,tsx}',\n    ];\n    this.options.uselessPackageFilePatterns ||= ['.config', 'stories', 'docs', 'arcoMeta.json'];\n    this.options.uselessProjectFilePatterns ||= [\n      '.storybook',\n      '.config',\n      'tests',\n      'arco.config.js',\n      'arco.scripts.config.js',\n    ];\n\n    const { componentDirPatterns = [] } = this.options;\n    const componentDirs = globSync(\n      (Array.isArray(componentDirPatterns) ? componentDirPatterns : [componentDirPatterns]).map(\n        (pattern) => path.resolve(pattern)\n      )\n    ).filter((dirPath) => fs.lstatSync(dirPath).isDirectory());\n    this.componentDirs.push(...componentDirs);\n  }\n\n  private generateWorkspaceComponentsConfig(extendsRule: Record<string, any>, members: any[]) {\n    const results = [];\n\n    this.componentInfoList.forEach((component) => {\n      const [sourceDir, ...restDirs] = component.path\n        .replace(component.package.path, '')\n        .replace(/^\\//, '')\n        .split('/');\n      const baseDir = `./${restDirs.join('/')}`;\n      const componentConfig = {\n        rootDir: path.join('./', component.package.path.replace(this.options.root, ''), sourceDir),\n        name: component.name,\n        author: component.author,\n      };\n\n      if (extendsRule.entries?.base !== baseDir) {\n        (componentConfig as any).entries = {\n          base: baseDir,\n        };\n      }\n\n      if (\n        !members.find(\n          (member) =>\n            path.resolve(member.rootDir, member.entries?.base || './') ===\n            path.resolve(componentConfig.rootDir, (componentConfig as any).entries?.base || './')\n        )\n      ) {\n        results.push(componentConfig);\n      }\n    });\n\n    return results;\n  }\n\n  private registerWorkspaceComponents() {\n    const workspaceConfig = loadConfig();\n    const aspectKey = 'arco.aspect/workspace';\n    const extendsRule = workspaceConfig[aspectKey].components?.extends || {};\n    const members = workspaceConfig[aspectKey].components?.members || [];\n    const componentConfigList = this.generateWorkspaceComponentsConfig(extendsRule, members);\n\n    writeConfig({\n      [aspectKey]: {\n        components: {\n          extends: extendsRule,\n          members: [...members, ...componentConfigList],\n        },\n      },\n    });\n  }\n\n  run() {\n    const spinner = ora();\n\n    const tipAdaptWorkspaceConfig = 'adapt workspace config';\n    spinner.start(tipAdaptWorkspaceConfig);\n    // adapt project\n    const workspaceAdapter = new WorkspaceAdapter({\n      workspaceRoot: this.options.root,\n      noEmit: this.options.noEmit,\n      path: this.options.root,\n      uselessFilePatterns: this.options.uselessProjectFilePatterns,\n    });\n    workspaceAdapter.run();\n    spinner.succeed(tipAdaptWorkspaceConfig);\n\n    // adapt components\n    this.componentDirs.forEach((componentDir) => {\n      const tip = `adapt workspace component in [${path.relative(\n        this.options.root,\n        componentDir\n      )}]`;\n      spinner.start(tip);\n      const adapter = new ComponentAdapter({\n        workspaceRoot: this.options.root,\n        noEmit: this.options.noEmit,\n        path: componentDir,\n        demoDir: this.options.demoDir,\n        uselessFilePatterns: this.options.uselessComponentFilePatterns,\n      });\n\n      this.componentInfoList.push(clone(adapter.info));\n      adapter.run();\n      spinner.succeed(tip);\n    });\n\n    // adapt component packages\n    [...new Set(this.componentInfoList.map((info) => info.package.path))].forEach((packageDir) => {\n      const tip = `adapt component package in [${path.relative(this.options.root, packageDir)}]`;\n      spinner.start(tip);\n      const adapter = new PackageAdapter({\n        workspaceRoot: this.options.root,\n        noEmit: this.options.noEmit,\n        path: packageDir,\n        uselessFilePatterns: this.options.uselessPackageFilePatterns,\n      });\n      adapter.run();\n      spinner.succeed(tip);\n    });\n\n    const tipRegisterComponents = 'register components to workspace config';\n    spinner.start(tipRegisterComponents);\n    // register components to workspace config\n    try {\n      this.registerWorkspaceComponents();\n      spinner.succeed(tipRegisterComponents);\n    } catch (err) {\n      spinner.fail(tipRegisterComponents);\n      console.error(err);\n    }\n  }\n}\n"
  },
  {
    "path": "packages/migrator/src/types.ts",
    "content": "export interface AdapterOptions {\n  workspaceRoot: string;\n  path: string;\n  noEmit: boolean;\n  uselessFilePatterns: string[];\n}\n\nexport type ComponentInfo = {\n  path: string;\n  name: string;\n  title?: string;\n  description?: string;\n  labels?: string[];\n  author?: string;\n  demos: Array<{\n    path: string;\n    moduleName: string;\n    isDefault?: boolean;\n    title?: string;\n    description?: string;\n  }>;\n  package: {\n    path: string;\n  };\n};\n\nexport type MigratorOptions = {\n  /**\n   * workspace root path, default to cwd()\n   */\n  root?: string;\n  /**\n   * globs to match workspace components\n   */\n  componentDirPatterns: string | string[];\n  /**\n   * don't delete or write new files while migrating\n   */\n  noEmit?: boolean;\n  /**\n   * path of demo dir, relative to component dir\n   */\n  demoDir?: string;\n  /**\n   * globs to match useless component files, relative to component dir\n   */\n  uselessProjectFilePatterns?: string[];\n  /**\n   * globs to match useless package files, relative to component package dir\n   */\n  uselessPackageFilePatterns?: string[];\n  /**\n   * globs to match useless project files, relative to process.cwd()\n   */\n  uselessComponentFilePatterns?: string[];\n};\n"
  },
  {
    "path": "packages/migrator/src/utils.ts",
    "content": "import path, { sep as pathSep } from 'path';\nimport { parse, assign, stringify } from 'comment-json';\nimport { readFileSync, writeFileSync } from 'fs-extra';\nimport { WORKSPACE_JSONC } from './constant';\n\nexport function loadConfig(root = process.cwd()) {\n  const configPath = path.resolve(root, WORKSPACE_JSONC);\n  try {\n    return parse(readFileSync(configPath, 'utf8'));\n  } catch (err) {\n    throw new Error(`Failed to read workspace config.\\n${err}`);\n  }\n}\n\nexport function writeConfig(configExtend: Record<string, any>, root = process.cwd()) {\n  const configPath = path.resolve(root, WORKSPACE_JSONC);\n  const prevConfig = loadConfig();\n  const nextConfig = assign(prevConfig, configExtend);\n  writeFileSync(configPath, stringify(nextConfig, null, 2));\n}\n\nexport function isParentDir(parent: string, child: string) {\n  parent = parent.replace(/^\\/$/, '');\n  child = child.replace(/^\\/$/, '');\n  return parent && child && parent !== child && child.startsWith(parent);\n}\n\nexport function buildPropagationPaths(absPath: string, endPath?: string): string[] {\n  endPath = endPath?.replace(/\\/$/, '') || '';\n\n  const paths: string[] = [];\n  const pathParts = absPath.split(pathSep);\n\n  pathParts.forEach((_, index) => {\n    const part = pathParts.slice(0, index + 1).join('/');\n    if (!part || isParentDir(part, endPath)) return;\n    paths.push(part);\n  });\n\n  return paths.reverse();\n}\n"
  },
  {
    "path": "packages/migrator/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"],\n  \"compilerOptions\": {\n    \"outDir\": \"dist\",\n    \"baseUrl\": \".\"\n  }\n}\n"
  },
  {
    "path": "packages/react/package.json",
    "content": "{\n  \"name\": \"@arco-cli/react\",\n  \"version\": \"2.4.5\",\n  \"homepage\": \"https://github.com/arco-design/arco-cli\",\n  \"repository\": \"https://github.com/arco-design/arco-cli\",\n  \"scripts\": {\n    \"dev\": \"sh ../../.scripts/build.sh dev\",\n    \"build\": \"sh ../../.scripts/build.sh\",\n    \"build-type\": \"sh ../../.scripts/build-type.sh\",\n    \"clean\": \"rm -rf dist\",\n    \"clean-type\": \"find dist -name *.d.ts |xargs rm -rf\",\n    \"prepublishOnly\": \"npm run build\"\n  },\n  \"main\": \"dist/index.js\",\n  \"files\": [\n    \"dist\"\n  ],\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@arco-cli/aspect\": \"^2.4.5\",\n    \"@arco-cli/core\": \"^2.3.2\",\n    \"@arco-cli/legacy\": \"^2.3.2\",\n    \"@arco-cli/service\": \"^2.4.5\",\n    \"@arco-cli/stone\": \"^2.0.0-beta.0\",\n    \"@arco-cli/ui-foundation-react\": \"^2.4.5\",\n    \"@babel/core\": \"^7.23.5\",\n    \"@babel/plugin-proposal-class-properties\": \"^7.18.6\",\n    \"@babel/plugin-proposal-decorators\": \"^7.23.5\",\n    \"@babel/plugin-proposal-object-rest-spread\": \"^7.20.7\",\n    \"@babel/plugin-transform-modules-commonjs\": \"^7.23.3\",\n    \"@babel/plugin-transform-runtime\": \"^7.23.4\",\n    \"@babel/preset-env\": \"^7.23.5\",\n    \"@babel/preset-react\": \"^7.23.3\",\n    \"@babel/preset-typescript\": \"^7.23.3\",\n    \"@babel/runtime\": \"^7.23.5\",\n    \"@mdx-js/react\": \"^1.6.22\",\n    \"@pmmmwh/react-refresh-webpack-plugin\": \"^0.5.10\",\n    \"@svgr/webpack\": \"^6.5.1\",\n    \"@testing-library/jest-dom\": \"^5.16.5\",\n    \"babel-loader\": \"^9.1.0\",\n    \"babel-plugin-transform-typescript-metadata\": \"^0.3.2\",\n    \"babel-preset-jest\": \"^29.2.0\",\n    \"babel-preset-react-app\": \"^10.0.1\",\n    \"camelcase\": \"^6.3.0\",\n    \"css-loader\": \"^6.7.2\",\n    \"css-minimizer-webpack-plugin\": \"^4.2.2\",\n    \"fs-extra\": \"^11.1.0\",\n    \"graphql-tag\": \"^2.12.6\",\n    \"identity-obj-proxy\": \"^3.0.0\",\n    \"jest\": \"^29.2.2\",\n    \"jest-environment-jsdom\": \"^29.3.1\",\n    \"less-loader\": \"^11.1.0\",\n    \"lodash\": \"^4.17.21\",\n    \"react-app-polyfill\": \"^3.0.0\",\n    \"react-dev-utils\": \"^12.0.1\",\n    \"react-error-boundary\": \"^3.1.4\",\n    \"react-error-overlay\": \"6.0.9\",\n    \"react-refresh\": \"^0.14.0\",\n    \"sass-loader\": \"^13.2.0\",\n    \"source-map-loader\": \"^4.0.1\",\n    \"strip-ansi\": \"^7.0.1\",\n    \"style-loader\": \"^3.3.1\",\n    \"terser-webpack-plugin\": \"^5.3.6\",\n    \"ts-document\": \"^0.8.0\",\n    \"tsconfig-paths-webpack-plugin\": \"^4.0.1\",\n    \"typescript\": \"^4.9.3\",\n    \"webpack\": \"^5.75.0\",\n    \"webpack-bundle-analyzer\": \"^4.8.0\"\n  }\n}\n"
  },
  {
    "path": "packages/react/src/index.ts",
    "content": "import { ReactAspect } from './react.aspect';\n\nexport default ReactAspect;\nexport { ReactAspect };\nexport { ReactMain } from './react.main.runtime';\n"
  },
  {
    "path": "packages/react/src/jest/index.ts",
    "content": "import cjsConfig from './jest.cjs.config';\nimport esmConfig from './jest.esm.config';\n\nexport { cjsConfig, esmConfig };\n"
  },
  {
    "path": "packages/react/src/jest/jest.base.config.js",
    "content": "module.exports = {\n  setupFiles: [require.resolve('react-app-polyfill/jsdom')],\n  setupFilesAfterEnv: [require.resolve('./setupTests.js')],\n  testEnvironment: require.resolve('jest-environment-jsdom'),\n  testPathIgnorePatterns: ['/node_modules/'],\n  transform: {\n    '^.+\\\\.(less|scss|sass|css)$': require.resolve('./transformers/style-transformer.js'),\n    '^(?!.*\\\\.(js|jsx|ts|tsx|css|json)$)': require.resolve('./transformers/file-transformer.js'),\n  },\n  transformIgnorePatterns: [\n    '[/\\\\\\\\]node_modules[/\\\\\\\\].+\\\\.(js|jsx|ts|tsx|cjs)$',\n    '^.+\\\\.module\\\\.(css|sass|scss)$',\n  ],\n  modulePaths: [],\n  moduleNameMapper: {\n    '\\\\.(css|less|scss|sass)$': require.resolve('identity-obj-proxy'),\n    '^.+\\\\.module\\\\.(css|sass|scss)$': require.resolve('identity-obj-proxy'),\n  },\n  moduleFileExtensions: [\n    'web.js',\n    'js',\n    'web.ts',\n    'ts',\n    'web.tsx',\n    'tsx',\n    'json',\n    'web.jsx',\n    'jsx',\n    'node',\n  ],\n  testTimeout: 30000,\n};\n"
  },
  {
    "path": "packages/react/src/jest/jest.cjs.config.js",
    "content": "/* eslint-disable */\nconst baseConfig = require('./jest.base.config');\n\nconst cjsTransformer = require.resolve('./transformers/cjs-transformer.js');\nconst cjsTransform = { ...baseConfig.transform, '^.+\\\\.(js|jsx|ts|tsx|cjs)$': cjsTransformer };\nconst cjsConfig = { ...baseConfig, transform: cjsTransform };\n\nmodule.exports = cjsConfig;\n"
  },
  {
    "path": "packages/react/src/jest/jest.esm.config.js",
    "content": "/* eslint-disable */\nconst baseConfig = require('./jest.base.config');\n\nconst esmTransformer = require.resolve('./transformers/esm-transformer.js');\nconst esmTransform = { ...baseConfig.transform, '^.+\\\\.(js|jsx|ts|tsx)$': esmTransformer };\nconst esmConfig = {\n  ...baseConfig,\n  extensionsToTreatAsEsm: ['.ts', '.tsx', '.jsx'],\n  transform: esmTransform,\n};\n\nmodule.exports = esmConfig;\n"
  },
  {
    "path": "packages/react/src/jest/setupTests.js",
    "content": "// add babel-polyfill.\n// require('babel-polyfill');\n// jest-dom adds custom jest matchers for asserting on DOM nodes.\n// allows you to do things like:\n// expect(element).toHaveTextContent(/react/i)\n// learn more: https://github.com/testing-library/jest-dom\nrequire('@testing-library/jest-dom/extend-expect');\n\nif (typeof window !== 'undefined') {\n  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}\n\nObject.defineProperty(global, 'localStorage', {\n  value: {\n    store: {},\n    setItem(key, value) {\n      this.store[key] = value;\n    },\n    getItem(key) {\n      return this.store[key];\n    },\n    removeItem(key) {\n      delete this.store[key];\n    },\n    clear() {\n      this.store = {};\n    },\n  },\n  configurable: true,\n});\n\nObject.defineProperty(global, 'ResizeObserver', {\n  value: jest.fn().mockImplementation(() => ({\n    observe: jest.fn(),\n    unobserve: jest.fn(),\n    disconnect: jest.fn(),\n  })),\n  configurable: true,\n});\n"
  },
  {
    "path": "packages/react/src/jest/transformers/base-transformer-plugins.js",
    "content": "/* eslint-disable global-require */\n\nconst basePlugins = [\n  [require('babel-plugin-transform-typescript-metadata')],\n  [require('@babel/plugin-proposal-decorators'), { legacy: true }],\n  [require('@babel/plugin-transform-runtime')],\n  [require('@babel/plugin-proposal-object-rest-spread')],\n  [require('@babel/plugin-proposal-class-properties')],\n];\n\nmodule.exports = {\n  basePlugins,\n};\n"
  },
  {
    "path": "packages/react/src/jest/transformers/base-transformer-presets.js",
    "content": "/* eslint-disable global-require */\n\nconst basePresets = [\n  [require('@babel/preset-react'), { runtime: 'automatic' }],\n  require('@babel/preset-typescript'),\n  require('babel-preset-jest'),\n];\n\nmodule.exports = {\n  basePresets,\n};\n"
  },
  {
    "path": "packages/react/src/jest/transformers/base-transformer-process.js",
    "content": "/* eslint-disable */\nconst { transform } = require('@babel/core');\n\nconst generateProcessFunc = (presets, plugins) => {\n  return (src, filename) => {\n    const result = transform(src, {\n      sourceMap: 'inline',\n      filename,\n      presets,\n      plugins,\n      babelrc: false,\n      configFile: false,\n    });\n\n    return { code: result ? result.code : src };\n  };\n};\n\nmodule.exports = {\n  generateProcessFunc,\n};\n"
  },
  {
    "path": "packages/react/src/jest/transformers/cjs-transformer.js",
    "content": "/* eslint-disable */\nconst { generateProcessFunc } = require('./base-transformer-process');\nconst { basePlugins } = require('./base-transformer-plugins');\nconst { basePresets } = require('./base-transformer-presets');\n\nconst presets = [\n  ...basePresets,\n  [\n    require('@babel/preset-env'),\n    {\n      targets: {\n        node: 12,\n      },\n      useBuiltIns: 'usage',\n      corejs: 3,\n    },\n  ],\n];\n\nconst plugins = [[require('@babel/plugin-transform-modules-commonjs')], ...basePlugins];\n\nmodule.exports = {\n  process: generateProcessFunc(presets, plugins),\n};\n"
  },
  {
    "path": "packages/react/src/jest/transformers/esm-transformer.js",
    "content": "/* eslint-disable */\nconst { basePlugins } = require('./base-transformer-plugins');\nconst { basePresets } = require('./base-transformer-presets');\nconst { generateProcessFunc } = require('./base-transformer-process');\n\nconst presets = [\n  ...basePresets,\n  [\n    require('@babel/preset-env'),\n    {\n      modules: false,\n      targets: {\n        node: 12,\n      },\n      useBuiltIns: 'usage',\n      corejs: 3,\n    },\n  ],\n];\n\nconst plugins = basePlugins;\n\nmodule.exports = {\n  process: generateProcessFunc(presets, plugins),\n};\n"
  },
  {
    "path": "packages/react/src/jest/transformers/file-transformer.js",
    "content": "/* eslint-disable */\nconst path = require('path');\nconst camelcase = require('camelcase');\n\n// This is a custom Jest transformer turning file imports into filenames.\n// http://facebook.github.io/jest/docs/en/webpack.html\n\nmodule.exports = {\n  process(src, filename) {\n    let code = '';\n    const assetFilename = JSON.stringify(path.basename(filename));\n\n    if (filename.match(/\\.svg$/)) {\n      // Based on how SVGR generates a component name:\n      // https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6\n      const pascalCaseFilename = camelcase(path.parse(filename).name, {\n        pascalCase: true,\n      });\n      const componentName = `Svg${pascalCaseFilename}`;\n\n      code = `const React = require('react');\n      module.exports = {\n        __esModule: true,\n        default: ${assetFilename},\n        ReactComponent: React.forwardRef(function ${componentName}(props, ref) {\n          return {\n            $$typeof: Symbol.for('react.element'),\n            type: 'svg',\n            ref: ref,\n            key: null,\n            props: Object.assign({}, props, {\n              children: ${assetFilename}\n            })\n          };\n        }),\n      };`;\n    } else {\n      code =  `module.exports = ${assetFilename};`;\n    }\n\n    return {\n      code\n    };\n  },\n};\n"
  },
  {
    "path": "packages/react/src/jest/transformers/style-transformer.js",
    "content": "// This is a custom Jest transformer turning style imports into empty objects.\n// http://facebook.github.io/jest/docs/en/webpack.html\n\nmodule.exports = {\n  process() {\n    return {\n      code: '',\n    };\n  },\n  getCacheKey() {\n    // The output is always the same.\n    return 'cssTransform';\n  },\n};\n"
  },
  {
    "path": "packages/react/src/react.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\nimport { CORE_ASPECT_ID_MAP } from '@arco-cli/legacy/dist/constants';\n\nexport const ReactAspect = Aspect.create({\n  id: CORE_ASPECT_ID_MAP.ENV_REACT,\n});\n\nexport default ReactAspect;\n"
  },
  {
    "path": "packages/react/src/react.env.ts",
    "content": "import { join, resolve } from 'path';\nimport fs from 'fs-extra';\nimport { cloneDeep } from 'lodash';\nimport ts from 'typescript';\nimport { PreviewEnv, TesterEnv, ExecutionContext } from '@arco-cli/aspect/dist/envs';\nimport { BuildTask } from '@arco-cli/service/dist/builder';\nimport { JestMain } from '@arco-cli/aspect/dist/jest';\nimport { Tester } from '@arco-cli/service/dist/tester';\nimport { CompilerMain, CompilerOptions } from '@arco-cli/service/dist/compiler';\nimport type {\n  Bundler,\n  BundlerContext,\n  DevServer,\n  DevServerContext,\n} from '@arco-cli/aspect/dist/bundler';\nimport { pathNormalizeToLinux } from '@arco-cli/legacy/dist/utils/path';\nimport { SourceFile } from '@arco-cli/legacy/dist/workspace/component/sources';\nimport {\n  TypescriptMain,\n  TsConfigTransformer,\n  TypescriptCompilerOptions,\n} from '@arco-cli/aspect/dist/typescript';\nimport { WebpackConfigTransformer, WebpackMain } from '@arco-cli/aspect/dist/webpack';\nimport { MultiCompilerMain } from '@arco-cli/aspect/dist/multi-compiler';\nimport { SassMain, SassCompilerOptions } from '@arco-cli/aspect/dist/sass';\nimport { LessMain, LessCompilerOptions } from '@arco-cli/aspect/dist/less';\nimport {\n  PreviewStrategyName,\n  COMPONENT_PREVIEW_STRATEGY_NAME,\n} from '@arco-cli/service/dist/preview';\nimport { sha1 } from '@arco-cli/legacy/dist/utils';\nimport {\n  BUILD_TASK_NAME_COMPILER_ESM,\n  BUILD_TASK_NAME_COMPILER_CJS,\n} from '@arco-cli/legacy/dist/constants';\nimport type { Doclet } from '@arco-cli/legacy/dist/types';\nimport { Workspace } from '@arco-cli/aspect/dist/workspace';\n\nimport { ReactAspect } from './react.aspect';\nimport basePreviewConfigFactory from './webpack/webpack.config.base';\nimport componentPreviewDevConfigFactory from './webpack/webpack.config.component.dev';\nimport componentPreviewProdConfigFactory from './webpack/webpack.config.component.prod';\nimport { parser } from './tsdoc';\nimport type { TsDocumentOptions } from './tsdoc/parser';\n\ntype CreateCompilerTaskOptions = {\n  tsModule?: typeof ts;\n  tsConfigTransformers?: TsConfigTransformer[];\n  multiCompilerOptions?: CompilerOptions;\n  lessCompilerOptions?: LessCompilerOptions;\n  sassCompilerOptions?: SassCompilerOptions;\n};\n\ntype DocMetadataCache = Record<string, { hash: string; metadata: Doclet[] }>;\n\n// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst defaultTsConfig = require('./typescript/tsconfig.json');\n\nconst DEFAULT_ESM_DIR = 'es';\nconst DEFAULT_CJS_DIR = 'lib';\n\nexport class ReactEnv implements TesterEnv<Tester>, PreviewEnv {\n  constructor(\n    private workspace: Workspace,\n    private compiler: CompilerMain,\n    private multiCompiler: MultiCompilerMain,\n    private jest: JestMain,\n    private tsAspect: TypescriptMain,\n    private webpack: WebpackMain,\n    private less: LessMain,\n    private sass: SassMain\n  ) {}\n\n  get cacheDir(): string {\n    return this.workspace?.getCacheDir(ReactAspect.id);\n  }\n\n  get docMetadataCachePath(): string {\n    return join(this.cacheDir, 'docMetadataCache.json');\n  }\n\n  private getDocMetadataCache(): DocMetadataCache {\n    try {\n      return fs.readJSONSync(this.docMetadataCachePath);\n    } catch (err) {}\n    return {};\n  }\n\n  private cacheDocMetadata(cache: DocMetadataCache) {\n    try {\n      fs.writeJSONSync(this.docMetadataCachePath, cache);\n    } catch (err) {}\n  }\n\n  private createTsCompilerOptions(): TypescriptCompilerOptions {\n    const tsconfig = cloneDeep(defaultTsConfig);\n    const currentDir = pathNormalizeToLinux(__dirname);\n    const compileJs = true;\n    const compileJsx = true;\n    return {\n      tsconfig,\n      types: [\n        resolve(currentDir, './typescript/style.d.ts'),\n        resolve(currentDir, './typescript/asset.d.ts'),\n      ],\n      compileJs,\n      compileJsx,\n    };\n  }\n\n  private async createComponentsWebpackBundler(\n    context: BundlerContext,\n    transformers: WebpackConfigTransformer[] = []\n  ): Promise<Bundler> {\n    const baseConfig = basePreviewConfigFactory(!context.development);\n    const componentProdConfig = componentPreviewProdConfigFactory();\n\n    const defaultTransformer: WebpackConfigTransformer = (configMutator) => {\n      const merged = configMutator.merge([baseConfig, componentProdConfig]);\n      return merged;\n    };\n    const mergedTransformers = [defaultTransformer, ...transformers];\n    return this.webpack.createBundler(context, mergedTransformers);\n  }\n\n  private createCjsJestTester(jestConfigPath?: string, jestModulePath?: string): Tester {\n    const defaultConfigPath = join(__dirname, './jest/jest.cjs.config.js');\n    const config = jestConfigPath || defaultConfigPath;\n    return this.jest.createTester(config, jestModulePath || require.resolve('jest'));\n  }\n\n  private createEsmCompiler(transformers: TsConfigTransformer[] = [], tsModule = ts) {\n    const tsCompileOptions = this.createTsCompilerOptions();\n    return this.tsAspect.createEsmCompiler(tsCompileOptions, transformers, tsModule);\n  }\n\n  private createCjsCompiler(transformers: TsConfigTransformer[] = [], tsModule = ts) {\n    const tsCompileOptions = this.createTsCompilerOptions();\n    return this.tsAspect.createCjsCompiler(tsCompileOptions, transformers, tsModule);\n  }\n\n  private createEsmCompilerTask({\n    tsModule,\n    tsConfigTransformers,\n    multiCompilerOptions,\n    lessCompilerOptions,\n    sassCompilerOptions,\n  }: CreateCompilerTaskOptions = {}) {\n    return this.compiler.createTask(\n      BUILD_TASK_NAME_COMPILER_ESM,\n      this.multiCompiler.createCompiler(\n        [\n          this.createEsmCompiler(tsConfigTransformers, tsModule),\n          this.less.createCompiler(lessCompilerOptions),\n          this.sass.createCompiler(sassCompilerOptions),\n        ],\n        multiCompilerOptions\n      )\n    );\n  }\n\n  private createCjsCompilerTask({\n    tsModule,\n    tsConfigTransformers,\n    multiCompilerOptions,\n    lessCompilerOptions,\n    sassCompilerOptions,\n  }: CreateCompilerTaskOptions = {}) {\n    return this.compiler.createTask(\n      BUILD_TASK_NAME_COMPILER_CJS,\n      this.multiCompiler.createCompiler(\n        [\n          this.createCjsCompiler(tsConfigTransformers, tsModule),\n          this.less.createCompiler(lessCompilerOptions),\n          this.sass.createCompiler(sassCompilerOptions),\n        ],\n        multiCompilerOptions\n      )\n    );\n  }\n\n  /**\n   * required for `arco start`\n   */\n  getDevEnvId(id?: string) {\n    return typeof id === 'string' ? id : ReactAspect.id;\n  }\n\n  getTester(jestConfigPath: string, jestModulePath?: string): Tester {\n    return this.createCjsJestTester(jestConfigPath, jestModulePath);\n  }\n\n  getDevServer(\n    context: DevServerContext,\n    transformers: WebpackConfigTransformer[] = []\n  ): DevServer {\n    const baseConfig = basePreviewConfigFactory(false);\n    const componentDevConfig = componentPreviewDevConfigFactory(\n      (context as any as ExecutionContext).id\n    );\n\n    const defaultTransformer: WebpackConfigTransformer = (configMutator) => {\n      const merged = configMutator.merge([baseConfig, componentDevConfig]);\n      return merged;\n    };\n\n    return this.webpack.createDevServer(context, [defaultTransformer, ...transformers]);\n  }\n\n  getDocsTemplate() {\n    return require.resolve('@arco-cli/ui-foundation-react/dist/preview/index.js');\n  }\n\n  getDocsMetadata(files: SourceFile[], options?: TsDocumentOptions): Doclet[] {\n    const cache = this.getDocMetadataCache();\n    const result = files.reduce((acc, file) => {\n      if (!file?.contents) return acc;\n\n      const hash = sha1(file.contents);\n\n      if (!cache[file.path] || cache[file.path].hash !== hash) {\n        const docletList = parser(file, options);\n        cache[file.path] = {\n          hash,\n          metadata: docletList,\n        };\n      }\n\n      return acc.concat(cache[file.path]?.metadata);\n    }, [] as Doclet[]);\n\n    this.cacheDocMetadata(cache);\n\n    return result;\n  }\n\n  getPreviewConfig() {\n    return {\n      strategyName: COMPONENT_PREVIEW_STRATEGY_NAME as PreviewStrategyName,\n      splitComponentBundle: true,\n      isScaling: true,\n    };\n  }\n\n  async getBundler(\n    context: BundlerContext,\n    transformers: WebpackConfigTransformer[] = []\n  ): Promise<Bundler> {\n    return this.createComponentsWebpackBundler(context, transformers);\n  }\n\n  getBuildPipe(modifiers: CreateCompilerTaskOptions): BuildTask[] {\n    return [\n      this.createEsmCompilerTask({\n        ...modifiers,\n        multiCompilerOptions: { distDir: DEFAULT_ESM_DIR },\n      }),\n      this.createCjsCompilerTask({\n        ...modifiers,\n        multiCompilerOptions: { distDir: DEFAULT_CJS_DIR },\n      }),\n    ];\n  }\n}\n"
  },
  {
    "path": "packages/react/src/react.main.runtime.ts",
    "content": "import path from 'path';\nimport fs from 'fs-extra';\nimport { MainRuntime } from '@arco-cli/core/dist/cli';\nimport { Logger, LoggerMain, LoggerAspect } from '@arco-cli/core/dist/logger';\nimport {\n  EnvsAspect,\n  EnvsMain,\n  ExecutionContext,\n  EnvTransformer,\n  Environment,\n} from '@arco-cli/aspect/dist/envs';\nimport { JestAspect, JestMain } from '@arco-cli/aspect/dist/jest';\nimport { WebpackAspect, WebpackMain } from '@arco-cli/aspect/dist/webpack';\nimport { CompilerAspect, CompilerMain } from '@arco-cli/service/dist/compiler';\nimport { MultiCompilerAspect, MultiCompilerMain } from '@arco-cli/aspect/dist/multi-compiler';\nimport { TypescriptAspect, TypescriptMain } from '@arco-cli/aspect/dist/typescript';\nimport { SassAspect, SassMain } from '@arco-cli/aspect/dist/sass';\nimport { LessAspect, LessMain } from '@arco-cli/aspect/dist/less';\nimport { WorkspaceAspect, Workspace } from '@arco-cli/aspect/dist/workspace';\nimport { DEFAULT_ENV_CONFIG_PATH } from '@arco-cli/legacy/dist/constants';\nimport type { ArcoEnvConfig } from '@arco-cli/aspect/dist/envs/types';\nimport type { BundlerContext, DevServerContext } from '@arco-cli/aspect/dist/bundler';\n\nimport { ReactAspect } from './react.aspect';\nimport { ReactEnv } from './react.env';\n\nexport class ReactMain {\n  static runtime = MainRuntime;\n\n  static dependencies = [\n    LoggerAspect,\n    WorkspaceAspect,\n    CompilerAspect,\n    MultiCompilerAspect,\n    EnvsAspect,\n    JestAspect,\n    TypescriptAspect,\n    WebpackAspect,\n    LessAspect,\n    SassAspect,\n  ];\n\n  static slots = [];\n\n  static provider([\n    loggerMain,\n    workspace,\n    compiler,\n    multiCompiler,\n    envs,\n    jestMain,\n    tsMain,\n    webpackMain,\n    lessMain,\n    sassMain,\n  ]: [\n    LoggerMain,\n    Workspace,\n    CompilerMain,\n    MultiCompilerMain,\n    EnvsMain,\n    JestMain,\n    TypescriptMain,\n    WebpackMain,\n    LessMain,\n    SassMain\n  ]) {\n    const defaultReactEnv = new ReactEnv(\n      workspace,\n      compiler,\n      multiCompiler,\n      jestMain,\n      tsMain,\n      webpackMain,\n      lessMain,\n      sassMain\n    );\n\n    const logger = loggerMain.createLogger(ReactAspect.id);\n    const reactMain = new ReactMain(defaultReactEnv, workspace, logger, envs);\n    const extendedReactEnv = reactMain.extendEnvConfigFromUser();\n\n    envs.registerEnv(extendedReactEnv);\n\n    return reactMain;\n  }\n\n  constructor(\n    private defaultReactEnv: ReactEnv,\n    private workspace: Workspace,\n    private logger: Logger,\n    private envs: EnvsMain\n  ) {}\n\n  private extendEnvConfigFromUser(): Environment {\n    let defineConfig = null;\n    const envConfigPath = path.resolve(this.workspace.path, DEFAULT_ENV_CONFIG_PATH);\n\n    if (fs.existsSync(envConfigPath)) {\n      try {\n        defineConfig = require(envConfigPath);\n      } catch (error) {\n        this.logger.error(`failed to extend ${ReactAspect.id} config from ${envConfigPath}`, error);\n        throw new Error(`Failed to extend ${ReactAspect.id} config. Details:\\n${error}`);\n      }\n    }\n\n    if (typeof defineConfig === 'function') {\n      try {\n        const userConfig: ArcoEnvConfig = defineConfig(ReactAspect.id);\n        const envTransformers: EnvTransformer[] = [];\n\n        userConfig.jest && envTransformers.push(this.useJest(userConfig.jest));\n        userConfig.webpack && envTransformers.push(this.useWebpack(userConfig.webpack));\n        userConfig.tsDocument && envTransformers.push(this.useTsDocument(userConfig.tsDocument));\n\n        if (userConfig.typescript || userConfig.less || userConfig.sass) {\n          envTransformers.push(\n            this.useBuildPipe({\n              typescript: userConfig.typescript,\n              less: userConfig.less,\n              sass: userConfig.sass,\n            })\n          );\n        }\n\n        if (envTransformers.length) {\n          return this.compose(envTransformers);\n        }\n      } catch (error) {\n        this.logger.error(`${ReactAspect.id} failed to extend env config from user`, error);\n      }\n    }\n\n    return this.defaultReactEnv;\n  }\n\n  /**\n   * override the env's build pile config for build time.\n   * include typescript / less / sass options\n   */\n  useBuildPipe(modifiers: Pick<ArcoEnvConfig, 'typescript' | 'less' | 'sass'> = {}) {\n    const overrides: any = {};\n    const { tsModule, buildConfig: tsConfigTransformers } = modifiers.typescript || {};\n    const lessCompilerOptions = modifiers.less;\n    const sassCompilerOptions = modifiers.sass;\n\n    if (tsModule || tsConfigTransformers || lessCompilerOptions || sassCompilerOptions) {\n      overrides.getBuildPipe = () => {\n        return this.defaultReactEnv.getBuildPipe({\n          tsModule,\n          tsConfigTransformers,\n          lessCompilerOptions,\n          sassCompilerOptions,\n        });\n      };\n    }\n\n    return this.envs.override(overrides);\n  }\n\n  /**\n   * override the env's dev server and preview webpack configurations.\n   * Replaces both overrideDevServerConfig and overridePreviewConfig\n   */\n  useWebpack(modifiers: ArcoEnvConfig['webpack'] = {}) {\n    const overrides: any = {};\n    const devServerTransformers = modifiers.devServerConfig;\n    if (devServerTransformers) {\n      overrides.getDevServer = (context: DevServerContext) =>\n        this.defaultReactEnv.getDevServer(context, devServerTransformers);\n      overrides.getDevEnvId = (context: DevServerContext) =>\n        this.defaultReactEnv.getDevEnvId((context as unknown as ExecutionContext).envDefinition.id);\n    }\n    const previewTransformers = modifiers.previewConfig;\n    if (previewTransformers) {\n      overrides.getBundler = (context: BundlerContext) =>\n        this.defaultReactEnv.getBundler(context, previewTransformers);\n    }\n    return this.envs.override(overrides);\n  }\n\n  /**\n   * override the jest configuration.\n   */\n  useJest(modifiers: ArcoEnvConfig['jest'] = {}) {\n    const { jestConfigPath, jestModulePath } = modifiers;\n    return this.envs.override({\n      getTester: () => this.defaultReactEnv.getTester(jestConfigPath, jestModulePath),\n    });\n  }\n\n  useTsDocument(modifiers: ArcoEnvConfig['tsDocument']) {\n    const { tsDocumentOptions } = modifiers;\n    return this.envs.override({\n      getDocsMetadata: (files: any) =>\n        this.defaultReactEnv.getDocsMetadata(files, tsDocumentOptions),\n    });\n  }\n\n  /**\n   * create a new composition of the react environment.\n   */\n  compose(transformers: EnvTransformer[]) {\n    return this.envs.compose(this.defaultReactEnv, transformers);\n  }\n}\n\nReactAspect.addRuntime(ReactMain);\n"
  },
  {
    "path": "packages/react/src/tsdoc/index.ts",
    "content": "export { parser } from './parser';\n"
  },
  {
    "path": "packages/react/src/tsdoc/parser.ts",
    "content": "import { generate, Project } from 'ts-document';\nimport type { GenerateConfig } from 'ts-document/lib/interface';\nimport {\n  InterfaceSchema,\n  FunctionSchema,\n  NestedTypeSchema,\n  TagType,\n  PropertyType,\n} from 'ts-document/lib/interface';\nimport logger from '@arco-cli/legacy/dist/logger';\nimport { SourceFile } from '@arco-cli/legacy/dist/workspace/component/sources';\nimport type { Doclet, APIProperty } from '@arco-cli/legacy/dist/types';\n\nexport type TsDocumentOptions = Partial<GenerateConfig>;\n\n/**\n * get doc-prop for preview from parsed ts-property\n */\nfunction getDocProp({ name, type, isOptional, tags }: PropertyType): APIProperty {\n  const findDescription = (tags: TagType[]): string => {\n    const enDesc = tags.find(({ name }) => name === 'en');\n    const zhDesc = tags.find(({ name }) => name === 'zh');\n    return zhDesc?.value || enDesc?.value || '';\n  };\n  const findDefault = (tags: TagType[]): string => {\n    return tags.find(({ name }) => name === 'defaultValue')?.value;\n  };\n  const findVersion = (tags: TagType[]): string => {\n    return tags.find(({ name }) => name === 'version')?.value;\n  };\n\n  return {\n    name,\n    type,\n    required: !isOptional,\n    description: findDescription(tags),\n    defaultValue: findDefault(tags),\n    version: findVersion(tags),\n  };\n}\n\nexport function parser(file: SourceFile, options?: TsDocumentOptions): Doclet[] {\n  const filePath = file.relative;\n  let doclets: Doclet[] = [];\n\n  try {\n    const componentsInfo = generate(file.path, {\n      sourceFilesPaths: [file.path],\n      escapeChars: false,\n      strictDeclarationOrder: true,\n      project: new Project({\n        compilerOptions: {\n          jsx: 'react' as any,\n        },\n      }),\n      defaultTypeMap: {},\n      ...options,\n    });\n\n    // componentInfo will be an Array when strictDeclarationOrder is true\n    if (Array.isArray(componentsInfo)) {\n      doclets = componentsInfo.map(({ title, schema }) => {\n        let properties = [];\n        let type = null;\n\n        if (typeof (schema as NestedTypeSchema).data === 'string') {\n          type = (schema as NestedTypeSchema).data;\n        } else if (Array.isArray((schema as InterfaceSchema).data)) {\n          properties = (schema as InterfaceSchema).data.map(getDocProp);\n        } else if (Array.isArray((schema as FunctionSchema).params)) {\n          properties = (schema as FunctionSchema).params.map((parsedProp) => {\n            const docProp = getDocProp(parsedProp);\n            if (parsedProp.initializerText) {\n              docProp.description = parsedProp.initializerText;\n            }\n            return docProp;\n          });\n        }\n\n        return {\n          filePath,\n          name: title,\n          type,\n          properties,\n        };\n      });\n    }\n  } catch (err) {\n    logger.trace(`failed parsing docs using docgen on path ${filePath} with error`, err);\n  }\n\n  return doclets;\n}\n"
  },
  {
    "path": "packages/react/src/types/reactConfig.ts",
    "content": "export type ReactConfig = {\n  // envConfigPath?: string;\n};\n"
  },
  {
    "path": "packages/react/src/typescript/asset.d.ts",
    "content": "declare module '*.png' {\n  const value: any;\n  export = value;\n}\n\ndeclare module '*.svg' {\n  import type { FunctionComponent, SVGProps } from 'react';\n\n  export const ReactComponent: FunctionComponent<SVGProps<SVGSVGElement> & { title?: string }>;\n  const src: string;\n  export default src;\n}\n\ndeclare module '*.jpg' {\n  const value: any;\n  export = value;\n}\n\ndeclare module '*.jpeg' {\n  const value: any;\n  export = value;\n}\n\ndeclare module '*.gif' {\n  const value: any;\n  export = value;\n}\n\ndeclare module '*.bmp' {\n  const value: any;\n  export = value;\n}\n"
  },
  {
    "path": "packages/react/src/typescript/style.d.ts",
    "content": "declare module '*.module.css' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.module.scss' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.module.sass' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.module.less' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.less' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.css' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.sass' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.scss' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.mdx' {\n  const component: any;\n  export default component;\n}\n"
  },
  {
    "path": "packages/react/src/typescript/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"rootDir\": \".\",\n    \"outDir\": \"dist\",\n    \"lib\": [\"es2019\", \"DOM\", \"ES6\", \"DOM.Iterable\"],\n    \"target\": \"es2015\",\n    \"module\": \"es2020\",\n    \"jsx\": \"react\",\n    \"moduleResolution\": \"node\",\n    \"allowJs\": true,\n    \"sourceMap\": true,\n    \"declaration\": true,\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": true,\n    \"resolveJsonModule\": true,\n    \"experimentalDecorators\": true\n  },\n  \"exclude\": [\"dist\"]\n}\n"
  },
  {
    "path": "packages/react/src/webpack/overlay/formatWebpackMessages.js",
    "content": "/* eslint-disable */\n/**\n * Copyright (c) 2015-present, Facebook, Inc.\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\n'use strict';\n\nconst friendlySyntaxErrorLabel = 'Syntax error:';\n\nfunction isLikelyASyntaxError(message) {\n  return message.indexOf(friendlySyntaxErrorLabel) !== -1;\n}\n\n// Cleans up webpack error messages.\nfunction formatMessage(message) {\n  let lines = [];\n\n  if (typeof message === 'string') {\n    lines = message.split('\\n');\n  } else if ('message' in message) {\n    lines = message['message'].split('\\n');\n  } else if (Array.isArray(message)) {\n    message.forEach((message) => {\n      if ('message' in message) {\n        lines = message['message'].split('\\n');\n      }\n    });\n  }\n\n  // Strip webpack-added headers off errors/warnings\n  // https://github.com/webpack/webpack/blob/master/lib/ModuleError.js\n  lines = lines.filter((line) => !/Module [A-z ]+\\(from/.test(line));\n\n  // Transform parsing error into syntax error\n  // TODO: move this to our ESLint formatter?\n  lines = lines.map((line) => {\n    const parsingError = /Line (\\d+):(?:(\\d+):)?\\s*Parsing error: (.+)$/.exec(line);\n    if (!parsingError) {\n      return line;\n    }\n    const [, errorLine, errorColumn, errorMessage] = parsingError;\n    return `${friendlySyntaxErrorLabel} ${errorMessage} (${errorLine}:${errorColumn})`;\n  });\n\n  message = lines.join('\\n');\n  // Smoosh syntax errors (commonly found in CSS)\n  message = message.replace(\n    /SyntaxError\\s+\\((\\d+):(\\d+)\\)\\s*(.+?)\\n/g,\n    `${friendlySyntaxErrorLabel} $3 ($1:$2)\\n`\n  );\n  // Clean up export errors\n  message = message.replace(\n    /^.*export '(.+?)' was not found in '(.+?)'.*$/gm,\n    `Attempted import error: '$1' is not exported from '$2'.`\n  );\n  message = message.replace(\n    /^.*export 'default' \\(imported as '(.+?)'\\) was not found in '(.+?)'.*$/gm,\n    `Attempted import error: '$2' does not contain a default export (imported as '$1').`\n  );\n  message = message.replace(\n    /^.*export '(.+?)' \\(imported as '(.+?)'\\) was not found in '(.+?)'.*$/gm,\n    `Attempted import error: '$1' is not exported from '$3' (imported as '$2').`\n  );\n  lines = message.split('\\n');\n\n  // Remove leading newline\n  if (lines.length > 2 && lines[1].trim() === '') {\n    lines.splice(1, 1);\n  }\n  // Clean up file name\n  lines[0] = lines[0].replace(/^(.*) \\d+:\\d+-\\d+$/, '$1');\n\n  // Cleans up verbose \"module not found\" messages for files and packages.\n  if (lines[1] && lines[1].indexOf('Module not found: ') === 0) {\n    lines = [\n      lines[0],\n      lines[1]\n        .replace('Error: ', '')\n        .replace('Module not found: Cannot find file:', 'Cannot find file:'),\n    ];\n  }\n\n  // Add helpful message for users trying to use Sass for the first time\n  if (lines[1] && lines[1].match(/Cannot find module.+sass/)) {\n    lines[1] = 'To import Sass files, you first need to install sass.\\n';\n    lines[1] += 'Run `bit install sass` inside your workspace.';\n  }\n\n  message = lines.join('\\n');\n  // Internal stacks are generally useless so we strip them... with the\n  // exception of stacks containing `webpack:` because they're normally\n  // from user code generated by webpack. For more information see\n  // https://github.com/facebook/create-react-app/pull/1050\n  message = message.replace(/^\\s*at\\s((?!webpack:).)*:\\d+:\\d+[\\s)]*(\\n|$)/gm, ''); // at ... ...:x:y\n  message = message.replace(/^\\s*at\\s<anonymous>(\\n|$)/gm, ''); // at <anonymous>\n  lines = message.split('\\n');\n\n  // Remove duplicated newlines\n  lines = lines.filter(\n    (line, index, arr) => index === 0 || line.trim() !== '' || line.trim() !== arr[index - 1].trim()\n  );\n\n  // Reassemble the message\n  message = lines.join('\\n');\n  return message.trim();\n}\n\nfunction formatWebpackMessages(json) {\n  const formattedErrors = json.errors.map(formatMessage);\n  const formattedWarnings = json.warnings.map(formatMessage);\n  const result = { errors: formattedErrors, warnings: formattedWarnings };\n  if (result.errors.some(isLikelyASyntaxError)) {\n    // If there are any syntax errors, show just them.\n    result.errors = result.errors.filter(isLikelyASyntaxError);\n  }\n  return result;\n}\n\nmodule.exports = formatWebpackMessages;\n"
  },
  {
    "path": "packages/react/src/webpack/overlay/launchEditorEndpoint.js",
    "content": "/* eslint-disable */\n/**\n * Copyright (c) 2015-present, Facebook, Inc.\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'use strict';\n\n// TODO: we might want to make this injectable to support DEV-time non-root URLs.\nmodule.exports = '/__open-stack-frame-in-editor';\n"
  },
  {
    "path": "packages/react/src/webpack/overlay/refreshOverlayInterop.js",
    "content": "/* eslint-disable */\n/** this file was copied as is from react-dev-utils/refreshOverlayInterop */\n\n// @remove-on-eject-begin\n/**\n * Copyright (c) 2015-present, Facebook, Inc.\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// @remove-on-eject-end\n'use strict';\n\nconst { dismissRuntimeErrors, reportRuntimeError } = require('react-error-overlay');\n\nmodule.exports = {\n  clearRuntimeErrors: dismissRuntimeErrors,\n  handleRuntimeError: reportRuntimeError,\n};\n"
  },
  {
    "path": "packages/react/src/webpack/overlay/webpackHotDevClient.js",
    "content": "/* eslint-disable */\n/*\n * this file was copied as is from `react-dev-utils/webpackHotDevClient`\n * and adjusted for our socket url.\n *\n * we use just set process.env.WDS_* with the EnvironmentPlugin or DefinePlugin\n * once we get react-error-overlay up and running again\n */\n\n/**\n * Copyright (c) 2015-present, Facebook, Inc.\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\n'use strict';\n\n// This alternative WebpackDevServer combines the functionality of:\n// https://github.com/webpack/webpack-dev-server/blob/webpack-1/client/index.js\n// https://github.com/webpack/webpack/blob/webpack-1/hot/dev-server.js\n\n// It only supports their simplest configuration (hot updates on same server).\n// It makes some opinionated choices on top, like adding a syntax error overlay\n// that looks similar to our console output. The error overlay is inspired by:\n// https://github.com/glenjamin/webpack-hot-middleware\n\nvar stripAnsi = require('strip-ansi');\nvar url = require('url');\nvar launchEditorEndpoint = require('./launchEditorEndpoint');\nvar formatWebpackMessages = require('./formatWebpackMessages');\nvar ErrorOverlay = require('react-error-overlay');\n\nErrorOverlay.setEditorHandler(function editorHandler(errorLocation) {\n  // Keep this sync with errorOverlayMiddleware.js\n  fetch(\n    launchEditorEndpoint +\n      '?fileName=' +\n      window.encodeURIComponent(errorLocation.fileName) +\n      '&lineNumber=' +\n      window.encodeURIComponent(errorLocation.lineNumber || 1) +\n      '&colNumber=' +\n      window.encodeURIComponent(errorLocation.colNumber || 1)\n  );\n});\n\n// We need to keep track of if there has been a runtime error.\n// Essentially, we cannot guarantee application state was not corrupted by the\n// runtime error. To prevent confusing behavior, we forcibly reload the entire\n// application. This is handled below when we are notified of a compile (code\n// change).\n// See https://github.com/facebook/create-react-app/issues/3096\nvar hadRuntimeError = false;\nErrorOverlay.startReportingRuntimeErrors({\n  onError: function () {\n    hadRuntimeError = true;\n  },\n  filename: '/static/js/bundle.js',\n});\n\nif (module.hot && typeof module.hot.dispose === 'function') {\n  module.hot.dispose(function () {\n    // TODO: why do we need this?\n    ErrorOverlay.stopReportingRuntimeErrors();\n  });\n}\n\nconst querystring = module.id.substring(module.id.indexOf('?'));\nconst urlParams = new URLSearchParams(querystring);\n\n// Connect to WebpackDevServer via a socket.\nvar connection = new WebSocket(\n  url.format({\n    protocol: window.location.protocol === 'https:' ? 'wss' : 'ws',\n    hostname: window.location.hostname,\n    port: window.location.port,\n    pathname: urlParams.get('sockPath') || '/ws',\n    slashes: true,\n  })\n);\n\n// Unlike WebpackDevServer client, we won't try to reconnect\n// to avoid spamming the console. Disconnect usually happens\n// when developer stops the server.\nconnection.onclose = function () {\n  if (typeof console !== 'undefined' && typeof console.info === 'function') {\n    console.info('The development server has disconnected.\\nRefresh the page if necessary.');\n  }\n};\n\n// Remember some state related to hot module replacement.\nvar isFirstCompilation = true;\nvar mostRecentCompilationHash = null;\nvar hasCompileErrors = false;\n\nfunction clearOutdatedErrors() {\n  // Clean up outdated compile errors, if any.\n  if (typeof console !== 'undefined' && typeof console.clear === 'function') {\n    if (hasCompileErrors) {\n      console.clear();\n    }\n  }\n}\n\n// Successful compilation.\nfunction handleSuccess() {\n  clearOutdatedErrors();\n\n  var isHotUpdate = !isFirstCompilation;\n  isFirstCompilation = false;\n  hasCompileErrors = false;\n\n  // Attempt to apply hot updates or reload.\n  if (isHotUpdate) {\n    tryApplyUpdates(function onHotUpdateSuccess() {\n      // Only dismiss it when we're sure it's a hot update.\n      // Otherwise it would flicker right before the reload.\n      tryDismissErrorOverlay();\n    });\n  }\n}\n\n// Compilation with warnings (e.g. ESLint).\nfunction handleWarnings(warnings) {\n  clearOutdatedErrors();\n\n  var isHotUpdate = !isFirstCompilation;\n  isFirstCompilation = false;\n  hasCompileErrors = false;\n\n  function printWarnings() {\n    // Print warnings to the console.\n    var formatted = formatWebpackMessages({\n      warnings: warnings,\n      errors: [],\n    });\n\n    if (typeof console !== 'undefined' && typeof console.warn === 'function') {\n      for (var i = 0; i < formatted.warnings.length; i++) {\n        if (i === 5) {\n          console.warn(\n            'There were more warnings in other files.\\n' +\n              'You can find a complete log in the terminal.'\n          );\n          break;\n        }\n        console.warn(stripAnsi(formatted.warnings[i]));\n      }\n    }\n  }\n\n  printWarnings();\n\n  // Attempt to apply hot updates or reload.\n  if (isHotUpdate) {\n    tryApplyUpdates(function onSuccessfulHotUpdate() {\n      // Only dismiss it when we're sure it's a hot update.\n      // Otherwise it would flicker right before the reload.\n      tryDismissErrorOverlay();\n    });\n  }\n}\n\n// Compilation with errors (e.g. syntax error or missing modules).\nfunction handleErrors(errors) {\n  clearOutdatedErrors();\n\n  isFirstCompilation = false;\n  hasCompileErrors = true;\n\n  // \"Massage\" webpack messages.\n  var formatted = formatWebpackMessages({\n    errors: errors,\n    warnings: [],\n  });\n\n  // Only show the first error.\n  ErrorOverlay.reportBuildError(formatted.errors[0]);\n\n  // Also log them to the console.\n  if (typeof console !== 'undefined' && typeof console.error === 'function') {\n    for (var i = 0; i < formatted.errors.length; i++) {\n      console.error(stripAnsi(formatted.errors[i]));\n    }\n  }\n\n  // Do not attempt to reload now.\n  // We will reload on next success instead.\n}\n\nfunction tryDismissErrorOverlay() {\n  if (!hasCompileErrors) {\n    ErrorOverlay.dismissBuildError();\n  }\n}\n\n// There is a newer version of the code available.\nfunction handleAvailableHash(hash) {\n  // Update last known compilation hash.\n  mostRecentCompilationHash = hash;\n}\n\n// Handle messages from the server.\nconnection.onmessage = function (e) {\n  var message = JSON.parse(e.data);\n  switch (message.type) {\n    case 'hash':\n      handleAvailableHash(message.data);\n      break;\n    case 'still-ok':\n    case 'ok':\n      handleSuccess();\n      break;\n    case 'content-changed':\n      // Triggered when a file from `contentBase` changed.\n      window.location.reload();\n      break;\n    case 'warnings':\n      handleWarnings(message.data);\n      break;\n    case 'errors':\n      handleErrors(message.data);\n      break;\n    default:\n    // Do nothing.\n  }\n};\n\n// Is there a newer version of this code available?\nfunction isUpdateAvailable() {\n  /* globals __webpack_hash__ */\n  // __webpack_hash__ is the hash of the current compilation.\n  // It's a global variable injected by webpack.\n  return mostRecentCompilationHash !== __webpack_hash__;\n}\n\n// webpack disallows updates in other states.\nfunction canApplyUpdates() {\n  return module.hot.status() === 'idle';\n}\n\nfunction canAcceptErrors() {\n  // NOTE: This var is injected by Webpack's DefinePlugin, and is a boolean instead of string.\n  const hasReactRefresh = process.env.FAST_REFRESH;\n\n  const status = module.hot.status();\n  // React refresh can handle hot-reloading over errors.\n  // However, when hot-reload status is abort or fail,\n  // it indicates the current update cannot be applied safely,\n  // and thus we should bail out to a forced reload for consistency.\n  return hasReactRefresh && ['abort', 'fail'].indexOf(status) === -1;\n}\n\n// Attempt to update code on the fly, fall back to a hard reload.\nfunction tryApplyUpdates(onHotUpdateSuccess) {\n  if (!module.hot) {\n    // HotModuleReplacementPlugin is not in webpack configuration.\n    window.location.reload();\n    return;\n  }\n\n  if (!isUpdateAvailable() || !canApplyUpdates()) {\n    return;\n  }\n\n  function handleApplyUpdates(err, updatedModules) {\n    const haveErrors = err || hadRuntimeError;\n    // When there is no error but updatedModules is unavailable,\n    // it indicates a critical failure in hot-reloading,\n    // e.g. server is not ready to serve new bundle,\n    // and hence we need to do a forced reload.\n    const needsForcedReload = !err && !updatedModules;\n    if ((haveErrors && !canAcceptErrors()) || needsForcedReload) {\n      window.location.reload();\n      return;\n    }\n\n    if (typeof onHotUpdateSuccess === 'function') {\n      // Maybe we want to do something.\n      onHotUpdateSuccess();\n    }\n\n    if (isUpdateAvailable()) {\n      // While we were updating, there was a new update! Do it again.\n      tryApplyUpdates();\n    }\n  }\n\n  // https://webpack.github.io/docs/hot-module-replacement.html#check\n  var result = module.hot.check(/* autoApply */ true, handleApplyUpdates);\n\n  // // webpack 2 returns a Promise instead of invoking a callback\n  if (result && result.then) {\n    result.then(\n      function (updatedModules) {\n        handleApplyUpdates(null, updatedModules);\n      },\n      function (err) {\n        handleApplyUpdates(err, null);\n      }\n    );\n  }\n}\n"
  },
  {
    "path": "packages/react/src/webpack/webpack.config.base.ts",
    "content": "import path from 'path';\nimport fs from 'fs-extra';\nimport 'style-loader';\nimport { Configuration } from 'webpack';\nimport { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin';\nimport getCSSModuleLocalIdent from 'react-dev-utils/getCSSModuleLocalIdent';\nimport * as stylesRegexps from '@arco-cli/legacy/dist/utils/regexp/style';\nimport { generateStyleLoaders, GenerateStyleLoadersOptions } from '@arco-cli/aspect/dist/webpack';\n\nconst MODULE_FILE_EXTENSIONS = [\n  'web.mjs',\n  'mjs',\n  'web.js',\n  'js',\n  'cjs',\n  'web.ts',\n  'ts',\n  'web.tsx',\n  'tsx',\n  'json',\n  'web.jsx',\n  'jsx',\n  'mdx',\n  'md',\n];\n\nconst IMAGE_INLINE_SIZE_LIMIT = parseInt(process.env.IMAGE_INLINE_SIZE_LIMIT || '10000');\n\nfunction EmptyPlugin() {\n  this.apply = function () {};\n}\n\nexport default function (isEnvProduction = false): Configuration {\n  // \"postcss\" loader applies autoprefixer to our CSS.\n  // \"css\" loader resolves paths in CSS and adds assets as dependencies.\n  // \"style\" loader turns CSS into JS modules that inject <style> tags.\n  // By default, we keep style in the js files, you can use MiniCSSExtractPlugin\n  // to extract that CSS to a file in production\n  const baseStyleLoadersOptions: GenerateStyleLoadersOptions = {\n    injectingLoader: require.resolve('style-loader'),\n    cssLoaderPath: require.resolve('css-loader'),\n    cssLoaderOpts: undefined,\n  };\n  const lessLoaderPath = require.resolve('less-loader');\n  const sassLoaderPath = require.resolve('sass-loader');\n\n  const webpackResolveAlias = {\n    '@mdx-js/react': require.resolve('@mdx-js/react'),\n  };\n\n  // react/jsx-dev-runtime.js is not exist in React 18\n  try {\n    Object.assign(webpackResolveAlias, {\n      'react/jsx-dev-runtime': require.resolve('react/jsx-dev-runtime.js'),\n      'react/jsx-runtime': require.resolve('react/jsx-runtime.js'),\n    });\n  } catch (err) {}\n\n  return {\n    devtool: false,\n\n    resolve: {\n      // These are the reasonable defaults supported by the Node ecosystem.\n      // We also include JSX as a common component filename extension to support\n      // some tools, although we do not recommend using it, see:\n      // https://github.com/facebook/create-react-app/issues/290\n      // `web` extension prefixes have been added for better support\n      // for React Native Web.\n      extensions: MODULE_FILE_EXTENSIONS.map((ext) => `.${ext}`),\n\n      alias: webpackResolveAlias,\n\n      plugins: [\n        (() => {\n          // an error will throw if tsconfig.json not exist\n          const defaultTsconfigPath = path.resolve(process.cwd(), 'tsconfig.json');\n          return fs.existsSync(defaultTsconfigPath)\n            ? new TsconfigPathsPlugin({\n                silent: true,\n                configFile: defaultTsconfigPath,\n              })\n            : new EmptyPlugin();\n        })(),\n      ],\n    },\n\n    module: {\n      parser: {\n        javascript: {\n          importExportsPresence: 'warn',\n        },\n      },\n      rules: [\n        {\n          test: /\\.m?js/,\n          resolve: {\n            fullySpecified: false,\n          },\n        },\n        {\n          // \"oneOf\" will traverse all following loaders until one will\n          // match the requirements. When no loader matches it will fall\n          // back to the \"file\" loader at the end of the loader list.\n          oneOf: [\n            // Process application JS with Babel.\n            // The preset includes JSX, Flow, TypeScript, and some ESNext features.\n            {\n              test: /\\.(js|mjs|jsx|ts|tsx)$/,\n              exclude: [/node_modules/, /\\/dist\\//],\n              loader: require.resolve('babel-loader'),\n              options: {\n                babelrc: false,\n                configFile: false,\n                customize: require.resolve('babel-preset-react-app/webpack-overrides'),\n                presets: [\n                  require.resolve('@babel/preset-react'),\n                  require.resolve('@babel/preset-typescript'),\n                ],\n                // This is a feature of `babel-loader` for webpack (not Babel itself).\n                // It enables caching results in ./node_modules/.cache/babel-loader/\n                // directory for faster rebuilds.\n                cacheDirectory: true,\n                cacheCompression: false,\n                compact: isEnvProduction,\n                plugins: [\n                  [require.resolve('@babel/plugin-proposal-decorators'), { version: 'legacy' }],\n                ],\n              },\n            },\n\n            // MDX support (move to the mdx aspect and extend from there)\n            {\n              test: /\\.mdx?$/,\n              exclude: [/node_modules/],\n              use: [\n                {\n                  loader: require.resolve('babel-loader'),\n                  options: {\n                    babelrc: false,\n                    configFile: false,\n                    presets: [\n                      require.resolve('@babel/preset-env'),\n                      require.resolve('@babel/preset-react'),\n                      require.resolve('@babel/preset-typescript'),\n                    ],\n                  },\n                },\n                {\n                  loader: require.resolve('@arco-cli/aspect/dist/mdx/loader'),\n                  // don't delete this empty options, it allows user to extend directly\n                  options: {},\n                },\n              ],\n            },\n\n            {\n              test: stylesRegexps.cssNoModulesRegex,\n              use: generateStyleLoaders({\n                ...baseStyleLoadersOptions,\n              }),\n              // Don't consider CSS imports dead code even if the\n              // containing package claims to have no side effects.\n              // Remove this when webpack adds a warning or an error for this.\n              // See https://github.com/webpack/webpack/issues/6571\n              sideEffects: true,\n            },\n\n            // By default, we support for CSS Modules (https://github.com/css-modules/css-modules)\n            // using the extension .module.css\n            {\n              test: stylesRegexps.cssModuleRegex,\n              use: generateStyleLoaders({\n                ...baseStyleLoadersOptions,\n                cssLoaderOpts: {\n                  modules: {\n                    getLocalIdent: getCSSModuleLocalIdent,\n                  },\n                },\n              }),\n            },\n\n            // Opt-in support for SASS (using .scss or .sass extensions).\n            {\n              test: stylesRegexps.sassNoModuleRegex,\n              use: generateStyleLoaders({\n                ...baseStyleLoadersOptions,\n                cssLoaderOpts: {\n                  importLoaders: 1,\n                },\n                preProcessLoaderPath: sassLoaderPath,\n              }),\n              sideEffects: true,\n            },\n\n            // By default, we support SASS Modules with the\n            // extensions .module.scss or .module.sass\n            {\n              test: stylesRegexps.sassModuleRegex,\n              use: generateStyleLoaders({\n                ...baseStyleLoadersOptions,\n                cssLoaderOpts: {\n                  importLoaders: 1,\n                  modules: {\n                    getLocalIdent: getCSSModuleLocalIdent,\n                  },\n                },\n                preProcessLoaderPath: sassLoaderPath,\n              }),\n            },\n\n            // Opt-in support for LESS (using .less extensions).\n            {\n              test: stylesRegexps.lessNoModuleRegex,\n              use: generateStyleLoaders({\n                ...baseStyleLoadersOptions,\n                cssLoaderOpts: {\n                  importLoaders: 1,\n                },\n                preProcessLoaderPath: lessLoaderPath,\n                preProcessLoaderOpts: {\n                  lessOptions: {\n                    javascriptEnabled: true,\n                  },\n                },\n              }),\n              sideEffects: true,\n            },\n\n            // By default, we support LESS Modules with the extensions .module.less\n            {\n              test: stylesRegexps.lessModuleRegex,\n              use: generateStyleLoaders({\n                ...baseStyleLoadersOptions,\n                cssLoaderOpts: {\n                  importLoaders: 1,\n                  modules: {\n                    getLocalIdent: getCSSModuleLocalIdent,\n                  },\n                },\n                preProcessLoaderPath: lessLoaderPath,\n                preProcessLoaderOpts: { lessOptions: {} },\n              }),\n            },\n\n            {\n              test: [/\\.bmp$/, /\\.gif$/, /\\.jpe?g$/, /\\.png$/],\n              type: 'asset',\n              parser: {\n                dataUrlCondition: {\n                  maxSize: IMAGE_INLINE_SIZE_LIMIT,\n                },\n              },\n              generator: {\n                filename: 'static/images/[hash][ext][query]',\n              },\n            },\n\n            {\n              test: /\\.svg$/,\n              use: [\n                {\n                  loader: require.resolve('@svgr/webpack'),\n                  options: { titleProp: true, ref: true },\n                },\n              ],\n            },\n\n            {\n              test: /\\.(woff(2)?|ttf|eot|svg)(\\?v=\\d+\\.\\d+\\.\\d+)?$/,\n              type: 'asset',\n              generator: {\n                filename: 'static/fonts/[hash][ext][query]',\n              },\n            },\n\n            // \"file\" loader makes sure those assets get served by WebpackDevServer.\n            // When you `import` an asset, you get its (virtual) filename.\n            // In production, they would get copied to the `build` folder.\n            // This loader doesn't use a \"test\" so it will catch all modules\n            // that fall through the other loaders.\n            {\n              // Exclude `js` files to keep \"css\" loader working as it injects\n              // its runtime that would otherwise be processed through \"file\" loader.\n              // Also exclude `html` and `json` extensions, so they get processed\n              // by webpack internal loaders.\n              exclude: [/\\.(js|mjs|cjs|jsx|ts|tsx)$/, /\\.html$/, /\\.mdx?/, /\\.json$/, /\\.css$/],\n              generator: {\n                filename: 'static/[hash][ext][query]',\n              },\n              type: 'asset',\n            },\n            // ** STOP ** Are you adding a new loader?\n            // Make sure to add the new loader(s) before the \"type:asset\" loader.\n          ],\n        },\n      ],\n    },\n\n    performance: false,\n  };\n}\n"
  },
  {
    "path": "packages/react/src/webpack/webpack.config.component.dev.ts",
    "content": "import { Configuration } from 'webpack';\nimport ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';\n\nconst matchNothingRegex = 'a^';\n\nexport default function (envId: string): Configuration {\n  return {\n    plugins: [\n      new ReactRefreshWebpackPlugin({\n        overlay: {\n          sockPath: `_hmr/${envId}`,\n          entry: require.resolve('./overlay/webpackHotDevClient'),\n          module: require.resolve('./overlay/refreshOverlayInterop'),\n        },\n\n        // we use '@pmmmwh/react-refresh-webpack-plugin/loader' directly where relevant.\n        // FYI, original defaults of the plugin are:\n        // include: /\\.([cm]js|[jt]sx?|flow)$/i, exclude: /node_modules/,\n        include: matchNothingRegex,\n      }),\n    ],\n\n    optimization: {\n      runtimeChunk: true,\n    },\n  };\n}\n"
  },
  {
    "path": "packages/react/src/webpack/webpack.config.component.prod.ts",
    "content": "import { Configuration } from 'webpack';\nimport TerserPlugin from 'terser-webpack-plugin';\nimport CssMinimizerPlugin from 'css-minimizer-webpack-plugin';\nimport { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';\nimport { ENV_BUNDLE_SIZE_ANALYZER } from '@arco-cli/legacy/dist/constants';\n\nconst BUNDLER_ANALYZER = process.env[ENV_BUNDLE_SIZE_ANALYZER] === 'true';\n\n// This is the production configuration.\nexport default function (dev?: boolean): Configuration {\n  const optimization = dev\n    ? undefined\n    : {\n        minimize: true,\n        minimizer: [\n          new TerserPlugin({\n            extractComments: false,\n          }),\n          new CssMinimizerPlugin({\n            minimizerOptions: {\n              preset: [\n                'default',\n                {\n                  minifyFontValues: { removeQuotes: false },\n                },\n              ],\n            },\n          }),\n        ],\n      };\n\n  return {\n    optimization,\n    performance: false,\n    plugins: [\n      BUNDLER_ANALYZER\n        ? new BundleAnalyzerPlugin({\n            analyzerMode: 'static',\n          })\n        : null,\n    ].filter(Boolean),\n  };\n}\n"
  },
  {
    "path": "packages/react/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"dist\",\n    \"paths\": {\n      \"@arco-cli/stone\": [\"../stone/src\"],\n      \"@arco-cli/legacy/dist/*\": [\"../legacy/src/*\"],\n      \"@arco-cli/core/dist/*\": [\"../core/src/*\"],\n      \"@arco-cli/aspect/dist/*\": [\"../aspect/src/*\"],\n      \"@arco-cli/service/dist*\": [\"../service/src/*\"],\n      \"@arco-cli/ui-foundation-react\": [\"../ui-foundation-react/src\"],\n      \"@arco-cli/ui-foundation-react/dist/*\": [\"../ui-foundation-react/src/*\"]\n    }\n  }\n}\n"
  },
  {
    "path": "packages/service/package.json",
    "content": "{\n  \"name\": \"@arco-cli/service\",\n  \"version\": \"2.4.5\",\n  \"homepage\": \"https://github.com/arco-design/arco-cli\",\n  \"repository\": \"https://github.com/arco-design/arco-cli\",\n  \"main\": \"./dist/index.js\",\n  \"scripts\": {\n    \"dev\": \"sh ../../.scripts/build.sh dev\",\n    \"build\": \"sh ../../.scripts/build.sh\",\n    \"build-type\": \"sh ../../.scripts/build-type.sh\",\n    \"clean\": \"rm -rf dist\",\n    \"clean-type\": \"find dist -name *.d.ts |xargs rm -rf\",\n    \"prepublishOnly\": \"npm run build\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@arco-cli/aspect\": \"^2.4.5\",\n    \"@arco-cli/core\": \"^2.3.2\",\n    \"@arco-cli/generator\": \"^2.1.0\",\n    \"@arco-cli/legacy\": \"^2.3.2\",\n    \"@arco-cli/stone\": \"^2.0.0-beta.0\",\n    \"@arco-cli/ui-foundation-react\": \"^2.4.5\",\n    \"@arco-cli/workspace-materials\": \"~0\",\n    \"@babel/runtime\": \"^7.20.6\",\n    \"@pmmmwh/react-refresh-webpack-plugin\": \"^0.5.10\",\n    \"@svgr/webpack\": \"^6.5.1\",\n    \"babel-loader\": \"^9.1.0\",\n    \"babel-preset-react-app\": \"^10.0.1\",\n    \"chalk\": \"^4.1.2\",\n    \"cleargraph\": \"^5.8.0\",\n    \"css-loader\": \"^6.7.2\",\n    \"express\": \"^4.18.2\",\n    \"fs-extra\": \"^10.1.0\",\n    \"html-webpack-plugin\": \"^5.5.0\",\n    \"http-proxy\": \"^1.18.1\",\n    \"ink\": \"^3.2.0\",\n    \"ink-spinner\": \"^4.0.3\",\n    \"less-loader\": \"^11.1.0\",\n    \"lodash\": \"^4.17.21\",\n    \"minimatch\": \"^6.1.6\",\n    \"p-map-series\": \"^2.1.0\",\n    \"pretty-time\": \"^1.1.0\",\n    \"react\": \"~17\",\n    \"react-dev-utils\": \"^12.0.1\",\n    \"react-dom\": \"~17\",\n    \"react-refresh\": \"^0.14.0\",\n    \"react-router-dom\": \"^6.5.0\",\n    \"sass-loader\": \"^13.2.0\",\n    \"source-map-loader\": \"^4.0.1\",\n    \"style-loader\": \"^3.3.1\",\n    \"webpack\": \"^5.75.0\",\n    \"webpack-dev-server\": \"^4.11.1\"\n  }\n}\n"
  },
  {
    "path": "packages/service/src/builder/build.cmd.ts",
    "content": "import chalk from 'chalk';\nimport { Logger } from '@arco-cli/core/dist/logger';\nimport { Workspace } from '@arco-cli/aspect/dist/workspace';\nimport { WorkspaceNotFoundError } from '@arco-cli/aspect/dist/workspace/exceptions';\nimport { Command, CommandOptions } from '@arco-cli/legacy/dist/cli/command';\nimport { CLI_COMPONENT_PATTERN_HELP, CLI_TASK_NAME_HELP } from '@arco-cli/legacy/dist/constants';\n\nimport { BuilderMain } from './builder.main.runtime';\n\ntype BuildOpts = {\n  skipTests?: boolean;\n  tasks?: string;\n};\n\nexport class BuilderCmd implements Command {\n  name = 'build [component-pattern]';\n\n  description = 'run set of tasks for build';\n\n  arguments = [{ name: 'component-pattern', description: CLI_COMPONENT_PATTERN_HELP }];\n\n  alias = '';\n\n  group = 'development';\n\n  options = [\n    // TODO enable test task while building\n    // ['', 'skip-tests', 'skip running component tests during build process'],\n    ['', 'tasks <task-names>', CLI_TASK_NAME_HELP],\n  ] as CommandOptions;\n\n  constructor(private builder: BuilderMain, private workspace: Workspace, private logger: Logger) {}\n\n  async report([pattern]: [string], { skipTests, tasks }: BuildOpts): Promise<string> {\n    if (!this.workspace) throw new WorkspaceNotFoundError();\n\n    const longProcessLogger = this.logger.createLongProcessLogger('build');\n    const components = await this.workspace.getManyByPattern(pattern);\n    if (!components.length) {\n      return chalk.bold('no components found to build');\n    }\n\n    this.logger.consoleSuccess(`found ${components.length} components to build`);\n    const envsExecutionResults = await this.builder.build(components, {\n      skipTests,\n      tasksInclude: typeof tasks === 'string' ? tasks.split(',') : [],\n    });\n    longProcessLogger.end();\n    envsExecutionResults.throwErrorsIfExist();\n    this.logger.consoleSuccess();\n    return chalk.green(\n      `the build has been completed. total: ${envsExecutionResults.tasksQueue.length} tasks`\n    );\n  }\n}\n"
  },
  {
    "path": "packages/service/src/builder/buildPipe.ts",
    "content": "import mapSeries from 'p-map-series';\nimport prettyTime from 'pretty-time';\nimport { EnvDefinition } from '@arco-cli/aspect/dist/envs';\nimport { Logger, LongProcessLogger } from '@arco-cli/core/dist/logger';\nimport { ComponentResult } from '@arco-cli/legacy/dist/workspace/componentResult';\n\nimport { BuildContext, BuildTask, BuildTaskHelper, BuildTaskResult } from './buildTask';\nimport { TasksQueue } from './tasksQueue';\nimport { TaskResultsList } from './taskResultsList';\nimport { EnvsBuildContext } from './builder.service';\n\nexport type TaskResults = {\n  /**\n   * task itself. useful for getting its id/description later on.\n   */\n  task: BuildTask;\n\n  /**\n   * environment where the task was running\n   */\n  env: EnvDefinition;\n\n  /**\n   * component build results.\n   */\n  componentsResults: ComponentResult[];\n\n  /**\n   * timestamp of start initiation.\n   */\n  startTime: number;\n\n  /**\n   * timestamp of task completion.\n   */\n  endTime: number;\n};\n\nexport class BuildPipe {\n  private failedTasks: BuildTask[] = [];\n\n  private failedDependencyTask: BuildTask | undefined;\n\n  private longProcessLogger: LongProcessLogger;\n\n  private taskResults: TaskResults[] = [];\n\n  constructor(\n    /**\n     * array of services to apply on the components.\n     */\n    readonly tasksQueue: TasksQueue,\n    readonly envsBuildContext: EnvsBuildContext,\n    readonly logger: Logger,\n    private previousTaskResults?: TaskResults[]\n  ) {}\n\n  get allTasksResults(): TaskResults[] {\n    return [...(this.previousTaskResults || []), ...(this.taskResults || [])];\n  }\n\n  /**\n   * execute a pipeline of build tasks.\n   */\n  async execute(): Promise<TaskResultsList> {\n    this.addSignalListener();\n    await this.executePreBuild();\n    this.longProcessLogger = this.logger.createLongProcessLogger(\n      'running tasks',\n      this.tasksQueue.length\n    );\n    await mapSeries(this.tasksQueue, async ({ task, env }) => this.executeTask(task, env));\n    this.longProcessLogger.end();\n    const tasksResultsList = new TaskResultsList(this.tasksQueue, this.taskResults);\n    await this.executePostBuild(tasksResultsList);\n\n    return tasksResultsList;\n  }\n\n  /**\n   * for some reason, some tasks (such as typescript compilation) ignore ctrl+C. this fixes it.\n   */\n  private addSignalListener() {\n    process.on('SIGTERM', () => {\n      process.exit();\n    });\n\n    process.on('SIGINT', () => {\n      process.exit();\n    });\n  }\n\n  private async executePreBuild() {\n    this.logger.setStatusLine('executing pre-build for all tasks');\n    await mapSeries(this.tasksQueue, async ({ task, env }) => {\n      await task.preBuild?.(this.getBuildContext(env.id));\n    });\n    this.logger.consoleSuccess();\n  }\n\n  private async executeTask(task: BuildTask, env: EnvDefinition): Promise<void> {\n    const taskId = BuildTaskHelper.serializeId(task);\n    const taskName = `${taskId}${task.description ? ` (${task.description})` : ''}`;\n    this.longProcessLogger.logProgress(`env \"${env.id}\", task \"${taskName}\"`);\n    this.updateFailedDependencyTask(task);\n    if (this.shouldSkipTask(taskId, env.id)) {\n      return;\n    }\n    const startTask = process.hrtime();\n    const taskStartTime = Date.now();\n    const buildContext = this.getBuildContext(env.id);\n    let buildTaskResult: BuildTaskResult;\n    try {\n      buildTaskResult = await task.execute(buildContext);\n    } catch (err) {\n      this.logger.consoleFailure(`env: ${env.id}, task \"${taskId}\" threw an error`);\n      throw err;\n    }\n\n    const endTime = Date.now();\n    const compsWithErrors = buildTaskResult.componentsResults.filter((c) => c.errors?.length);\n    if (compsWithErrors.length) {\n      this.logger.consoleFailure(`env: ${env.id}, task \"${taskId}\" has failed`);\n      this.failedTasks.push(task);\n    } else {\n      const duration = prettyTime(process.hrtime(startTask));\n      this.logger.consoleSuccess(\n        `env \"${env.id}\", task \"${taskName}\" has completed successfully in ${duration}`\n      );\n    }\n\n    const taskResults: TaskResults = {\n      task,\n      env,\n      componentsResults: buildTaskResult.componentsResults,\n      startTime: taskStartTime,\n      endTime,\n    };\n\n    this.taskResults.push(taskResults);\n  }\n\n  private async executePostBuild(tasksResults: TaskResultsList) {\n    this.logger.setStatusLine('executing post-build for all tasks');\n    await mapSeries(this.tasksQueue, async ({ task, env }) => {\n      await task.postBuild?.(this.getBuildContext(env.id), tasksResults);\n    });\n    this.logger.consoleSuccess();\n  }\n\n  private updateFailedDependencyTask(task: BuildTask) {\n    if (!this.failedDependencyTask && this.failedTasks.length && task.dependencies) {\n      task.dependencies.forEach((dependency) => {\n        const { aspectId, name } = BuildTaskHelper.deserializeIdAllowEmptyName(dependency);\n        this.failedDependencyTask = this.failedTasks.find((failedTask) => {\n          if (name && name !== failedTask.name) return false;\n          return aspectId === failedTask.aspectId;\n        });\n      });\n    }\n  }\n\n  private shouldSkipTask(taskId: string, envId: string): boolean {\n    if (!this.failedDependencyTask) return false;\n    const failedTaskId = BuildTaskHelper.serializeId(this.failedDependencyTask);\n    this.logger.consoleWarning(\n      `env: ${envId}, task \"${taskId}\" has skipped due to \"${failedTaskId}\" failure`\n    );\n    return true;\n  }\n\n  private getBuildContext(envId: string): BuildContext {\n    const buildContext = this.envsBuildContext[envId];\n    if (!buildContext) throw new Error(`unable to find buildContext for ${envId}`);\n    buildContext.previousTasksResults = this.allTasksResults;\n    return buildContext;\n  }\n}\n"
  },
  {
    "path": "packages/service/src/builder/buildPipelineOrder.ts",
    "content": "import { Graph } from 'cleargraph';\nimport { EnvDefinition, Environment } from '@arco-cli/aspect/dist/envs';\n\nimport TesterAspect from '@service/tester';\n\nimport { BuildTask, BuildTaskHelper } from './buildTask';\nimport { TasksQueue } from './tasksQueue';\nimport type { TaskSlot } from './builder.main.runtime';\n\ntype TaskDependenciesGraph = Graph<string, string>;\ntype Location = 'start' | 'middle' | 'end';\ntype TasksLocationGraph = { location: Location; graph: TaskDependenciesGraph };\ntype PipelineEnv = { env: EnvDefinition; pipeline: BuildTask[] };\ntype DataPerLocation = {\n  location: Location;\n  graph: TaskDependenciesGraph;\n  pipelineEnvs: PipelineEnv[];\n};\n\n/**\n * there are two ways how to add tasks to build pipeline.\n * 1. `getBuildPipe()` method of the env.\n * 2. registering to the `builder.registerBuildTask()`.\n *\n * in the option #1, it's possible to determine the order. e.g. `getBuildPipe() { return [taskA, taskB, taskC]; }`\n * in the option #2, the register happens once the extension is loaded, so there is no way to put\n * one task before/after another task.\n *\n * To be able to determine the order, you can do the following\n * 1. \"task.location\", it has two options \"start\" and \"end\". the rest are \"middle\".\n * 2. \"task.dependencies\", the dependencies must be completed for all envs before this task starts.\n * the dependencies are applicable inside a location and not across locations. see getLocation()\n * or/and continue reading for more info about this.\n *\n * to determine the final order of the tasks, the following is done:\n * 1. split all tasks to three groups: start, middle and end.\n * 2. for each group define a dependencies graph for the tasks with \"dependencies\" prop and the pipeline.\n * 3. start with the first group \"start\", toposort the dependencies graph and push the found tasks\n * to a queue. once completed, iterate the pipeline and add all tasks to the queue.\n * 4. do the same for the \"middle\" and \"end\" groups.\n *\n * the reason for splitting the tasks to the three groups and not using the \"dependencies\" field\n * alone to determine the order is that the \"start\" and \"end\" groups are mostly core and \"middle\"\n * is mostly the user entering tasks to the pipeline and we as the core don't know about the users\n * tasks. For example, a core task \"PublishComponent\" must happen after the compiler, however, a\n * user might have an env without a compiler. if we determine the order only by the dependencies\n * field, the \"PublishComponent\" would have a dependency \"compiler\" and because in this case there\n * is no compiler task, it would throw an error about missing dependencies.\n */\nexport function calculatePipelineOrder({\n  envs,\n  taskSlot,\n  tasksInclude = [],\n  skipTests = false,\n  pipeNameOnEnv = 'getBuildPipe',\n}: {\n  envs: EnvDefinition[];\n  taskSlot: TaskSlot;\n  tasksInclude?: string[];\n  skipTests?: boolean;\n  pipeNameOnEnv?: string;\n}): TasksQueue {\n  const graphs: TasksLocationGraph[] = [];\n  const locations: Location[] = ['start', 'middle', 'end']; // the order is important here!\n  locations.forEach((location) => {\n    graphs.push({ location, graph: new Graph<string, string>() });\n  });\n  const pipelineEnvs: PipelineEnv[] = [];\n  envs.forEach((envDefinition) => {\n    const pipeline = getPipelineForEnv(taskSlot, envDefinition.env, pipeNameOnEnv);\n    pipelineEnvs.push({ env: envDefinition, pipeline });\n  });\n\n  const flattenedPipeline: BuildTask[] = pipelineEnvs\n    .map((pipelineEnv) => pipelineEnv.pipeline)\n    .flat();\n  flattenedPipeline.forEach((task) => addDependenciesToGraph(graphs, flattenedPipeline, task));\n\n  const dataPerLocation: DataPerLocation[] = graphs.map(({ location, graph }) => {\n    const pipelineEnvsPerLocation: PipelineEnv[] = pipelineEnvs.map(({ env, pipeline }) => {\n      return { env, pipeline: pipeline.filter((task) => (task.location || 'middle') === location) };\n    });\n    return { location, graph, pipelineEnvs: pipelineEnvsPerLocation };\n  });\n\n  const tasksQueue = new TasksQueue();\n  locations.forEach((location) => addTasksToGraph(tasksQueue, dataPerLocation, location));\n\n  if (tasksInclude?.length) {\n    return new TasksQueue(\n      ...tasksQueue.filter(\n        ({ task }) => tasksInclude.includes(task.name) || tasksInclude.includes(task.aspectId)\n      )\n    );\n  }\n\n  if (skipTests) {\n    return new TasksQueue(...tasksQueue.filter(({ task }) => task.aspectId !== TesterAspect.id));\n  }\n\n  return tasksQueue;\n}\n\nfunction addTasksToGraph(\n  tasksQueue: TasksQueue,\n  dataPerLocation: DataPerLocation[],\n  location: Location\n) {\n  const data = dataPerLocation.find((d) => d.location === location);\n  if (!data) return;\n  const sorted = data.graph.toposort();\n  sorted.forEach((taskNode) => {\n    const { aspectId, name } = BuildTaskHelper.deserializeId(taskNode);\n    data.pipelineEnvs.forEach(({ env, pipeline }) => {\n      const taskIndex = pipeline.findIndex(\n        (pipelineTask) => pipelineTask.aspectId === aspectId && pipelineTask.name === name\n      );\n      if (taskIndex < 0) return;\n      const task = pipeline[taskIndex];\n      tasksQueue.push({ env, task });\n      pipeline.splice(taskIndex, 1); // delete the task from the pipeline\n    });\n  });\n  data.pipelineEnvs.forEach(({ env, pipeline }) => {\n    pipeline.forEach((task) => tasksQueue.push({ env, task }));\n  });\n}\n\nfunction addDependenciesToGraph(\n  graphs: TasksLocationGraph[],\n  pipeline: BuildTask[],\n  task: BuildTask\n) {\n  if (!task.dependencies || !task.dependencies.length) return;\n  const taskId = BuildTaskHelper.serializeId(task);\n  task.dependencies.forEach((dependency) => {\n    const { aspectId, name } = BuildTaskHelper.deserializeIdAllowEmptyName(dependency);\n    const dependencyTasks = pipeline.filter((pipelineTask) => {\n      if (pipelineTask.aspectId !== aspectId) return false;\n      return name ? name === pipelineTask.name : true;\n    });\n    if (dependencyTasks.length === 0) {\n      throw new Error(\n        `unable to find dependency \"${dependency}\" of \"${BuildTaskHelper.serializeId(\n          task\n        )}\" in the pipeline`\n      );\n    }\n    dependencyTasks.forEach((dependencyTask) => {\n      const location = getLocation(task, dependencyTask);\n      if (!location) {\n        // the dependency is behind and will be in the correct order regardless the graph.\n        return;\n      }\n      const graphLocation = graphs.find((g) => g.location === location);\n      if (!graphLocation) throw new Error(`unable to find graph for location ${location}`);\n      const dependencyId = BuildTaskHelper.serializeId(dependencyTask);\n      const graph = graphLocation.graph;\n      graph.setNode(taskId, taskId);\n      graph.setNode(dependencyId, dependencyId);\n      graph.setEdge(dependencyId, taskId, 'dependency');\n    });\n  });\n}\n\n/**\n * since the task execution is happening per group: \"start\", \"middle\" and \"end\", the dependencies\n * need to be inside the same group.\n * e.g. if a dependency located at \"end\" group and the task located at \"start\", it's impossible to\n * complete the dependency before the task, there it throws an error.\n * it's ok to have the dependency located earlier, e.g. \"start\" and the task at \"end\", and in this\n * case, it will not be part of the graph because there is no need to do any special calculation.\n */\nfunction getLocation(task: BuildTask, dependencyTask: BuildTask): Location | null {\n  const taskLocation = task.location || 'middle';\n  const dependencyLocation = dependencyTask.location || 'middle';\n\n  const isDependencyAhead =\n    (taskLocation === 'start' && dependencyLocation !== 'start') ||\n    (taskLocation === 'middle' && dependencyLocation === 'end');\n\n  const isDependencyEqual = taskLocation === dependencyLocation;\n\n  if (isDependencyAhead) {\n    throw new Error(`a task \"${BuildTaskHelper.serializeId(task)}\" located at ${taskLocation}\nhas a dependency \"${BuildTaskHelper.serializeId(dependencyTask)} located at ${dependencyLocation},\nwhich is invalid. the dependency must be located earlier or in the same location as the task\"`);\n  }\n\n  if (isDependencyEqual) {\n    return taskLocation;\n  }\n\n  // dependency is behind. e.g. task is \"end\" and dependency is \"start\". no need to enter to the\n  // graph as it's going to be executed in the right order regardless the graph.\n  return null;\n}\n\nfunction getPipelineForEnv(\n  taskSlot: TaskSlot,\n  env: Environment,\n  pipeNameOnEnv: string\n): BuildTask[] {\n  const buildTasks: BuildTask[] = env[pipeNameOnEnv] ? env[pipeNameOnEnv]() : [];\n  const slotsTasks = taskSlot.values().flat();\n  const tasksAtStart: BuildTask[] = [];\n  const tasksAtEnd: BuildTask[] = [];\n  slotsTasks.forEach((task) => {\n    if (task.location === 'start') {\n      tasksAtStart.push(task);\n      return;\n    }\n    if (task.location === 'end') {\n      tasksAtEnd.push(task);\n      return;\n    }\n    tasksAtStart.push(task);\n  });\n\n  // merge with extension registered tasks.\n  const mergedTasks = [...tasksAtStart, ...buildTasks, ...tasksAtEnd];\n\n  return mergedTasks;\n}\n"
  },
  {
    "path": "packages/service/src/builder/buildTask.ts",
    "content": "import type { Component } from '@arco-cli/aspect/dist/component';\nimport { ExecutionContext } from '@arco-cli/aspect/dist/envs';\nimport { Workspace } from '@arco-cli/aspect/dist/workspace';\nimport { ComponentResult } from '@arco-cli/legacy/dist/workspace/componentResult';\n\nimport { TaskResultsList } from './taskResultsList';\nimport { TaskResults } from './buildPipe';\n\nexport type TaskLocation = 'start' | 'end';\n\n/**\n * delimiter between task.aspectId and task.name\n */\nexport const TaskIdDelimiter = ':';\n\nexport interface BuildTaskResult {\n  /**\n   * build results for each of the components in the build context.\n   */\n  componentsResults: ComponentResult[];\n}\n\nexport interface BuildContext extends ExecutionContext {\n  /**\n   * Workspace path for build\n   */\n  workspace: Workspace;\n\n  /**\n   * all components about to be built/tagged.\n   */\n  components: Component[];\n\n  /**\n   * data generated by tasks that were running before this task\n   */\n  previousTasksResults: TaskResults[];\n}\n\nexport interface TaskDescriptor {\n  aspectId: string;\n  name?: string;\n  description?: string;\n}\n\nexport interface BuildTask {\n  /**\n   * aspect id serialized of the creator of the task.\n   */\n  aspectId: string;\n\n  /**\n   * name of the task. function as an identifier among other tasks of the same aspectId.\n   * spaces and special characters are not allowed. as a convention, use UpperCamelCase style.\n   * (e.g. TypescriptCompiler).\n   */\n  name: string;\n\n  /**\n   * description of what the task does.\n   * if available, the logger will log it show it in the status-line.\n   */\n  description?: string;\n\n  /**\n   * where to put the task, before the env pipeline or after\n   */\n  location?: TaskLocation;\n\n  /**\n   * execute a task in a build context\n   */\n  execute(context: BuildContext): Promise<BuildTaskResult>;\n\n  /**\n   * run before the build pipeline has started. this is useful when some preparation are needed to\n   * be done on all envs before the build starts.\n   */\n  preBuild?(context: BuildContext): Promise<void>;\n\n  /**\n   * run after the build pipeline completed for all envs. useful for doing some cleanup on the\n   * capsules before the deployment starts.\n   */\n  postBuild?(context: BuildContext, tasksResults: TaskResultsList): Promise<void>;\n\n  /**\n   * needed if you want the task to be running only after the dependencies were completed\n   * for *all* envs.\n   * normally this is not needed because the build-pipeline runs the tasks in the same order\n   * they're located in the `getBuildPipe()` array and according to the task.location.\n   * the case where this is useful is when a task not only needs to be after another task, but also\n   * after all environments were running that task.\n   * a dependency is task.aspectId. if an aspect has multiple tasks, to be more specific, use\n   * \"aspectId:name\", e.g. \"arco.aspect/compiler:TypescriptCompiler\".\n   */\n  dependencies?: string[];\n}\n\nexport class BuildTaskHelper {\n  static serializeId({ aspectId, name }: { aspectId: string; name: string }): string {\n    return aspectId + TaskIdDelimiter + name;\n  }\n\n  static deserializeId(id: string): { aspectId: string; name: string } {\n    const split = id.split(TaskIdDelimiter);\n    if (split.length === 0) throw new Error(`deserializeId, ${id} is empty`);\n    if (split.length === 1) throw new Error(`deserializeId, ${id} has only aspect-id without name`);\n    if (split.length === 2) return { aspectId: split[0], name: split[1] };\n    throw new Error(`deserializeId, id ${id} has more than one ${TaskIdDelimiter}`);\n  }\n\n  /**\n   * don't throw an error when the id includes only the aspect-id without the task name.\n   * useful for task dependencies, when it's allowed to specify the aspect-id only.\n   */\n  static deserializeIdAllowEmptyName(id: string): { aspectId: string; name?: string } {\n    return id.includes(TaskIdDelimiter)\n      ? BuildTaskHelper.deserializeId(id)\n      : { aspectId: id, name: undefined };\n  }\n}\n"
  },
  {
    "path": "packages/service/src/builder/builder.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const BuilderAspect = Aspect.create({\n  id: 'arco.service/builder',\n});\n\nexport default BuilderAspect;\n"
  },
  {
    "path": "packages/service/src/builder/builder.main.runtime.ts",
    "content": "import { Slot, SlotRegistry } from '@arco-cli/stone';\nimport { MainRuntime, CLIAspect, CLIMain } from '@arco-cli/core/dist/cli';\nimport { Component } from '@arco-cli/aspect/dist/component';\nimport { EnvsAspect, EnvsMain } from '@arco-cli/aspect/dist/envs';\nimport { LoggerAspect, LoggerMain } from '@arco-cli/core/dist/logger';\nimport { WorkspaceAspect, Workspace } from '@arco-cli/aspect/dist/workspace';\n\nimport BuilderAspect from './builder.aspect';\nimport { BuilderService, BuilderServiceOptions } from './builder.service';\nimport { BuilderCmd } from './build.cmd';\nimport { BuildTask } from './buildTask';\n\nexport type TaskSlot = SlotRegistry<BuildTask[]>;\n\nexport class BuilderMain {\n  static runtime = MainRuntime;\n\n  static dependencies = [CLIAspect, EnvsAspect, WorkspaceAspect, LoggerAspect];\n\n  static slots = [Slot.withType<BuildTask[]>()];\n\n  static provider(\n    [cli, envs, workspace, loggerMain]: [CLIMain, EnvsMain, Workspace, LoggerMain],\n    _config,\n    [taskSlot]: [TaskSlot]\n  ) {\n    const logger = loggerMain.createLogger(BuilderAspect.id);\n    const buildService = new BuilderService(workspace, taskSlot, logger);\n    const builder = new BuilderMain(envs, buildService, taskSlot);\n\n    envs.registerService(buildService);\n    cli.register(new BuilderCmd(builder, workspace, logger));\n\n    return builder;\n  }\n\n  constructor(\n    private envs: EnvsMain,\n    private buildService: BuilderService,\n    private buildTaskSlot: TaskSlot\n  ) {}\n\n  /**\n   * register a build task to apply on all component build pipelines.\n   */\n  registerBuildTasks(tasks: BuildTask[]) {\n    this.buildTaskSlot.register(tasks);\n    return this;\n  }\n\n  async build(componnets: Component[], options?: BuilderServiceOptions) {\n    const envs = await this.envs.createEnvironment(componnets);\n    const buildResult = await envs.runOnce(this.buildService, options);\n    return buildResult;\n  }\n}\n\nBuilderAspect.addRuntime(BuilderMain);\n"
  },
  {
    "path": "packages/service/src/builder/builder.service.tsx",
    "content": "import React from 'react';\nimport { Text, Newline } from 'ink';\nimport { Logger } from '@arco-cli/core/dist/logger';\nimport { Workspace } from '@arco-cli/aspect/dist/workspace';\nimport { Component } from '@arco-cli/aspect/dist/component';\nimport { EnvDefinition, EnvService, ExecutionContext } from '@arco-cli/aspect/dist/envs';\n\nimport { BuildContext, BuildTaskHelper } from './buildTask';\nimport { TaskResultsList } from './taskResultsList';\nimport { calculatePipelineOrder } from './buildPipelineOrder';\nimport { TaskSlot } from './builder.main.runtime';\nimport { BuildPipe, TaskResults } from './buildPipe';\n\nexport type BuilderServiceOptions = {\n  skipTests?: boolean;\n  originalSeeders?: string[];\n  tasksInclude?: string[];\n  previousTasksResults?: TaskResults[];\n};\n\nexport type BuildServiceResults = {\n  id: string;\n  buildResults: TaskResultsList;\n  components: Component[];\n  errors?: [];\n};\n\nexport type EnvsBuildContext = { [envId: string]: BuildContext };\n\nexport type BuilderDescriptor = { tasks: string[] };\n\nexport class BuilderService implements EnvService<BuildServiceResults, BuilderDescriptor> {\n  name = 'builder';\n\n  constructor(private workspace: Workspace, private taskSlot: TaskSlot, private logger: Logger) {}\n\n  async runOnce(envsExecutionContext: ExecutionContext[], options: BuilderServiceOptions) {\n    const envs = envsExecutionContext.map((context) => context.envDefinition);\n    const tasksQueue = calculatePipelineOrder({\n      envs,\n      taskSlot: this.taskSlot,\n      skipTests: options.skipTests,\n      tasksInclude: options.tasksInclude,\n    });\n    tasksQueue.validate();\n\n    this.logger.info(`going to run tasks in the following order:\\n${tasksQueue.toString()}`);\n    const title = `running build pipe for ${envs.length} environments, total ${tasksQueue.length} tasks`;\n    const longProcessLogger = this.logger.createLongProcessLogger(title);\n    this.logger.consoleTitle(title);\n\n    const envsBuildContext: EnvsBuildContext = {};\n    envsExecutionContext.forEach((executionContext) => {\n      envsBuildContext[executionContext.id] = Object.assign(executionContext, {\n        workspace: this.workspace,\n        previousTasksResults: [],\n      });\n    });\n\n    const buildPipe = new BuildPipe(\n      tasksQueue,\n      envsBuildContext,\n      this.logger,\n      options.previousTasksResults\n    );\n\n    const buildResults = await buildPipe.execute();\n    longProcessLogger.end();\n    buildResults.hasErrors() ? this.logger.consoleFailure() : this.logger.consoleSuccess();\n\n    return buildResults;\n  }\n\n  getDescriptor(env: EnvDefinition) {\n    const tasks = calculatePipelineOrder({ envs: [env], taskSlot: this.taskSlot }).map(({ task }) =>\n      BuildTaskHelper.serializeId(task)\n    );\n    return { tasks };\n  }\n\n  render(env: EnvDefinition) {\n    const { tasks } = this.getDescriptor(env);\n\n    if (!tasks || !tasks.length) {\n      return null;\n    }\n\n    return (\n      <Text>\n        <Text underline color=\"green\">\n          build pipe\n        </Text>\n        <Newline />\n        <Text color=\"cyan\">\n          total {tasks.length} tasks are configured to be executed in the following order\n        </Text>\n        <Newline />\n        {tasks.map((task, index) => (\n          <Text key={index}>\n            <Text>\n              {index + 1}. {task}\n            </Text>\n            <Newline />\n          </Text>\n        ))}\n        <Newline />\n      </Text>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/service/src/builder/exceptions/artifactDefinitionError.ts",
    "content": "export class ArtifactDefinitionError extends Error {\n  constructor() {\n    super(`must include glob or directories`);\n  }\n}\n"
  },
  {
    "path": "packages/service/src/builder/exceptions/artifactStorageError.ts",
    "content": "import { Component } from '@arco-cli/aspect/dist/component';\n\nexport class ArtifactStorageError extends Error {\n  constructor(_: Error, component: Component) {\n    super(`failed to store artifacts for component ${component.id}`);\n  }\n}\n"
  },
  {
    "path": "packages/service/src/builder/exceptions/index.ts",
    "content": "export { InvalidTaskError } from './invalidTaskError';\nexport { ArtifactStorageError } from './artifactStorageError';\nexport { ArtifactDefinitionError } from './artifactDefinitionError';\n"
  },
  {
    "path": "packages/service/src/builder/exceptions/invalidTaskError.ts",
    "content": "import ArcoError from '@arco-cli/legacy/dist/error/arcoError';\n\nexport class InvalidTaskError extends ArcoError {\n  constructor(readonly taskAspectId: string, reason: string) {\n    super(`task of ${taskAspectId} is invalid, ${reason}`);\n  }\n}\n"
  },
  {
    "path": "packages/service/src/builder/index.ts",
    "content": "import { BuilderAspect } from './builder.aspect';\n\nexport default BuilderAspect;\nexport { BuilderAspect };\nexport {\n  BuildContext,\n  BuildTask,\n  BuildTaskResult,\n  TaskLocation,\n  BuildTaskHelper,\n} from './buildTask';\nexport { TaskResultsList } from './taskResultsList';\nexport { mergeComponentResults } from './mergeComponentResults';\nexport type { BuilderMain } from './builder.main.runtime';\n"
  },
  {
    "path": "packages/service/src/builder/mergeComponentResults.ts",
    "content": "import { merge } from 'lodash';\nimport type { ComponentResult } from '@arco-cli/legacy/dist/workspace/componentResult';\n\ntype ComponentIndex = {\n  [id: string]: ComponentResult;\n};\n\n/**\n * merge ComponentResult arrays.\n */\nexport function mergeComponentResults(resultMatrix: ComponentResult[][]) {\n  if (!resultMatrix.length) return [];\n\n  const index: ComponentIndex = {};\n\n  resultMatrix.forEach((results) => {\n    results.forEach((result) => {\n      const id = result.id;\n      const existing = index[id] || { warnings: [], errors: [], metadata: {} };\n\n      index[id] = {\n        id,\n        warnings: existing.warnings.concat(result.warnings || []),\n        errors: existing.errors.concat(result.errors || []),\n        metadata: merge(existing.metadata, result.metadata || {}),\n      };\n    });\n  });\n\n  return Object.values(index);\n}\n"
  },
  {
    "path": "packages/service/src/builder/taskResultsList.ts",
    "content": "import chalk from 'chalk';\nimport ArcoError from '@arco-cli/legacy/dist/error/arcoError';\nimport { ComponentResult } from '@arco-cli/legacy/dist/workspace/componentResult';\n\nimport { BuildTaskHelper } from './buildTask';\nimport { TasksQueue } from './tasksQueue';\nimport { TaskResults } from './buildPipe';\n\nexport class TaskResultsList {\n  constructor(\n    public tasksQueue: TasksQueue,\n    /**\n     * results of all tasks executed in the build pipeline.\n     */\n    public tasksResults: TaskResults[]\n  ) {}\n\n  hasErrors(): boolean {\n    return this.tasksResults.some((taskResult) =>\n      taskResult.componentsResults.find((c) => c.errors?.length)\n    );\n  }\n\n  throwErrorsIfExist() {\n    const errorMessage = this.getErrorMessageFormatted();\n    if (errorMessage) {\n      throw new ArcoError(errorMessage);\n    }\n  }\n\n  /**\n   * group errors from all tasks and show them nicely to the user\n   */\n  private getErrorMessageFormatted(): string | null {\n    const tasksErrors: string[] = [];\n    let totalErrors = 0;\n    this.tasksResults.forEach((taskResult) => {\n      const compsWithErrors = taskResult.componentsResults.filter((c) => c.errors?.length);\n      if (!compsWithErrors.length) return;\n      const title = chalk.bold(\n        `Failed task ${tasksErrors.length + 1}: \"${BuildTaskHelper.serializeId(\n          taskResult.task\n        )}\" of env \"${taskResult.env.id}\"\\n`\n      );\n      const errorsStr = compsWithErrors\n        .map((compWithErrors) => this.aggregateTaskErrorsToOneString(compWithErrors))\n        .join('\\n\\n');\n      const taskErrors = compsWithErrors.reduce(\n        (acc, current) => acc + (current.errors || []).length,\n        0\n      );\n      const summery = `\\n\\nFound ${taskErrors} errors in ${compsWithErrors.length} components`;\n      totalErrors += taskErrors;\n      tasksErrors.push(title + errorsStr + summery);\n    });\n    if (!tasksErrors.length) return null;\n    const title = `\\nThe following errors were found while running the build pipeline\\n`;\n    const errorsStr = tasksErrors.join('\\n\\n');\n    const totalTasks = this.tasksQueue.length;\n    const totalFailed = tasksErrors.length;\n    const totalSucceed = this.tasksResults.length - totalFailed;\n    const totalSkipped = totalTasks - this.tasksResults.length;\n    const summery = `\\n\\n\\n✖ Total ${totalTasks} tasks. ${totalSucceed} succeeded. ${totalFailed} failed. ${totalSkipped} skipped. Total errors: ${totalErrors}.`;\n    return title + errorsStr + summery;\n  }\n\n  private aggregateTaskErrorsToOneString(componentResult: ComponentResult) {\n    const rawErrors = componentResult.errors || [];\n    const errors = rawErrors.map((e) => (typeof e === 'string' ? e : e.toString()));\n    return `component: ${componentResult.id}\\n${errors.join('\\n')}`;\n  }\n}\n"
  },
  {
    "path": "packages/service/src/builder/tasksQueue.ts",
    "content": "import { EnvDefinition } from '@arco-cli/aspect/dist/envs';\nimport { BuildTask, BuildTaskHelper } from './buildTask';\nimport { InvalidTaskError } from './exceptions';\n\ntype EnvTask = { env: EnvDefinition; task: BuildTask };\n\nexport class TasksQueue extends Array<EnvTask> {\n  toString() {\n    return this.map(\n      ({ env, task }) => `env ${env.id}, task ${BuildTaskHelper.serializeId(task)}`\n    ).join('\\n');\n  }\n\n  /**\n   * make sure tasks names are valid and there are no duplications\n   */\n  validate() {\n    this.forEach(({ task }) => {\n      this.validateTaskName(task);\n    });\n    this.validateDuplications();\n  }\n\n  private validateTaskName(task: BuildTask) {\n    if (!task.name) throw new InvalidTaskError(task.aspectId, 'name is missing');\n    const regexWord = /^\\w+$/; // match any word: a-zA-Z0-9 and underscore.\n    const isValid = regexWord.test(task.name);\n    if (!isValid)\n      throw new InvalidTaskError(\n        task.aspectId,\n        `name \"${task.name}\" is invalid, only alphanumeric characters are allowed`\n      );\n  }\n\n  private validateDuplications() {\n    const uniqueTasks = this.map(({ env, task }) => `${env.id} ${task.aspectId}:${task.name}`);\n    uniqueTasks.forEach((uniqTask) => {\n      if (uniqueTasks.filter((u) => u === uniqTask).length > 1) {\n        throw new InvalidTaskError(\n          uniqTask,\n          'there are two or more tasks with the same name and aspectId in the same environment'\n        );\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "packages/service/src/compiler/compiler.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const CompilerAspect = Aspect.create({\n  id: 'arco.service/compiler',\n});\n\nexport default CompilerAspect;\n"
  },
  {
    "path": "packages/service/src/compiler/compiler.main.runtime.ts",
    "content": "import { MainRuntime } from '@arco-cli/core/dist/cli';\nimport { LoggerAspect, LoggerMain, Logger } from '@arco-cli/core/dist/logger';\nimport { CompilerAspect } from './compiler.aspect';\nimport { CompilerTask } from './compiler.task';\nimport type { Compiler, CompilerAspectConfig } from './types';\n\nexport class CompilerMain {\n  static runtime = MainRuntime;\n\n  static dependencies = [LoggerAspect];\n\n  static slots = [];\n\n  static provider([loggerMain]: [LoggerMain], config: CompilerAspectConfig = {}) {\n    const logger = loggerMain.createLogger(CompilerAspect.id);\n    return new CompilerMain(config, logger);\n  }\n\n  constructor(private config: CompilerAspectConfig, private logger: Logger) {}\n\n  createTask(name: string, compiler: Compiler): CompilerTask {\n    return new CompilerTask(CompilerAspect.id, name, this.config, this.logger, compiler);\n  }\n}\n\nCompilerAspect.addRuntime(CompilerMain);\n"
  },
  {
    "path": "packages/service/src/compiler/compiler.task.ts",
    "content": "import path from 'path';\nimport fs from 'fs-extra';\nimport minimatch from 'minimatch';\nimport type { Logger } from '@arco-cli/core/dist/logger';\nimport type { Component } from '@arco-cli/aspect/dist/component';\n\nimport { BuildContext, BuildTask, BuildTaskResult, TaskResultsList } from '@service/builder';\n\nimport type { Compiler, CompilerAspectConfig } from './types';\nimport CompilerAspect from './compiler.aspect';\nimport { sortPackageBuildOrders } from './utils/sortPackageBuildOrders';\n\nexport class CompilerTask implements BuildTask {\n  readonly description = 'compile components';\n\n  constructor(\n    readonly aspectId: string,\n    readonly name: string,\n    readonly config: CompilerAspectConfig,\n    private logger: Logger,\n    private compilerInstance: Compiler\n  ) {}\n\n  private sortContextComponents(components: Component[]) {\n    const getSortFn = (orders: string[]) => {\n      orders = Array.isArray(orders) ? orders : [];\n      // avoid change origin array's order by reverse() and sort()\n      orders = [...orders].reverse();\n      return ({ id: idA }: Component, { id: idB }: Component) => {\n        const indexA = orders.findIndex(\n          (keyword) => idA.indexOf(keyword) > -1 || minimatch(idA, keyword)\n        );\n        const indexB = orders.findIndex(\n          (keyword) => idB.indexOf(keyword) > -1 || minimatch(idB, keyword)\n        );\n        // all components in orderRule should sort to first\n        // then sort them by their index in orderRule\n        return indexB - indexA;\n      };\n    };\n\n    const { orders: defaultPackageBuildOrders } = sortPackageBuildOrders(\n      components.map(({ packageName, dependencies }) => ({\n        name: packageName,\n        dependencies: Object.keys(dependencies),\n      }))\n    );\n\n    return [...components]\n      .sort(getSortFn(defaultPackageBuildOrders.map((packageName) => `${packageName}/*`)))\n      .sort(getSortFn(this.config.componentCompilationOrders));\n  }\n\n  private async clearDistDir(component: Component, compiler: Compiler) {\n    const distDirAbs = path.resolve(component.packageDirAbs, compiler.distDir);\n    return fs.remove(distDirAbs);\n  }\n\n  private async copyNonSupportedFiles(component: Component, compiler: Compiler) {\n    await Promise.all(\n      component.files\n        .filter(({ path: filePath }) => {\n          for (const pattern of compiler.ignorePatterns) {\n            if (minimatch(filePath, pattern)) {\n              return false;\n            }\n          }\n          return !compiler.isFileSupported(filePath);\n        })\n        .map(async (file) => {\n          const content = file.contents;\n          const filePath = path.join(component.packageDirAbs, compiler.distDir, file.relative);\n          await fs.ensureFileSync(filePath);\n          await fs.outputFile(filePath, content);\n        })\n    );\n  }\n\n  async execute(context: BuildContext): Promise<BuildTaskResult> {\n    const uniqueComponents: Component[] = [];\n    for (const component of context.components) {\n      if (!uniqueComponents.find((com) => com.rootDir === component.rootDir)) {\n        uniqueComponents.push(component);\n      }\n    }\n\n    // we reduce the list size of components that need to build according to rootDir\n    // no need to repeat the build process multiple times if the components have the same root directory\n    // but do NOT change buildContext directly\n    const buildResults = await this.compilerInstance.build({\n      ...context,\n      components: this.sortContextComponents(uniqueComponents),\n    } as BuildContext);\n\n    return buildResults;\n  }\n\n  async preBuild(context: BuildContext) {\n    await Promise.all(\n      this.sortContextComponents(context.components).map(async (component) => {\n        // should clear dist dir at first, then do other operations\n        if (!this.config.skipDeleteDistDir) {\n          await this.clearDistDir(component, this.compilerInstance);\n        }\n        await this.copyNonSupportedFiles(component, this.compilerInstance);\n      })\n    );\n    await this.compilerInstance.preBuild?.(context);\n  }\n\n  async postBuild?(context: BuildContext, tasksResults: TaskResultsList): Promise<void> {\n    await this.compilerInstance.postBuild?.(context, tasksResults);\n\n    // execute post-build task specify via env config\n    const aspectPostBuildConfig = this.config.postBuild;\n    let aspectPostBuildFn = (_info) => null;\n    if (typeof aspectPostBuildConfig === 'function') {\n      aspectPostBuildFn = aspectPostBuildConfig;\n    } else if (typeof aspectPostBuildConfig === 'string') {\n      try {\n        aspectPostBuildFn = require(path.join(context.workspace.path, aspectPostBuildConfig));\n      } catch (err) {\n        this.logger.consoleFailure(\n          `${\n            CompilerAspect.id\n          }: failed to load the postBuild function defined in workspace config file.\\n${err.toString()}`\n        );\n      }\n    }\n    try {\n      await aspectPostBuildFn?.({\n        taskName: this.name,\n        logger: this.logger,\n        context,\n      });\n    } catch (err) {\n      this.logger.consoleFailure(\n        `${\n          CompilerAspect.id\n        }: failed to execute the postBuild function defined in workspace config file.\\n${err.toString()}`\n      );\n    }\n  }\n}\n"
  },
  {
    "path": "packages/service/src/compiler/index.ts",
    "content": "import { CompilerAspect } from './compiler.aspect';\n\nexport default CompilerAspect;\nexport { CompilerAspect };\nexport type { CompilerMain } from './compiler.main.runtime';\nexport type {\n  Compiler,\n  CompilerOptions,\n  StyleCompilerOptions,\n  CompilerAspectConfig,\n} from './types';\n"
  },
  {
    "path": "packages/service/src/compiler/types.ts",
    "content": "import type { Component } from '@arco-cli/aspect/dist/component';\nimport type { Logger } from '@arco-cli/core/dist/logger';\n\nimport { BuildContext, BuildTaskResult, TaskResultsList } from '@service/builder';\n\nexport interface CompilerAspectConfig {\n  /**\n   * whether to skip deleting the component product directory before compiling\n   */\n  skipDeleteDistDir?: boolean;\n  /**\n   * specify the component compilation order, receive component id or Glob string\n   * when some components depend on other components, specifying the compilation order is useful\n   * e.g. ['base-package/**', 'second-base-package/**']\n   */\n  componentCompilationOrders?: Array<string>;\n  /**\n   * postBuild\n   */\n  postBuild?:\n    | string\n    | ((info: { taskName: string; context: BuildContext; logger: Logger }) => void | Promise<void>);\n}\n\nexport interface CompilerOptions {\n  /**\n   * name of the compiler.\n   */\n  name?: string;\n\n  /**\n   * relative path of the dist directory inside the capsule. e.g. \"dist\".\n   */\n  distDir?: string;\n\n  /**\n   * determines which ones of the generated files will be saved while building\n   * e.g. distGlobPatterns = [`${this.distDir}/**`, `!${this.distDir}/tsconfig.tsbuildinfo`];\n   * see https://github.com/mrmlnc/fast-glob for the supported glob patters syntax.\n   */\n  distGlobPatterns?: string[];\n\n  /**\n   * determines which files will be ignored while building\n   * e.g. ignorePatterns = ['__docs__', '__test__'];\n   */\n  ignorePatterns?: string[];\n\n  /**\n   * optional. default to \"dist\".\n   * useful when the build pipeline has multiple compiler tasks of the same compiler.\n   * e.g. using the same Babel compiler for two different tasks, one for creating \"es5\" files, and\n   * the second for creating \"esm\". the artifact names would be \"es5\" and \"esm\" accordingly.\n   */\n  artifactName?: string;\n}\n\n/**\n * info of style file to compile\n */\nexport type StyleFileToCompile = {\n  /**\n   * absolute path of source file\n   */\n  pathSource: string;\n  /**\n   * absolute path of compiled file\n   */\n  pathTarget: string;\n  /**\n   * get file contents string to compile\n   */\n  getContents: () => string;\n};\n\nexport interface StyleCompilerOptions {\n  /**\n   * compile\n   */\n  compile?: (\n    fileInfo: StyleFileToCompile,\n    defaultCompileFn: (fileInfo: StyleFileToCompile) => Promise<string>\n  ) => Promise<string>;\n\n  /**\n   * whether to combine all raw style files to one\n   */\n  combine?: boolean | { filename: string; sorter: (depPathA: string, depPathB: string) => number };\n}\n\nexport interface Compiler extends CompilerOptions {\n  /**\n   * id of the compiler.\n   */\n  id: string;\n\n  /**\n   * returns the version of the current compiler instance (e.g. '4.0.1').\n   */\n  version(): string;\n\n  /**\n   * returns the display name of the current compiler instance (e.g. 'TypeScript')\n   */\n  displayName: string;\n\n  /**\n   * Delete dist folder before writing the new compiled files\n   */\n  deleteDistDir?: boolean;\n\n  /**\n   * whether source files (such as .less/.scss) should be copied into the dist directory\n   */\n  shouldCopySourceFiles?: boolean;\n\n  /**\n   * serialized config of the compiler.\n   */\n  displayConfig?(): string;\n\n  /**\n   * only supported files matching get compiled. others, are copied to the dist dir.\n   */\n  isFileSupported(filePath: string): boolean;\n\n  /**\n   * return the dist dir of the compiled files (relative path from the component root dir)\n   */\n  getDistDir?(): string;\n\n  /**\n   * given a source file, return its parallel in the dists. e.g. \"index.ts\" => \"dist/index.js\"\n   * both, the return path and the given path are relative paths.\n   */\n  getDistPathBySrcPath(srcPath: string): string;\n\n  /**\n   * given a component, returns the path to the source folder to use for the preview, uses the one\n   * in node_modules by default\n   */\n  getPreviewComponentRootPath?(component: Component): string;\n\n  /**\n   * compile components inside isolated capsules. this being used during tag for the release.\n   * meaning, the final package of the component has the dists generated by this method.\n   */\n  build?(context: BuildContext): Promise<BuildTaskResult>;\n\n  /**\n   * run before the build pipeline has started. this is useful when souiuime preparation are needed to\n   * be done on all envs before the build starts.\n   */\n  preBuild?(context: BuildContext): Promise<void>;\n\n  /**\n   * run after the build pipeline completed for all envs. useful for some cleanups\n   */\n  postBuild?(context: BuildContext, tasksResults: TaskResultsList): Promise<void>;\n}\n"
  },
  {
    "path": "packages/service/src/compiler/utils/compileStyle.ts",
    "content": "import os from 'os';\nimport path from 'path';\nimport fs from 'fs-extra';\nimport { Component } from '@arco-cli/aspect/dist/component';\nimport { SourceFile } from '@arco-cli/legacy/dist/workspace/component/sources';\n\nimport type { StyleCompilerOptions, StyleFileToCompile } from '../types';\n\nexport type CompileStyleOptions = {\n  component: Component;\n  distDir: string;\n  shouldCopySourceFiles: boolean;\n  rawFileExt: 'sass' | 'less';\n  combine: StyleCompilerOptions['combine'];\n  compile: (fileInfo: StyleFileToCompile) => Promise<string>;\n  userCustomCompileFn: StyleCompilerOptions['compile'];\n  filter: (file: SourceFile) => boolean;\n};\n\nexport async function compileStyle({\n  component,\n  distDir,\n  shouldCopySourceFiles,\n  combine,\n  compile,\n  userCustomCompileFn,\n  filter,\n  rawFileExt,\n}: CompileStyleOptions) {\n  const componentResult = {\n    id: component.id,\n    errors: [],\n  };\n\n  const filesToCompile: Array<StyleFileToCompile> = [];\n  const combineFileInfo: { rawFilePath: string; cssFilePath: string; deps: string[] } = {\n    rawFilePath: '',\n    cssFilePath: '',\n    deps: [],\n  };\n\n  const getDistPathBySrcPath = (srcPath: string): string => {\n    return srcPath.replace(new RegExp(`\\\\.${rawFileExt}$`, 'i'), '.css');\n  };\n\n  component.files.forEach((file) => {\n    const valid = filter(file);\n    if (!valid) return;\n\n    const fileToCompile: StyleFileToCompile = {\n      getContents: () => file.contents.toString(),\n      pathSource: file.path,\n      pathTarget: path.join(component.packageDirAbs, distDir, file.relative),\n    };\n    filesToCompile.push(fileToCompile);\n\n    if (combine) {\n      const combineFilename =\n        typeof combine === 'object' && combine.filename\n          ? combine.filename\n          : `style/index.${rawFileExt}`;\n      const sorter = typeof combine === 'object' ? combine.sorter : null;\n      combineFileInfo.rawFilePath ||= path.join(component.packageDirAbs, distDir, combineFilename);\n      combineFileInfo.cssFilePath ||= getDistPathBySrcPath(combineFileInfo.rawFilePath);\n      combineFileInfo.deps.push(fileToCompile.pathTarget);\n      if (typeof sorter === 'function') {\n        combineFileInfo.deps = combineFileInfo.deps.sort(sorter);\n      }\n    }\n  });\n\n  if (combineFileInfo.rawFilePath) {\n    const styleDistDir = path.dirname(combineFileInfo.rawFilePath);\n    const content = combineFileInfo.deps\n      .map((depPath) => {\n        // we got an error \"semicolons aren't allowed in the indented syntax.\" while compiling scss\n        // so remove semicolon at end of line\n        return `@import '${path.relative(styleDistDir, depPath)}'${\n          rawFileExt === 'less' ? ';' : ''\n        }`;\n      })\n      .join(os.EOL);\n    await fs.ensureFile(combineFileInfo.rawFilePath);\n    await fs.writeFile(combineFileInfo.rawFilePath, content);\n    filesToCompile.push({\n      getContents: () => content,\n      pathSource: combineFileInfo.rawFilePath,\n      pathTarget: combineFileInfo.rawFilePath,\n    });\n  }\n\n  // we should copy source file to dist before compiling\n  // otherwise not found error will throw while combine-less compiling\n  const shouldCopySourceFileBeforeCompile = !!combineFileInfo.rawFilePath;\n  const copySourceFileToTarget = async ({ pathSource, pathTarget }: StyleFileToCompile) => {\n    if (shouldCopySourceFiles && pathSource !== pathTarget) {\n      await fs.ensureDir(path.dirname(pathTarget));\n      await fs.copyFile(pathSource, pathTarget);\n    }\n  };\n\n  if (shouldCopySourceFileBeforeCompile) {\n    await Promise.all(filesToCompile.map(copySourceFileToTarget));\n  }\n\n  await Promise.all(\n    filesToCompile.map(async (file) => {\n      try {\n        const cssContent =\n          typeof userCustomCompileFn === 'function'\n            ? await userCustomCompileFn(file, compile)\n            : await compile(file);\n        const targetCssPath = getDistPathBySrcPath(file.pathTarget);\n\n        await fs.ensureFile(targetCssPath);\n        await fs.writeFile(targetCssPath, cssContent);\n      } catch (err) {\n        componentResult.errors.push(err);\n      }\n\n      if (!shouldCopySourceFileBeforeCompile) {\n        await copySourceFileToTarget(file);\n      }\n    })\n  );\n\n  return componentResult;\n}\n"
  },
  {
    "path": "packages/service/src/compiler/utils/sortPackageBuildOrders.ts",
    "content": "import { Graph } from 'cleargraph';\n\nexport function sortPackageBuildOrders(\n  packages: Array<{ name: string; dependencies?: string[] }>\n): { orders: string[]; isCyclic: boolean; error?: Error } {\n  const graph = new Graph(packages.map(({ name }) => ({ id: name, node: name })));\n\n  for (const { name, dependencies = [] } of packages) {\n    for (const dep of dependencies) {\n      if (graph.hasNode(dep)) {\n        graph.setEdge(dep, name, 'dependency');\n      }\n    }\n  }\n\n  const result = {\n    orders: packages.map(({ name }) => name),\n    isCyclic: graph.isCyclic(),\n    error: null,\n  };\n\n  try {\n    result.orders = graph.toposort();\n  } catch (err) {\n    result.error = err;\n  }\n\n  return result;\n}\n"
  },
  {
    "path": "packages/service/src/fork/fork.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const ForkAspect = Aspect.create({\n  id: 'arco.service/fork',\n});\n"
  },
  {
    "path": "packages/service/src/fork/fork.cmd.ts",
    "content": "import { Command, CommandOptions } from '@arco-cli/legacy/dist/cli/command';\nimport { WorkspaceNotFoundError } from '@arco-cli/aspect/dist/workspace/exceptions';\nimport { Workspace } from '@arco-cli/aspect/dist/workspace';\nimport { Logger } from '@arco-cli/core/dist/logger';\nimport { ForkMain } from '@service/fork/fork.main.runtime';\n\nexport class ForkCmd implements Command {\n  name = 'fork [component-id]';\n\n  description = 'fork component from Arco material market';\n\n  arguments = [];\n\n  alias = '';\n\n  group = 'collaborate';\n\n  options = [] as CommandOptions;\n\n  constructor(private logger: Logger, private fork: ForkMain, private workspace: Workspace) {}\n\n  async report(): Promise<string> {\n    if (!this.workspace) throw new WorkspaceNotFoundError();\n\n    if (this.fork) {\n      this.logger.debug(`start to fork component to workspace`);\n      return 'TODO: fork component to current workspace.';\n    }\n\n    return '';\n  }\n}\n"
  },
  {
    "path": "packages/service/src/fork/fork.main.runtime.ts",
    "content": "import { CLIAspect, CLIMain, MainRuntime } from '@arco-cli/core/dist/cli';\nimport { LoggerAspect, LoggerMain } from '@arco-cli/core/dist/logger';\nimport { WorkspaceAspect, Workspace } from '@arco-cli/aspect/dist/workspace';\n\nimport { ForkAspect } from './fork.aspect';\nimport { ForkCmd } from './fork.cmd';\n\nexport class ForkMain {\n  static runtime = MainRuntime;\n\n  static dependencies = [LoggerAspect, CLIAspect, WorkspaceAspect];\n\n  static provider([loggerMain, cli, workspace]: [LoggerMain, CLIMain, Workspace]) {\n    const logger = loggerMain.createLogger(ForkAspect.id);\n    const fork = new ForkMain();\n    // TODO register cmd after forking component to workspace ready\n    if (0) {\n      cli.register(new ForkCmd(logger, fork, workspace));\n    }\n    return fork;\n  }\n\n  constructor() {}\n}\n\nForkAspect.addRuntime(ForkMain);\n"
  },
  {
    "path": "packages/service/src/fork/index.ts",
    "content": "import { ForkAspect } from './fork.aspect';\n\nexport { ForkAspect };\nexport default ForkAspect;\nexport type { ForkMain } from './fork.main.runtime';\n"
  },
  {
    "path": "packages/service/src/generator/create.cmd.ts",
    "content": "import chalk from 'chalk';\nimport { Command, CommandOptions } from '@arco-cli/legacy/dist/cli/command';\nimport { Workspace } from '@arco-cli/aspect/dist/workspace';\nimport { WorkspaceNotFoundError } from '@arco-cli/aspect/dist/workspace/exceptions';\n\nimport { GeneratorMain, CreateComponentOptions } from './generator.main.runtime';\n\nexport class CreateCmd implements Command {\n  name = 'create <component-name>';\n\n  description = 'create a new component using a template';\n\n  arguments = [\n    {\n      name: 'name',\n      description: 'component name you want to create, e.g \"Button\"',\n    },\n  ];\n\n  alias = '';\n\n  group = 'development';\n\n  options = [\n    ['f', 'force', 'force overwrite directory, if it already exists'],\n    ['p', 'path <path>', 'directory path to create the new component'],\n    ['', 'template <template-name>', 'template for generating the component'],\n    ['', 'templateArgs <template-args>', 'template arguments for generating the component'],\n    ['', 'packageName <package-name>', 'package name of current component'],\n  ] as CommandOptions;\n\n  constructor(private workspace: Workspace, private generator: GeneratorMain) {}\n\n  async report(\n    [name]: [string],\n    {\n      force,\n      path,\n      packageName,\n      template,\n      templateArgs,\n    }: Pick<CreateComponentOptions, 'force' | 'path' | 'packageName' | 'template' | 'templateArgs'>\n  ): Promise<string> {\n    if (!this.workspace) throw new WorkspaceNotFoundError();\n\n    try {\n      const { message } = await this.generator.create({\n        name,\n        force,\n        path,\n        packageName,\n        template,\n        templateArgs,\n      });\n      return chalk.green(message);\n    } catch (err) {\n      return chalk.red(err.toString());\n    }\n  }\n}\n"
  },
  {
    "path": "packages/service/src/generator/generator.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const GeneratorAspect = Aspect.create({\n  id: 'arco.service/generator',\n});\n\nexport default GeneratorAspect;\n"
  },
  {
    "path": "packages/service/src/generator/generator.main.runtime.ts",
    "content": "import path from 'path';\nimport fs from 'fs-extra';\nimport { get, isPlainObject } from 'lodash';\nimport { CLIAspect, CLIMain, MainRuntime } from '@arco-cli/core/dist/cli';\nimport { LoggerAspect, LoggerMain, Logger } from '@arco-cli/core/dist/logger';\nimport { WorkspaceAspect, Workspace } from '@arco-cli/aspect/dist/workspace';\nimport { Generator, TemplateManifest, GenerateOptions } from '@arco-cli/generator';\n\nimport { GeneratorAspect } from './generator.aspect';\nimport { CreateCmd } from './create.cmd';\n\nexport type GeneratorConfig = {\n  defaultPath?: string;\n  defaultTemplate?: string;\n  hooks?: {\n    afterComponentCreated?: string;\n  };\n};\n\nexport type CreateComponentOptions = {\n  name: string;\n  force?: boolean;\n} & Pick<GenerateOptions, 'path' | 'packageName' | 'template' | 'templateArgs'>;\n\nexport class GeneratorMain {\n  static runtime = MainRuntime;\n\n  static dependencies = [LoggerAspect, CLIAspect, WorkspaceAspect];\n\n  static provider(\n    [loggerMain, cli, workspace]: [LoggerMain, CLIMain, Workspace],\n    config: GeneratorConfig\n  ) {\n    const logger = loggerMain.createLogger(GeneratorAspect.id);\n    const generator = new GeneratorMain(config, logger, workspace);\n    cli.register(new CreateCmd(workspace, generator));\n    return generator;\n  }\n\n  constructor(\n    private config: GeneratorConfig,\n    private logger: Logger,\n    private workspace: Workspace\n  ) {}\n\n  private updateWorkspaceConfig(name: string, rootDir: string, manifest: TemplateManifest) {\n    const newWorkspaceConfig = { ...this.workspace.config };\n    const componentConfig = {\n      name,\n      rootDir: rootDir.replace(/\\/[^/]*$/, ''),\n      entries: {\n        base: name,\n        ...manifest.entries,\n      },\n    };\n\n    newWorkspaceConfig.components ||= { members: [] };\n    if (Array.isArray(newWorkspaceConfig.components)) {\n      newWorkspaceConfig.components.push(componentConfig);\n    } else {\n      const extendsRule = newWorkspaceConfig.components.extends;\n      const deleteExtendProperties = (obj: Record<string, any>, parentPath = '') => {\n        Object.entries(obj).forEach(([key, value]) => {\n          const propertyPath = parentPath ? `${parentPath}.${key}` : key;\n          if (JSON.stringify(get(extendsRule, propertyPath)) === JSON.stringify(value)) {\n            delete obj[key];\n          } else if (isPlainObject(value)) {\n            deleteExtendProperties(value, propertyPath);\n          }\n        });\n      };\n      deleteExtendProperties(componentConfig);\n      newWorkspaceConfig.components.members.push(componentConfig);\n    }\n\n    this.workspace.updateWorkspaceConfigFile(WorkspaceAspect.id, newWorkspaceConfig);\n  }\n\n  async create({\n    name,\n    force,\n    path: generatePath,\n    ...createComponentOptions\n  }: CreateComponentOptions): Promise<{ ok: boolean; message: string }> {\n    generatePath ||= this.config.defaultPath\n      ? path.resolve(this.workspace.path, this.config.defaultPath)\n      : '';\n    createComponentOptions.template ||= (() => {\n      const defaultTemplate = this.config.defaultTemplate;\n      const localTemplate = Generator.parseLocalTemplatePath(defaultTemplate);\n      if (localTemplate) {\n        const { prefix, path: templatePath } = localTemplate;\n        return `${prefix}${path.resolve(this.workspace.path, templatePath)}`;\n      }\n      return defaultTemplate;\n    })();\n\n    const { hooks: { afterComponentCreated } = {} } = this.config;\n    const generator = new Generator(name, { path: generatePath, ...createComponentOptions });\n    const targetPath = generator.getTargetPath();\n    const rootDir = path.relative(this.workspace.path, targetPath);\n\n    if (fs.existsSync(targetPath)) {\n      if (force) {\n        fs.removeSync(targetPath);\n      } else {\n        return {\n          ok: false,\n          message: `already a directory exist at ${targetPath}, use the '--force' flag to overwrite it`,\n        };\n      }\n    }\n\n    const longProcessLogger = this.logger.createLongProcessLogger(\n      `create a new component named ${name} to ${targetPath}`\n    );\n    const { manifest, exports: componentExports } = await generator.generate();\n\n    if (manifest?.type === 'component') {\n      this.updateWorkspaceConfig(name, rootDir, manifest);\n\n      if (afterComponentCreated) {\n        try {\n          // eslint-disable-next-line @typescript-eslint/no-var-requires\n          const fn = require(path.join(this.workspace.path, afterComponentCreated));\n          await fn(componentExports);\n        } catch (err) {\n          this.logger.consoleFailure(\n            `${\n              GeneratorAspect.id\n            }: failed to execute hook [afterComponentCreated]\\n${err.toString()}`\n          );\n        }\n      }\n    }\n\n    longProcessLogger.end();\n\n    return {\n      ok: true,\n      message: `new component [${name}] has been created successfully at '${rootDir.replace(\n        /^[^.]/,\n        ($0) => `./${$0}`\n      )}'`,\n    };\n  }\n}\n\nGeneratorAspect.addRuntime(GeneratorMain);\n"
  },
  {
    "path": "packages/service/src/generator/index.ts",
    "content": "import { GeneratorAspect } from './generator.aspect';\n\nexport default GeneratorAspect;\nexport { GeneratorAspect };\nexport { GeneratorMain } from './generator.main.runtime';\nexport type { GeneratorConfig } from './generator.main.runtime';\n"
  },
  {
    "path": "packages/service/src/index.ts",
    "content": "// don't write any content here\n// we create this file to make require.resolve() can find path of this package\n"
  },
  {
    "path": "packages/service/src/preview/bundlingStrategy.ts",
    "content": "import { Target, BundlerResult, BundlerContext } from '@arco-cli/aspect/dist/bundler';\n\nimport { BuildContext, BuildTaskResult } from '@service/builder';\n\nimport { PreviewDefinition } from './types';\nimport { PreviewTask } from './preview.task';\n\nexport interface ComputeTargetsContext extends BuildContext {\n  splitComponentBundle?: boolean;\n}\n\nexport interface BundlingStrategy {\n  /**\n   * name of the bundling strategy.\n   */\n  name: string;\n\n  /**\n   * compute bundling targets for the build context.\n   */\n  computeTargets(\n    context: ComputeTargetsContext,\n    previewDefs: PreviewDefinition[],\n    previewTask: PreviewTask\n  ): Promise<Target[]>;\n\n  /**\n   * compute the results of the bundler.\n   */\n  computeResults(\n    context: BundlerContext,\n    results: BundlerResult[],\n    previewTask: PreviewTask\n  ): Promise<BuildTaskResult>;\n}\n"
  },
  {
    "path": "packages/service/src/preview/cli/previewServerStatus/index.ts",
    "content": ""
  },
  {
    "path": "packages/service/src/preview/cli/previewServerStatus/previewServerHeader.tsx",
    "content": "import React from 'react';\nimport { Box, Text } from 'ink';\n\nexport function PreviewServerHeader() {\n  return (\n    <Box>\n      <Box width=\"40%\">\n        <Text underline>ENVIRONMENT NAME</Text>\n      </Box>\n      <Box width=\"40%\">\n        <Text underline>URL</Text>\n      </Box>\n      <Box width=\"20%\">\n        <Text underline>STATUS</Text>\n      </Box>\n    </Box>\n  );\n}\n"
  },
  {
    "path": "packages/service/src/preview/cli/previewServerStatus/previewServerRow.tsx",
    "content": "import React from 'react';\nimport { Text, Box } from 'ink';\nimport type { ComponentServer } from '@arco-cli/aspect/dist/bundler';\n\nexport type PreviewServerRowProps = {\n  previewServer: ComponentServer;\n  verbose?: boolean;\n};\n\nfunction stringifyIncludedEnvs(includedEnvs: string[] = [], verbose = false) {\n  if (includedEnvs.length > 2 && !verbose) return ` ${includedEnvs.length} other envs`;\n  return includedEnvs.join(', ');\n}\n\nexport function PreviewServerRow({ previewServer, verbose }: PreviewServerRowProps) {\n  return (\n    <Box>\n      <Box width=\"40%\">\n        <Text color=\"cyan\">\n          {previewServer.context.envRuntime.id}\n          {previewServer.context.relatedContexts.length &&\n          previewServer.context.relatedContexts.length > 1 ? (\n            <Text>\n              {' '}\n              on behalf of {stringifyIncludedEnvs(previewServer.context.relatedContexts, verbose)}\n            </Text>\n          ) : null}\n        </Text>\n      </Box>\n      <Box width=\"40%\">\n        <Text>{`http://localhost:${previewServer.port}`}</Text>\n      </Box>\n      <Box width=\"20%\">\n        <Text color=\"yellow\">RUNNING</Text>\n      </Box>\n    </Box>\n  );\n}\n"
  },
  {
    "path": "packages/service/src/preview/cli/previewServerStatus/previewServerStatus.tsx",
    "content": "import React, { useMemo } from 'react';\nimport { Text, Box } from 'ink';\nimport { head, flatten } from 'lodash';\nimport { ComponentServer } from '@arco-cli/aspect/dist/bundler';\nimport { Error, ErrorLevel } from './webpackError';\nimport { PreviewServerHeader } from './previewServerHeader';\nimport { PreviewServerRow } from './previewServerRow';\nimport type { CompilationResult } from '../../webpackEventsListener';\n\nexport const IGNORE_WARNINGS = [\n  // Webpack 5+ has no facility to disable this warning.\n  // System.import is used in @angular/core for deprecated string-form lazy routes\n  /System.import\\(\\) is deprecated and will be removed soon/i,\n  // We need to include all the files in the compilation because we don't know what people will use in their compositions\n  /is part of the TypeScript compilation but it's unused/i,\n  // https://github.com/webpack-contrib/source-map-loader/blob/b2de4249c7431dd8432da607e08f0f65e9d64219/src/index.js#L83\n  /Failed to parse source map from/,\n];\n\nexport type PreviewServerStatusProps = {\n  previewServers: ComponentServer[];\n  serverStats?: Record<string, CompilationResult>;\n};\n\nexport function PreviewServerStatus({\n  previewServers,\n  serverStats: servers = {},\n}: PreviewServerStatusProps) {\n  const isCompiling = useMemo(() => Object.values(servers).some((x) => x.compiling), [servers]);\n  const errors = useMemo(\n    () =>\n      head(\n        Object.values(servers)\n          .map((x) => x.errors)\n          .filter((x) => !!x)\n      ),\n    [servers]\n  );\n  const warnings = useMemo(\n    () => flatten(Object.values(servers).map((x) => x.warnings)),\n    [servers]\n  ).filter((warning) => !IGNORE_WARNINGS.find((reg) => warning?.message?.match(reg)));\n\n  if (errors && errors.length) {\n    return <Error errors={errors} level={ErrorLevel.ERROR} />;\n  }\n\n  if (isCompiling) {\n    return <Text>Compiling...</Text>;\n  }\n\n  return (\n    <>\n      <PreviewServerHeader />\n      {previewServers.map((server, key) => {\n        return <PreviewServerRow key={key} previewServer={server} />;\n      })}\n\n      {warnings && warnings.length > 0 && (\n        <Box marginTop={1} flexDirection=\"column\">\n          {/* could add dev-server name */}\n          <Error errors={warnings} level={ErrorLevel.WARNING} />\n        </Box>\n      )}\n    </>\n  );\n}\n"
  },
  {
    "path": "packages/service/src/preview/cli/previewServerStatus/webpackError.tsx",
    "content": "import React from 'react';\nimport { Text, Newline } from 'ink';\n\nexport enum ErrorLevel {\n  // eslint-disable-next-line no-unused-vars\n  WARNING = 'warning',\n  // eslint-disable-next-line no-unused-vars\n  ERROR = 'error',\n}\n\nexport type ErrorProps = {\n  errors: any[];\n  level: ErrorLevel;\n};\n\nexport function Error({ errors, level }: ErrorProps) {\n  const color = level === ErrorLevel.WARNING ? 'yellow' : 'red';\n\n  return (\n    <>\n      {errors.map((warning, index) => (\n        <Text key={index} color={color}>\n          <Text>{warning.message}</Text>\n          {warning.stack && <Newline />}\n          <Text>{warning.stack}</Text>\n          <Newline />\n        </Text>\n      ))}\n    </>\n  );\n}\n"
  },
  {
    "path": "packages/service/src/preview/exceptions/bundlingStrategyNotFoundError.ts",
    "content": "export class BundlingStrategyNotFoundError extends Error {\n  constructor(strategyName: string) {\n    super(`bundling strategy with name ${strategyName} was not found`);\n  }\n}\n"
  },
  {
    "path": "packages/service/src/preview/exceptions/index.ts",
    "content": "export { PreviewNotFoundError } from './previewNotFoundError';\nexport { PreviewOutputFileNotFoundError } from './previewOutputFileNotFoundError';\nexport { BundlingStrategyNotFoundError } from './bundlingStrategyNotFoundError';\n"
  },
  {
    "path": "packages/service/src/preview/exceptions/previewNotFoundError.ts",
    "content": "export class PreviewNotFoundError extends Error {\n  constructor(name: string | null) {\n    super(`Preview for name: ${name} was not found`);\n  }\n}\n"
  },
  {
    "path": "packages/service/src/preview/exceptions/previewOutputFileNotFoundError.ts",
    "content": "import ArcoError from '@arco-cli/legacy/dist/error/arcoError';\n\nexport class PreviewOutputFileNotFoundError extends ArcoError {\n  constructor(componentId: string, filePath: string) {\n    super(`preview output file for component: \"${componentId}\" was not found in the path: \"${filePath}\".\n\nThis is usually a result of an error during the bundling process.\nThe error might be an error of another component that uses the same env.`);\n  }\n}\n"
  },
  {
    "path": "packages/service/src/preview/executionRef.ts",
    "content": "import { Component } from '@arco-cli/aspect/dist/component';\nimport type { ExecutionContext } from '@arco-cli/aspect/dist/envs';\n\nexport class ExecutionRef {\n  constructor(public executionCtx: ExecutionContext) {\n    this.currentComponents = executionCtx.components;\n  }\n\n  currentComponents: Component[];\n\n  add(added: Component) {\n    this.currentComponents = this.currentComponents.concat(added);\n  }\n\n  remove(removed: string) {\n    this.currentComponents = this.currentComponents.filter((c) => c.id !== removed);\n  }\n\n  update(next: Component) {\n    this.currentComponents = this.currentComponents.map((c) => (c.id === next.id ? next : c));\n  }\n\n  get(id: string) {\n    return this.currentComponents.find((x) => x.id === id);\n  }\n}\n"
  },
  {
    "path": "packages/service/src/preview/generateLink.ts",
    "content": "import type { ComponentMap } from '@arco-cli/aspect/dist/component';\nimport { toWindowsCompatiblePath } from '@arco-cli/legacy/dist/utils/path';\n\nexport type GenerateLinkOptions = {\n  prefix: string;\n  componentMap: ComponentMap<{ previews: string[]; previewContextProvider: string }>;\n  componentMetadataMap?: ComponentMap<Record<string, any>>;\n  mainModule?: string;\n};\n\nexport function generateLink({\n  prefix,\n  mainModule,\n  componentMap,\n  componentMetadataMap,\n}: GenerateLinkOptions): string {\n  const links = componentMap\n    .toArray()\n    .map(\n      (\n        [\n          component,\n          { previews: previewFilePaths, previewContextProvider: previewContextProviderPath },\n        ],\n        index\n      ) => {\n        const metadata = componentMetadataMap?.getValueByComponentId(component.id) || {};\n        return {\n          metadata,\n          componentIdentifier: component.id,\n          modules: previewFilePaths.map((path, pathIdx) => ({\n            varName: moduleVarName(index, pathIdx),\n            resolveFrom: toWindowsCompatiblePath(path),\n          })),\n          contextProviderPath: toWindowsCompatiblePath(previewContextProviderPath),\n        };\n      }\n    );\n\n  return `\nimport { linkModules } from '${toWindowsCompatiblePath(\n    require.resolve('./previewRuntime/preview.preview.runtime')\n  )}';\n${\n  mainModule\n    ? `import * as mainModule from '${toWindowsCompatiblePath(mainModule)}';`\n    : 'const mainModule = {};'\n}\n\nlinkModules('${prefix}', {\n  mainModule,\n  componentMap: {\n${links\n  // must include all components, including empty\n  .map(\n    (link) =>\n      `    \"${link.componentIdentifier}\": [${link.modules\n        .map((module) => `() => import('${module.resolveFrom}')`)\n        .join(', ')}]`\n  )\n  .join(',\\n')}\n  },\n  componentMetadataMap: {\n${links\n  // must include all components, including empty\n  .map((link) => `    \"${link.componentIdentifier}\": ${JSON.stringify(link.metadata)}`)\n  .join(',\\n')}\n  },\n  componentContextProviderMap: {\n${links\n  .filter(({ contextProviderPath }) => contextProviderPath)\n  .map(\n    ({ componentIdentifier, contextProviderPath }) =>\n      `    \"${componentIdentifier}\": () => import('${contextProviderPath}')`\n  )\n  .join(',\\n')}\n  },\n});\n`;\n}\n\nfunction moduleVarName(componentIdx: number, fileIdx: number) {\n  return `file_${componentIdx}_${fileIdx}`;\n}\n"
  },
  {
    "path": "packages/service/src/preview/index.ts",
    "content": "import { PreviewAspect, PreviewRuntime } from './preview.aspect';\n\nexport default PreviewAspect;\nexport { PreviewAspect, PreviewRuntime };\nexport type { PreviewMain, EnvPreviewConfig, PreviewStrategyName } from './preview.main.runtime';\nexport type {\n  PreviewDefinition,\n  PreviewModule,\n  ModuleImportFunction,\n  RenderingContext,\n} from './types';\nexport {\n  COMPONENT_PREVIEW_STRATEGY_NAME,\n  ENV_PREVIEW_STRATEGY_NAME,\n} from './strategies/strategiesNames';\n"
  },
  {
    "path": "packages/service/src/preview/preview.aspect.ts",
    "content": "import { Aspect, RuntimeDefinition } from '@arco-cli/stone';\n\nexport const PREVIEW_ASPECT_ID = 'arco.service/preview';\n\nexport const PreviewRuntime = new RuntimeDefinition('preview');\n\nexport const PreviewAspect = Aspect.create({\n  id: PREVIEW_ASPECT_ID,\n  declareRuntime: PreviewRuntime,\n});\n\nexport default PreviewAspect;\n"
  },
  {
    "path": "packages/service/src/preview/preview.main.runtime.ts",
    "content": "import { join } from 'path';\nimport fs from 'fs-extra';\nimport { Slot, SlotRegistry } from '@arco-cli/stone';\nimport { MainRuntime } from '@arco-cli/core/dist/cli';\nimport { DIR_CACHE_ROOT } from '@arco-cli/legacy/dist/constants';\nimport { BundlerAspect, BundlerMain, Asset } from '@arco-cli/aspect/dist/bundler';\nimport { EnvsAspect, EnvsMain, ExecutionContext, PreviewEnv } from '@arco-cli/aspect/dist/envs';\nimport { AspectDefinition } from '@arco-cli/core/dist/aspect-loader';\nimport { Workspace, WorkspaceAspect } from '@arco-cli/aspect/dist/workspace';\nimport { PubsubAspect, PubsubMain } from '@arco-cli/aspect/dist/pubsub';\nimport { Component } from '@arco-cli/aspect/dist/component';\nimport { sha1 } from '@arco-cli/legacy/dist/utils';\nimport { Logger, LoggerAspect, LoggerMain } from '@arco-cli/core/dist/logger';\n\nimport { UIAspect, UIMain } from '@service/ui';\nimport { BuilderAspect, BuilderMain } from '@service/builder';\n\nimport PreviewAspect, { PreviewRuntime } from './preview.aspect';\nimport { PreviewStartPlugin } from './preview.startPlugin';\nimport { ExecutionRef } from './executionRef';\nimport { PreviewDefinition } from './types';\nimport { generateLink } from './generateLink';\nimport { PreviewTask } from './preview.task';\nimport { BundlingStrategy } from './bundlingStrategy';\nimport { COMPONENT_PREVIEW_STRATEGY_NAME, ComponentBundlingStrategy } from './strategies';\nimport { BundlingStrategyNotFoundError } from './exceptions';\n\nconst DEFAULT_CACHE_DIR = join(DIR_CACHE_ROOT, PreviewAspect.id);\n\nconst NOOP_RESULT = {\n  results: [],\n  toString: () => `updating link file`,\n};\n\nexport type PreviewStrategyName = 'env' | 'component';\n\nexport type EnvPreviewConfig = {\n  strategyName?: PreviewStrategyName;\n  splitComponentBundle?: boolean;\n};\n\nexport type PreviewConfig = {\n  bundlingStrategy?: string;\n  disabled: boolean;\n  /**\n   * limit concurrent components when running the bundling step for your bundler during generate components preview task.\n   * this helps mitigate large memory consumption for the build pipeline. This may increase the overall time for the generate-preview task, but reduce memory footprint.\n   * default - no limit.\n   */\n  maxChunkSize?: number;\n};\n\nexport type ComponentPreviewSizedFile = Asset;\n\nexport type ComponentPreviewSize = {\n  files: ComponentPreviewSizedFile[];\n  assets: ComponentPreviewSizedFile[];\n  totalFiles: number;\n  compressedTotalFiles?: number;\n  totalAssets: number;\n  compressedTotalAssets?: number;\n  total: number;\n  compressedTotal?: number;\n};\n\nexport type ComponentPreviewMetaData = {\n  size?: ComponentPreviewSize;\n};\n\nexport type PreviewDefinitionSlot = SlotRegistry<PreviewDefinition>;\n\nexport class PreviewMain {\n  static runtime = MainRuntime;\n\n  static dependencies = [\n    WorkspaceAspect,\n    UIAspect,\n    BundlerAspect,\n    PubsubAspect,\n    BuilderAspect,\n    LoggerAspect,\n    EnvsAspect,\n  ];\n\n  static slots = [Slot.withType<PreviewDefinition>()];\n\n  static provider(\n    [workspace, uiMain, bundler, pubsub, builder, loggerMain, envs]: [\n      Workspace,\n      UIMain,\n      BundlerMain,\n      PubsubMain,\n      BuilderMain,\n      LoggerMain,\n      EnvsMain\n    ],\n    config: PreviewConfig,\n    [previewSlot]: [PreviewDefinitionSlot]\n  ) {\n    const logger = loggerMain.createLogger(PreviewAspect.id);\n    const preview = new PreviewMain(config, workspace, uiMain, logger, envs, previewSlot);\n\n    if (workspace) {\n      uiMain.registerStartPlugin(new PreviewStartPlugin(workspace, bundler, pubsub, logger));\n      // workspace.registerOnComponentLoad(() => {});\n      // workspace.registerOnComponentChange(async () => {});\n      // workspace.registerOnComponentAdd(async () => {});\n      workspace.registerOnComponentChange((component) =>\n        preview.handleComponentChange(component, (currentComponents) =>\n          currentComponents.update(component)\n        )\n      );\n    }\n\n    builder.registerBuildTasks([new PreviewTask(preview)]);\n\n    bundler.registerTarget({\n      entry: preview.getPreviewTarget.bind(preview),\n    });\n\n    return preview;\n  }\n\n  constructor(\n    public config: PreviewConfig,\n    private workspace: Workspace | undefined,\n    private ui: UIMain,\n    private logger: Logger,\n    private envs: EnvsMain,\n    private previewSlot: PreviewDefinitionSlot\n  ) {}\n\n  get cacheDir(): string {\n    return this.workspace?.getCacheDir(PreviewAspect.id) || DEFAULT_CACHE_DIR;\n  }\n\n  private executionRefs = new Map<string, ExecutionRef>();\n\n  private writeHash = new Map<string, string>();\n\n  private timestamp = Date.now();\n\n  private getUi() {\n    const ui = this.ui.getUi();\n    if (!ui) throw new Error('ui not found');\n    return ui;\n  }\n\n  private async getPreviewTarget(\n    /** execution context (of the specific env) */\n    context: ExecutionContext\n  ): Promise<string[]> {\n    // store context for later link-file updates\n    // also register related envs that this context is acting on their behalf\n    [context.id, ...context.relatedContexts].forEach((ctxId) => {\n      this.executionRefs.set(ctxId, new ExecutionRef(context));\n    });\n\n    const previewRuntime = await this.writePreviewRuntime();\n    const linkFiles = await this.updateLinkFiles(context, context.components);\n\n    return [...linkFiles, previewRuntime];\n  }\n\n  private getDefaultStrategies() {\n    return [new ComponentBundlingStrategy(this)];\n  }\n\n  private async resolveAspects(runtimeName?: string): Promise<AspectDefinition[]> {\n    const root = this.getUi()[1];\n    runtimeName = runtimeName || MainRuntime.name;\n    const resolvedAspects = await root.resolveAspects(runtimeName);\n    return resolvedAspects;\n  }\n\n  private updateLinkFiles(context: ExecutionContext, components: Component[] = []) {\n    const previews = this.previewSlot.values();\n    const paths = previews.map(async (previewDef) => {\n      const dirPath = join(this.cacheDir, context.id);\n      if (!fs.existsSync(dirPath)) {\n        fs.mkdirSync(dirPath, { recursive: true });\n      }\n\n      const prefix = previewDef.prefix;\n      const templatePath = await previewDef.renderTemplatePath?.(context.env);\n      const componentMap = (await previewDef.getModuleMap(components)).map(\n        ({ previews, previewContextProvider }) => {\n          return {\n            previews: previews.map((file) => file.path),\n            previewContextProvider: previewContextProvider?.path,\n          };\n        }\n      );\n      const componentMetadataMap = await previewDef.getMetadataMap?.(components, context.env);\n\n      const contents = generateLink({\n        prefix,\n        componentMap,\n        mainModule: templatePath,\n        componentMetadataMap,\n      });\n      const hash = sha1(contents);\n      const targetPath = join(dirPath, `${prefix}-${this.timestamp}.js`);\n\n      // write only if link has changed (prevents triggering fs watches)\n      if (this.writeHash.get(targetPath) !== hash) {\n        fs.writeFileSync(targetPath, contents);\n        this.writeHash.set(targetPath, hash);\n      }\n\n      return targetPath;\n    });\n\n    return Promise.all(paths);\n  }\n\n  private async handleComponentChange(\n    c: Component,\n    updater: (currentComponents: ExecutionRef) => void\n  ) {\n    const env = this.envs.getEnv(c);\n    const envId = env.id.toString();\n\n    const executionRef = this.executionRefs.get(envId);\n    if (!executionRef) {\n      this.logger.warn(\n        `failed to update link file for component \"${c.id.toString()}\" - could not find execution context for ${envId}`\n      );\n      return NOOP_RESULT;\n    }\n\n    // add / remove / etc\n    updater(executionRef);\n    await this.updateLinkFiles(executionRef.executionCtx, executionRef.currentComponents);\n\n    return NOOP_RESULT;\n  }\n\n  getDefs(): PreviewDefinition[] {\n    return this.previewSlot.values();\n  }\n\n  getEnvPreviewConfig(env?: PreviewEnv): EnvPreviewConfig {\n    return typeof env?.getPreviewConfig === 'function' ? env.getPreviewConfig() : {};\n  }\n\n  getBundlingStrategy(env?: PreviewEnv): BundlingStrategy {\n    const strategies = this.getDefaultStrategies();\n    const envPreviewConfig = this.getEnvPreviewConfig(env);\n    const strategyFromEnv = envPreviewConfig?.strategyName;\n    const strategyName =\n      strategyFromEnv || this.config.bundlingStrategy || COMPONENT_PREVIEW_STRATEGY_NAME;\n    const selected = strategies.find((strategy) => {\n      return strategy.name === strategyName;\n    });\n\n    if (!selected) throw new BundlingStrategyNotFoundError(strategyName);\n\n    return selected;\n  }\n\n  registerDefinition(previewDef: PreviewDefinition) {\n    this.previewSlot.register(previewDef);\n  }\n\n  async writePreviewRuntime() {\n    const [name] = this.getUi();\n    const resolvedAspects = await this.resolveAspects(PreviewRuntime.name);\n    const filePath = await this.ui.generateRoot({\n      aspectDefs: resolvedAspects,\n      runtimeName: PreviewRuntime.name,\n      rootAspect: PreviewAspect.id,\n      rootExtensionName: name,\n    });\n    return filePath;\n  }\n\n  writeBuildEntry(contents: string, targetDir: string, prefix: string) {\n    const hash = sha1(contents);\n    const targetPath = join(targetDir, `${prefix}-${this.timestamp}.js`);\n\n    // TODO clear cache before build-task\n    // write only if link has changed (prevents triggering fs watches)\n    if (this.writeHash.get(targetPath) !== hash) {\n      fs.writeFileSync(targetPath, contents);\n      this.writeHash.set(targetPath, hash);\n    }\n\n    return targetPath;\n  }\n}\n\nPreviewAspect.addRuntime(PreviewMain);\n"
  },
  {
    "path": "packages/service/src/preview/preview.startPlugin.tsx",
    "content": "import React, { useState, useEffect, Dispatch, SetStateAction } from 'react';\nimport { flatten } from 'lodash';\nimport { Workspace } from '@arco-cli/aspect/dist/workspace';\nimport { BundlerMain } from '@arco-cli/aspect/dist/bundler';\nimport { PubsubMain } from '@arco-cli/aspect/dist/pubsub';\nimport { ComponentServer } from '@arco-cli/aspect/dist/bundler/componentServer';\nimport { Logger } from '@arco-cli/core/dist/logger';\n\nimport { StartPlugin, StartPluginOptions, ProxyEntry } from '@service/ui';\n\nimport { CompilationResult, SubscribeToWebpackEvents } from './webpackEventsListener';\nimport { PreviewServerStatus } from './cli/previewServerStatus/previewServerStatus';\n\ntype CompilationServers = Record<string, CompilationResult>;\ntype ServersSetter = Dispatch<SetStateAction<CompilationServers>>;\n\nexport class PreviewStartPlugin implements StartPlugin {\n  constructor(\n    private workspace: Workspace,\n    private bundler: BundlerMain,\n    private pubsub: PubsubMain,\n    private logger: Logger\n  ) {}\n\n  previewServers: ComponentServer[] = [];\n\n  private setReady: () => void;\n\n  private readyPromise = new Promise<void>((resolve) => {\n    this.setReady = resolve;\n  });\n\n  private initialState: CompilationServers = {};\n\n  // implements react-like setter (value or updater)\n  private updateServers: ServersSetter = (servers) => {\n    this.initialState = typeof servers === 'function' ? servers(this.initialState) : servers;\n    return servers;\n  };\n\n  private listenToDevServers() {\n    // keep state changes immutable!\n    SubscribeToWebpackEvents(this.pubsub, {\n      onStart: (id) => {\n        this.updateServers((state) => ({\n          ...state,\n          [id]: { compiling: true },\n        }));\n      },\n      onDone: (id, results) => {\n        this.updateServers((state) => ({\n          ...state,\n          [id]: results,\n        }));\n      },\n    });\n  }\n\n  get whenReady(): Promise<void> {\n    return this.readyPromise;\n  }\n\n  async initiate(options: StartPluginOptions) {\n    this.listenToDevServers();\n\n    // set workspace's component pattern\n    this.workspace.setComponentPattern(options.pattern);\n\n    const conponents = await this.workspace.getManyByPattern(options.pattern);\n    const previewServers = await this.bundler.devServer(conponents);\n    previewServers.forEach((server) => server.listen());\n\n    // DON'T add wait! this promise never resolve, so it will stop all the start process!\n    this.workspace.watcher.watchAll({}).catch((error) => {\n      const msg = `watcher found an error`;\n      this.logger.error(msg, error);\n      this.logger.console(`${msg}, ${error.message}`);\n    });\n\n    this.previewServers = this.previewServers.concat(previewServers);\n  }\n\n  getProxy(): ProxyEntry[] {\n    const proxyConfigs = this.previewServers.map<ProxyEntry[]>((server) => {\n      return [\n        {\n          context: [`/preview/${server.context.envRuntime.id}`],\n          target: `http://localhost:${server.port}`,\n        },\n        {\n          context: [`/_hmr/${server.context.envRuntime.id}`],\n          target: `http://localhost:${server.port}`,\n          ws: true,\n        },\n      ];\n    });\n\n    return flatten(proxyConfigs);\n  }\n\n  render = () => {\n    const [servers, setServers] = useState<CompilationServers>(this.initialState);\n    this.updateServers = setServers;\n    this.initialState = {};\n\n    useEffect(() => {\n      const noneAreCompiling = Object.values(servers).every((x) => !x.compiling);\n      if (noneAreCompiling) this.setReady();\n    }, [servers]);\n\n    return <PreviewServerStatus previewServers={this.previewServers} serverStats={servers} />;\n  };\n}\n"
  },
  {
    "path": "packages/service/src/preview/preview.task.ts",
    "content": "import { resolve } from 'path';\nimport { ExecutionContext } from '@arco-cli/aspect/dist/envs';\nimport { Bundler, BundlerContext, Target } from '@arco-cli/aspect/dist/bundler';\nimport { BUILD_TASK_NAME_PREVIEW } from '@arco-cli/legacy/dist/constants';\n\nimport { BuildContext, BuildTask, BuildTaskResult, TaskLocation } from '@service/builder';\n\nimport { PreviewMain } from './preview.main.runtime';\nimport { PREVIEW_ASPECT_ID } from './preview.aspect';\n\nexport class PreviewTask implements BuildTask {\n  constructor(private preview: PreviewMain) {}\n\n  aspectId = PREVIEW_ASPECT_ID;\n\n  name = BUILD_TASK_NAME_PREVIEW;\n\n  location: TaskLocation = 'end';\n\n  async execute(context: BuildContext): Promise<BuildTaskResult> {\n    const defs = this.preview.getDefs();\n    const url = `/preview/${context.envRuntime.id}`;\n    const bundlingStrategy = this.preview.getBundlingStrategy(context.env);\n    const envPreviewConfig = this.preview.getEnvPreviewConfig(context.env);\n    const splitComponentBundle = envPreviewConfig.splitComponentBundle ?? false;\n    const computeTargetsContext = Object.assign(context, { splitComponentBundle });\n\n    const targets: Target[] = await bundlingStrategy.computeTargets(\n      computeTargetsContext,\n      defs,\n      this\n    );\n\n    const bundlerContext: BundlerContext = Object.assign(context, {\n      targets,\n      entry: [],\n      publicPath: this.getPreviewDirectory(context),\n      rootPath: url,\n      metaData: {\n        initiator: `${BUILD_TASK_NAME_PREVIEW} task`,\n        envId: context.id,\n      },\n    });\n\n    const bundler: Bundler = await context.env.getBundler(bundlerContext);\n    const bundlerResults = await bundler.run();\n\n    return bundlingStrategy.computeResults(bundlerContext, bundlerResults, this);\n  }\n\n  getPreviewDirectory(context: ExecutionContext) {\n    return resolve(`${context.id}/public`);\n  }\n}\n"
  },
  {
    "path": "packages/service/src/preview/previewRuntime/index.ts",
    "content": "export { PreviewAspect, PreviewRuntime } from '../preview.aspect';\nexport type { PreviewPreview } from './preview.preview.runtime';\n"
  },
  {
    "path": "packages/service/src/preview/previewRuntime/preview.preview.runtime.tsx",
    "content": "import { Slot, SlotRegistry } from '@arco-cli/stone';\n\nimport { PREVIEW_MODULES } from './previewModules';\nimport { PreviewNotFoundError } from '../exceptions';\nimport PreviewAspect, { PreviewRuntime } from '../preview.aspect';\nimport {\n  PreviewModule,\n  PreviewType,\n  RenderingContext,\n  RenderingContextSlot,\n  RenderingContextProvider,\n} from '../types';\n\n// forward linkModules for generate-link.ts\nexport { linkModules } from './previewModules';\n\ntype PreviewSlot = SlotRegistry<PreviewType>;\n\nexport class PreviewPreview {\n  static dependencies = [];\n\n  static slots = [Slot.withType<PreviewType>(), Slot.withType<RenderingContextProvider>()];\n\n  static runtime = PreviewRuntime;\n\n  static provider(\n    _deps,\n    _config,\n    [previewSlot, renderingContextSlot]: [PreviewSlot, RenderingContextSlot]\n  ) {\n    const previewPreview = new PreviewPreview(previewSlot, renderingContextSlot);\n    return previewPreview;\n  }\n\n  constructor(\n    private previewSlot: PreviewSlot,\n    private renderingContextSlot: RenderingContextSlot\n  ) {}\n\n  private getParam(query: string, param: string) {\n    const params = new URLSearchParams(query);\n    return params.get(param);\n  }\n\n  private getQuery() {\n    const withoutHash = window.location.hash.substring(1);\n    const [, after] = withoutHash.split('?');\n    return after;\n  }\n\n  private getLocation() {\n    const withoutHash = window.location.hash.substring(1);\n    const [before, after] = withoutHash.split('?');\n\n    return {\n      previewName: this.getParam(after, 'preview'),\n      componentId: before,\n    };\n  }\n\n  private getDefault() {\n    const previews = this.previewSlot.values();\n    const defaultOne = previews.find((previewCandidate) => previewCandidate.default);\n    return defaultOne?.name || previews[0].name;\n  }\n\n  private getPreview(previewName: string): undefined | PreviewType {\n    const previews = this.previewSlot.values();\n    return previews.find((previewCandidate) => previewCandidate.name === previewName);\n  }\n\n  private async getPreviewModule(previewName: string): Promise<PreviewModule> {\n    const relevantModel = PREVIEW_MODULES.get(previewName);\n    if (!relevantModel) throw new Error(`[preview.preview] missing preview \"${previewName}\"`);\n    return relevantModel;\n  }\n\n  private getRenderingContext() {\n    return new RenderingContext(this.renderingContextSlot);\n  }\n\n  registerPreview(preview: PreviewType) {\n    this.previewSlot.register(preview);\n    return this;\n  }\n\n  registerRenderContext(renderContext: RenderingContextProvider) {\n    this.renderingContextSlot.register(renderContext);\n    return this;\n  }\n\n  setViewport() {\n    const query = this.getQuery();\n    const viewPort = this.getParam(query, 'viewport');\n    if (viewPort) {\n      window.document.body.style.maxWidth = `${viewPort}px`;\n    } else {\n      window.document.body.style.width = '100%';\n    }\n  }\n\n  async render() {\n    // fit content always.\n    window.document.body.style.width = 'fit-content';\n\n    const { previewName, componentId } = this.getLocation();\n    const name = previewName || this.getDefault();\n    const preview = this.getPreview(name);\n\n    if (!preview) {\n      throw new PreviewNotFoundError(previewName);\n    }\n\n    const includes = (\n      await Promise.all(\n        (preview.include || []).map(async (inclPreviewName) => {\n          const includedPreview = this.getPreview(inclPreviewName);\n          if (!includedPreview) return undefined;\n\n          const inclPreviewModule = await this.getPreviewModule(inclPreviewName);\n          return includedPreview.selectPreviewModel?.(componentId, inclPreviewModule);\n        })\n      )\n    ).filter((module) => !!module);\n\n    const previewModule = await this.getPreviewModule(name);\n    await preview.render(componentId, previewModule, includes, this.getRenderingContext());\n\n    this.setViewport();\n  }\n}\n\nPreviewAspect.addRuntime(PreviewPreview);\n"
  },
  {
    "path": "packages/service/src/preview/previewRuntime/previewModules.tsx",
    "content": "import type { PreviewModule, ModuleImportFunction } from '../types';\n\ntype ModuleId = string;\n\nexport class PreviewModules extends Map<ModuleId, PreviewModule> {\n  onSet = new Set<() => void>();\n\n  override set(id: ModuleId, preview: PreviewModule) {\n    super.set(id, preview);\n    this.onSet.forEach((callback) => callback());\n    return this;\n  }\n\n  loadComponentPreviews(compId: string, previews: Record<string, ModuleImportFunction[]>) {\n    Object.entries(previews).forEach(([previewName, moduleFile]) => {\n      const preview = this.get(previewName);\n      if (preview) {\n        preview.componentMap[compId] = moduleFile;\n      }\n    });\n  }\n}\n\nexport const PREVIEW_MODULES = new PreviewModules();\n\nexport function linkModules(previewName: string, previewModule: PreviewModule) {\n  PREVIEW_MODULES.set(previewName, previewModule);\n}\n"
  },
  {
    "path": "packages/service/src/preview/strategies/componentStrategy.ts",
    "content": "import fs from 'fs-extra';\nimport { join, resolve, basename, dirname } from 'path';\nimport { Component } from '@arco-cli/aspect/dist/component';\nimport { flatten, isEmpty, chunk } from 'lodash';\nimport { toFsCompatible } from '@arco-cli/legacy/dist/utils';\nimport type {\n  Asset,\n  Target,\n  BundlerResult,\n  BundlerContext,\n  BundlerEntryMap,\n} from '@arco-cli/aspect/dist/bundler';\nimport type { ComponentResult } from '@arco-cli/legacy/dist/workspace/componentResult';\nimport {\n  toComponentChunkId,\n  toComponentChunkFilename,\n} from '@arco-cli/legacy/dist/workspace/componentIdTo';\nimport { DIR_ARTIFACTS_PREVIEW } from '@arco-cli/legacy/dist/constants';\n\nimport { BundlingStrategy, ComputeTargetsContext } from '../bundlingStrategy';\nimport type { PreviewDefinition } from '../types';\nimport type { ComponentPreviewMetaData, PreviewMain } from '../preview.main.runtime';\nimport { generatePreviewBundleEntry } from './generatePreviewBundleEntry';\nimport { PreviewOutputFileNotFoundError } from '../exceptions';\n\nexport const COMPONENT_STRATEGY_SIZE_KEY_NAME = 'size';\nexport const COMPONENT_STRATEGY_ARTIFACT_NAME = 'preview-component';\n\ntype ComponentEntry = {\n  component: Component;\n  entries: Record<string, any>;\n};\n\n/**\n * bundles all components in a given env into the same bundle.\n */\nexport class ComponentBundlingStrategy implements BundlingStrategy {\n  name = 'component';\n\n  artifactDir = DIR_ARTIFACTS_PREVIEW;\n\n  constructor(private preview: PreviewMain) {}\n\n  async computeTargets(\n    context: ComputeTargetsContext,\n    previewDefs: PreviewDefinition[]\n  ): Promise<Target[]> {\n    const cacheDir = this.getCacheDir(context);\n    const outputPath = this.getOutputPath(context);\n\n    fs.removeSync(cacheDir);\n    fs.ensureDirSync(outputPath);\n\n    const entriesArr = await Promise.all(\n      context.components.map((component) => {\n        return this.computeComponentEntry(previewDefs, component, context);\n      }, {})\n    );\n    const chunkSize = this.preview.config.maxChunkSize;\n    const chunks = chunkSize ? chunk(entriesArr, chunkSize) : [entriesArr];\n\n    return chunks.map((currentChunk) => {\n      const entries: BundlerEntryMap = {};\n      const components: Component[] = [];\n      currentChunk.forEach((entry) => {\n        Object.assign(entries, entry.entries);\n        components.push(entry.component);\n      });\n\n      return {\n        entries,\n        components,\n        outputPath,\n      };\n    });\n  }\n\n  async computeResults(context: BundlerContext, results: BundlerResult[]) {\n    const componentsResults = flatten(\n      await Promise.all(results.map((result) => this.computeTargetResult(context, result)))\n    );\n\n    const artifacts = [\n      {\n        name: COMPONENT_STRATEGY_ARTIFACT_NAME,\n        globPatterns: ['**'],\n        rootDir: this.artifactDir,\n      },\n    ];\n\n    return {\n      componentsResults,\n      artifacts,\n    };\n  }\n\n  private async computeComponentEntry(\n    previewDefs: PreviewDefinition[],\n    component: Component,\n    context: ComputeTargetsContext\n  ): Promise<ComponentEntry> {\n    const componentPreviewPath = await this.computePaths(previewDefs, context, component);\n    // const componentPath = resolve(\n    //   context.workspace.path,\n    //   component.componentDir,\n    //   component.entries.main\n    // );\n    const chunks = {\n      componentPreview: toComponentChunkId(component.id, 'preview'),\n      // TODO build component UMD dist files\n      // component: context.splitComponentBundle ? component.id : undefined,\n    };\n    const entries = {\n      [chunks.componentPreview]: {\n        filename: toComponentChunkFilename(component.id, 'preview'),\n        import: componentPreviewPath,\n        library: { name: chunks.componentPreview, type: 'umd' },\n      },\n    };\n\n    // if (chunks.component) {\n    //   entries[chunks.component] = {\n    //     filename: this.getComponentChunkFilename(component.id, 'component'),\n    //     import: componentPath,\n    //     library: { name: chunks.component, type: 'umd' },\n    //   };\n    // }\n\n    return { component, entries };\n  }\n\n  private getCacheDir(context: ComputeTargetsContext) {\n    const capsulesDir = context.workspace.getCacheDir('capsules');\n    const envName = context.id.replace('/', '__');\n    return resolve(`${capsulesDir}/${envName}-preview`);\n  }\n\n  private getOutputPath(context: ComputeTargetsContext) {\n    return resolve(`${this.getCacheDir(context)}/output`);\n  }\n\n  private getAssetAbsolutePath(context: BundlerContext, asset: Asset): string {\n    const path = this.getOutputPath(context);\n    return join(path, 'public', this.getAssetFilename(asset));\n  }\n\n  private getAssetFilename(asset: Asset): string {\n    // handle cases where the asset name is something like my-image.svg?hash (while the filename in the fs is just my-image.svg)\n    const [name] = asset.name.split('?');\n    return name;\n  }\n\n  private async copyAssetsToArtifacts(context: BundlerContext, result: BundlerResult) {\n    // components may share the same artifact dir\n    // old artifacts should be cleaned up before copy task starting\n    await Promise.all(\n      context.components.map(async (component) => {\n        await fs.remove(join(component.packageDirAbs, this.artifactDir));\n      })\n    );\n\n    return Promise.all(\n      context.components.map(async (component) => {\n        const files = this.findAssetsForComponent(component, result);\n\n        if (!files) return;\n\n        const artifactDirFullPath = join(component.packageDirAbs, this.artifactDir);\n\n        await Promise.all(\n          files.map(async (asset) => {\n            const filePath = this.getAssetAbsolutePath(context, asset);\n            if (!fs.existsSync(filePath)) {\n              throw new PreviewOutputFileNotFoundError(component.id, filePath);\n            }\n            const destFilePath = join(artifactDirFullPath, this.getAssetFilename(asset));\n            await fs.ensureDir(dirname(destFilePath));\n            await fs.copyFile(filePath, destFilePath);\n          })\n        );\n      })\n    );\n  }\n\n  private findAssetsForComponent(\n    component: Component,\n    bundlerResult: BundlerResult\n  ): Asset[] | undefined {\n    const { assets, entriesAssetsMap = {}, chunks = [] } = bundlerResult;\n\n    if (!assets) return undefined;\n\n    const componentEntryId = component.id;\n    const componentPreviewEntryId = toComponentChunkId(component.id, 'preview');\n    const componentFiles = entriesAssetsMap[componentEntryId]?.assets || [];\n    const componentAuxiliaryFiles = entriesAssetsMap[componentEntryId]?.auxiliaryAssets || [];\n    const componentPreviewFiles = entriesAssetsMap[componentPreviewEntryId]?.assets || [];\n    const componentPreviewAuxiliaryFiles =\n      entriesAssetsMap[componentPreviewEntryId]?.auxiliaryAssets || [];\n\n    const result = componentFiles\n      .concat(componentAuxiliaryFiles)\n      .concat(componentPreviewFiles)\n      .concat(componentPreviewAuxiliaryFiles);\n\n    // find asset which belong to component runtime but not exist in its assets\n    chunks.forEach((chunk) => {\n      if (\n        chunk.runtime.indexOf(componentEntryId) > -1 ||\n        chunk.runtime.indexOf(componentPreviewEntryId) > -1\n      ) {\n        chunk.files.forEach((chunkFileName) => {\n          // if chunk-asset is not in component asset list, add it\n          if (!result.find((asset) => asset.name === chunkFileName)) {\n            const chunkFileAsset = assets.find((asset) => asset.name === chunkFileName);\n            chunkFileAsset && result.push(chunkFileAsset);\n          }\n        });\n      }\n    });\n\n    return result;\n  }\n\n  private computeComponentMetadata(\n    result: BundlerResult,\n    component: Component\n  ): ComponentPreviewMetaData {\n    const componentEntryId = component.id;\n\n    if (!result?.entriesAssetsMap || !result?.entriesAssetsMap[componentEntryId]) {\n      return {};\n    }\n\n    const files = (result.entriesAssetsMap[componentEntryId]?.assets || []).map((file) => {\n      return {\n        name: basename(file.name),\n        size: file.size,\n        compressedSize: file.compressedSize,\n      };\n    });\n    const filesTotalSize = result.entriesAssetsMap[componentEntryId]?.assetsSize || 0;\n    const compressedTotalFiles =\n      result.entriesAssetsMap[componentEntryId]?.compressedAssetsSize || 0;\n    const assets = (result.entriesAssetsMap[componentEntryId]?.auxiliaryAssets || []).map(\n      (file) => {\n        return {\n          name: basename(file.name),\n          size: file.size,\n          compressedSize: file.compressedSize,\n        };\n      }\n    );\n    const assetsTotalSize = result.entriesAssetsMap[componentEntryId]?.auxiliaryAssetsSize || 0;\n    const compressedTotalAssets =\n      result.entriesAssetsMap[componentEntryId]?.compressedAuxiliaryAssetsSize || 0;\n    const totalSize = filesTotalSize + assetsTotalSize;\n    const compressedTotal = compressedTotalFiles + compressedTotalAssets;\n\n    return {\n      [COMPONENT_STRATEGY_SIZE_KEY_NAME]: {\n        files,\n        assets,\n        totalFiles: filesTotalSize,\n        totalAssets: assetsTotalSize,\n        total: totalSize,\n        compressedTotalFiles,\n        compressedTotalAssets,\n        compressedTotal,\n      },\n    };\n  }\n\n  private async computeTargetResult(context: BundlerContext, result: BundlerResult) {\n    if (isEmpty(result.errors)) {\n      // In case there are errors files will not be emitted so trying to copy them will fail anyway\n      await this.copyAssetsToArtifacts(context, result);\n    }\n\n    const componentsResults: ComponentResult[] = result.components.map((component) => {\n      const metadata = this.computeComponentMetadata(result, component);\n      return {\n        id: component.id,\n        metadata,\n        errors: result.errors.map((err) => (typeof err === 'string' ? err : err.message)),\n        warning: result.warnings,\n        startTime: result.startTime,\n        endTime: result.endTime,\n      };\n    });\n\n    return componentsResults;\n  }\n\n  private async computePaths(\n    defs: PreviewDefinition[],\n    context: ComputeTargetsContext,\n    component: Component\n  ): Promise<string> {\n    const moduleMapsPromise = defs.map(async (previewDef) => {\n      const { previews: previewFiles, previewContextProvider: previewContextProviderFile } = (\n        await previewDef.getModuleMap([component])\n      ).getValueByComponentId(component.id);\n\n      if (!previewFiles) {\n        return { prefix: previewDef.prefix, previewPaths: [] };\n      }\n\n      const previewPaths = previewFiles.map((file) => file.path);\n      const renderPath = await previewDef.renderTemplatePath?.(context.env);\n      const metadata = (\n        await previewDef.getMetadataMap([component], context.env)\n      ).getValueByComponentId(component.id);\n\n      return {\n        prefix: previewDef.prefix,\n        previewPaths,\n        previewContextProviderPath: previewContextProviderFile?.path,\n        renderPath,\n        metadata,\n      };\n    });\n\n    const moduleMaps = await Promise.all(moduleMapsPromise);\n    const contents = generatePreviewBundleEntry(moduleMaps);\n    const filenamePrefix = `preview.${toFsCompatible(component.id)}`;\n\n    return this.preview.writeBuildEntry(contents, this.getCacheDir(context), filenamePrefix);\n  }\n}\n"
  },
  {
    "path": "packages/service/src/preview/strategies/generatePreviewBundleEntry.ts",
    "content": "import { toWindowsCompatiblePath } from '@arco-cli/legacy/dist/utils/path';\n\nexport type ModuleVar = {\n  prefix: string;\n  previewPaths: string[];\n  previewContextProviderPath?: string;\n  renderPath?: string;\n  metadata?: unknown;\n};\n\nexport function generatePreviewBundleEntry(modules: ModuleVar[]): string {\n  const previews = modules.map(({ prefix, previewPaths }) => {\n    return {\n      name: prefix,\n      entries: previewPaths.map((path, idx) => ({\n        path: toWindowsCompatiblePath(path),\n        importedName: `${prefix}_${idx}`,\n      })),\n    };\n  });\n\n  const previewContextProviders = modules\n    .filter(({ previewContextProviderPath }) => previewContextProviderPath)\n    .map(({ prefix, previewContextProviderPath }) => {\n      return {\n        name: prefix,\n        entry: {\n          path: toWindowsCompatiblePath(previewContextProviderPath),\n          importedName: `${prefix}_context_provider`,\n        },\n      };\n    });\n\n  const renders = modules\n    .filter(({ renderPath }) => renderPath)\n    .map(({ prefix, renderPath }) => {\n      return {\n        name: prefix,\n        entry: {\n          path: toWindowsCompatiblePath(renderPath),\n          importedName: `${prefix}_render`,\n        },\n      };\n    });\n\n  // import per preview file\n  const importPreviewStr: string = previews\n    .map(({ entries }) =>\n      entries\n        .map(({ path, importedName }) => `import * as ${importedName} from '${path}'`)\n        .join(';\\n')\n    )\n    .join(';\\n');\n\n  // import per preview-context-provider file\n  const importPreviewContextProviderStr: string = previewContextProviders\n    .map(({ entry: { path, importedName } }) => `import ${importedName} from '${path}'`)\n    .join(';\\n');\n\n  // import per render function file\n  const importRenderStr: string = renders\n    .map(({ entry: { path, importedName } }) => `import ${importedName} from '${path}'`)\n    .join(';\\n');\n\n  // export files group per preview\n  const exportsString: string = previews\n    .map(\n      ({ name, entries }) =>\n        `export const ${name} = [${entries.map((entry) => entry.importedName).join(', ')}]`\n    )\n    .concat(\n      previewContextProviders.map(\n        ({ name, entry }) => `export const ${name}ContextProvider = ${entry.importedName}`\n      )\n    )\n    .concat(renders.map(({ name, entry }) => `export const ${name}Render = ${entry.importedName}`))\n    .join(';\\n');\n\n  const exportsMetadataString: string = modules\n    .filter(({ metadata }) => metadata)\n    .map(({ prefix, metadata }) => `export const ${prefix}Metadata = ${JSON.stringify(metadata)}`)\n    .join(';\\n');\n\n  return `${importPreviewStr};\n  \n${importPreviewContextProviderStr};\n\n${importRenderStr};\n\n${exportsString};\n\n${exportsMetadataString};\n`;\n}\n"
  },
  {
    "path": "packages/service/src/preview/strategies/index.ts",
    "content": "export {\n  ComponentBundlingStrategy,\n  COMPONENT_STRATEGY_ARTIFACT_NAME,\n  COMPONENT_STRATEGY_SIZE_KEY_NAME,\n} from './componentStrategy';\nexport { ENV_PREVIEW_STRATEGY_NAME, COMPONENT_PREVIEW_STRATEGY_NAME } from './strategiesNames';\n"
  },
  {
    "path": "packages/service/src/preview/strategies/strategiesNames.ts",
    "content": "export const ENV_PREVIEW_STRATEGY_NAME = 'env';\nexport const COMPONENT_PREVIEW_STRATEGY_NAME = 'component';\n"
  },
  {
    "path": "packages/service/src/preview/types/custom.d.ts",
    "content": "declare module '*.module.css' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\ndeclare module '*.module.scss' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\ndeclare module '*.module.sass' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.module.less' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.less' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.css' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.sass' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.scss' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.mdx' {\n  const component: any;\n  export default component;\n}\n"
  },
  {
    "path": "packages/service/src/preview/types/index.ts",
    "content": "export { PreviewType } from './previewType';\nexport { PreviewDefinition } from './previewDefinition';\nexport { PreviewModule, ModuleImportFunction } from './previewModule';\nexport {\n  RenderingContextOptions,\n  RenderingContextSlot,\n  RenderingContext,\n  RenderingContextProvider,\n} from './renderingContext';\n"
  },
  {
    "path": "packages/service/src/preview/types/previewDefinition.ts",
    "content": "import type { Component, ComponentMap } from '@arco-cli/aspect/dist/component';\nimport type { Environment } from '@arco-cli/aspect/dist/envs';\nimport type { AbstractVinyl } from '@arco-cli/legacy/dist/workspace/component/sources';\n\nexport interface PreviewDefinition {\n  /**\n   * extension preview prefix\n   */\n  prefix: string;\n\n  /**\n   * which other extension modules to include in the preview context.\n   */\n  include?: string[];\n\n  /**\n   * Whether to include the peers chunk in the output html\n   */\n  includePeers?: boolean;\n\n  /**\n   * path of the default template to be executed.\n   */\n  renderTemplatePath?: (env: Environment) => Promise<string>;\n\n  /**\n   * get all files to require in the preview runtime.\n   */\n  getModuleMap(\n    components: Component[]\n  ): Promise<ComponentMap<{ previews: AbstractVinyl[]; previewContextProvider?: AbstractVinyl }>>;\n\n  /**\n   * get all component metadata needed in the preview runtime.\n   */\n  getMetadataMap?(components: Component[], env: Environment): Promise<ComponentMap<unknown>>;\n}\n"
  },
  {
    "path": "packages/service/src/preview/types/previewModule.ts",
    "content": "/**\n * single preview module, e.g. compositions file\n */\nexport type ModuleImportFunction<T = any> = () => Promise<Record<string, T>>;\n\n/**\n * A full index of the preview data\n */\nexport type PreviewModule<T = any> = {\n  /**\n   * Dictionary mapping components to their module files.\n   */\n  componentMap: Record<string, ModuleImportFunction<T>[]>;\n\n  /**\n   * Dictionary mapping components to their preview metadata\n   */\n  componentMetadataMap: Record<string, unknown>;\n\n  /**\n   * Dictionary mapping components to their context-providers\n   */\n  componentContextProviderMap: Record<string, ModuleImportFunction<T>>;\n\n  /**\n   * The 'main file' for this Preview type\n   */\n  mainModule: {\n    default: {\n      (...args: any[]): void;\n      apiObject?: boolean;\n    };\n  };\n};\n"
  },
  {
    "path": "packages/service/src/preview/types/previewType.ts",
    "content": "import { RenderingContext } from './renderingContext';\nimport { PreviewModule } from './previewModule';\n\nexport interface PreviewType {\n  /**\n   * preview name to register.\n   */\n  name: string;\n\n  /**\n   * preview render method.\n   */\n  render(\n    componentId: string,\n    linkedModules: PreviewModule<any>,\n    includedPreviews: string[],\n    renderingContext: RenderingContext\n  ): Promise<void>;\n\n  /**\n   * determine if this will be the default preview to render.\n   */\n  default?: boolean;\n\n  /**\n   * which other extension modules to include in the preview context.\n   */\n  include?: string[];\n\n  /**\n   * select relevant information to show in preview context\n   */\n  selectPreviewModel?: (componentId: string, module: PreviewModule) => any;\n}\n"
  },
  {
    "path": "packages/service/src/preview/types/renderingContext.ts",
    "content": "import type { SlotRegistry } from '@arco-cli/stone';\n\nexport type RenderingContextOptions = { aspectsFilter?: string[] };\n\nexport type RenderingContextProvider = (options: RenderingContextOptions) => { [key: string]: any };\n\nexport type RenderingContextSlot = SlotRegistry<RenderingContextProvider>;\n\nexport class RenderingContext {\n  constructor(\n    private contexts: RenderingContextSlot,\n    private options: RenderingContextOptions = {}\n  ) {}\n\n  /**\n   * obtain rendering context of a specific aspect.\n   */\n  get(aspectId: string) {\n    const contextFactory = this.contexts.get(aspectId);\n    return contextFactory?.(this.options);\n  }\n}\n"
  },
  {
    "path": "packages/service/src/preview/uiRuntime/componentPreview.tsx",
    "content": "import React, { IframeHTMLAttributes, useContext } from 'react';\nimport { compact } from 'lodash';\nimport { ComponentModel } from '@arco-cli/aspect/dist/component/uiRuntime';\nimport { Overview } from '@arco-cli/workspace-materials';\nimport { WorkspaceContext } from '@arco-cli/ui-foundation-react';\n\nimport { toPreviewUrl } from './urls';\n\n// omitting 'referrerPolicy' because of an TS error during build. Re-include when needed\nexport interface ComponentPreviewProps\n  extends Omit<IframeHTMLAttributes<HTMLIFrameElement>, 'src' | 'referrerPolicy'> {\n  /**\n   * component to preview.\n   */\n  component: ComponentModel;\n\n  /**\n   * preview name.\n   */\n  previewName?: string;\n\n  /**\n   * query params to append at the end of the *hash*. Changing this property will not reload the preview\n   * e.g. 'foo=bar&bar=there', or ['foo=bar', 'bar=there']\n   */\n  queryParams?: string | string[];\n\n  /**\n   * viewport\n   */\n  viewport?: number | null;\n\n  /**\n   * extra stylesheet apply to iframe\n   */\n  extraStyle?: string;\n\n  /**\n   * is in dark mode\n   */\n  darkMode?: boolean;\n}\n\n/**\n * renders a preview of a component.\n */\nexport const ComponentPreview = function ({\n  component,\n  previewName,\n  queryParams,\n  viewport = 1280,\n  extraStyle,\n  darkMode,\n}: ComponentPreviewProps) {\n  const { overviewScrollContainerID } = useContext(WorkspaceContext);\n\n  const targetParams =\n    viewport === null\n      ? queryParams\n      : Array.isArray(queryParams)\n      ? queryParams.concat(`viewport=${viewport}`)\n      : compact([queryParams, `viewport=${viewport}`]);\n  const url = toPreviewUrl(component, previewName, targetParams);\n\n  return (\n    <Overview\n      src={url}\n      scrollContainer={`#${overviewScrollContainerID}`}\n      extraStyle={extraStyle}\n      darkMode={darkMode}\n      spinProps={{ tip: 'Loading...' }}\n      scrollContainerOffset={220}\n    />\n  );\n};\n"
  },
  {
    "path": "packages/service/src/preview/uiRuntime/index.ts",
    "content": "export { ComponentPreview } from './componentPreview';\nexport type { ComponentPreviewProps } from './componentPreview';\n"
  },
  {
    "path": "packages/service/src/preview/uiRuntime/urls.ts",
    "content": "import { ComponentModel } from '@arco-cli/aspect/dist/component/uiRuntime';\n\n/**\n * Optionally append prefix/postfix to a string.\n */\nfunction affix(prefix = '', str = '', suffix = '') {\n  if (!str) return '';\n  return `${prefix}${str}${suffix}`;\n}\n\n/**\n * creates component preview arguments\n */\nfunction toPreviewHash(\n  /**\n   * component to preview\n   */\n  component: ComponentModel,\n  /**\n   * current preview (docs, compositions, etc)\n   */\n  previewName?: string,\n  /**\n   * extra data to append to query\n   */\n  queryParams: string | string[] = ''\n) {\n  const previewParam = affix(`preview=`, previewName);\n  const hashQuery = [previewParam]\n    .concat(queryParams)\n    .filter((x) => !!x) // also removes empty strings\n    .join('&');\n  return `${component.id}${affix('?', hashQuery)}`;\n}\n\n/**\n * generates a full url to a preview (overview / docs etc)\n */\nexport function toPreviewUrl(\n  component: ComponentModel,\n  previewName?: string,\n  additionalParams?: string | string[]\n) {\n  const serverPath = component.server.url;\n  const hash = toPreviewHash(component, previewName, additionalParams);\n  return `${serverPath}#${hash}`;\n}\n"
  },
  {
    "path": "packages/service/src/preview/webpackEventsListener.ts",
    "content": "import {\n  WebpackAspect,\n  WebpackCompilationDoneEvent,\n  WebpackCompilationStartedEvent,\n} from '@arco-cli/aspect/dist/webpack';\nimport { PubsubMain, ArcoBaseEvent } from '@arco-cli/aspect/dist/pubsub';\n\nexport type CompilationResult = {\n  errors?: Error[];\n  warnings?: Error[];\n  compiling: boolean;\n};\n\nexport type Handlers = {\n  /**\n   * emitted when compilation completes. Might happen after server is already up and running.\n   */\n  onDone?: (serverId: string, stats: CompilationResult) => void;\n  /**\n   * happens whenever compilation starts, e.g. when a file changes, or on initial compilation\n   */\n  onStart?: (serverId: string) => void;\n};\n\n/**\n * Listen for Webpack compilation pub sub events.\n */\nexport function SubscribeToWebpackEvents(pubsub: PubsubMain, handlers: Handlers = {}) {\n  pubsub.sub(WebpackAspect.id, (event: ArcoBaseEvent<any>) => {\n    if (event instanceof WebpackCompilationDoneEvent) {\n      const { stats, devServerID } = event.data;\n\n      const results = {\n        errors: stats.compilation.errors,\n        warnings: stats.compilation.warnings,\n        compiling: false,\n      };\n\n      handlers.onDone?.(devServerID, results);\n    }\n\n    if (event instanceof WebpackCompilationStartedEvent) {\n      const { devServerID } = event.data;\n\n      handlers.onStart?.(devServerID);\n    }\n  });\n}\n"
  },
  {
    "path": "packages/service/src/syncer/index.ts",
    "content": "import { SyncerAspect } from './syncer.aspect';\n\nexport default SyncerAspect;\nexport { SyncerAspect };\nexport type { SyncerMain } from './syncer.main.runtime';\n"
  },
  {
    "path": "packages/service/src/syncer/sync.cmd.ts",
    "content": "import chalk from 'chalk';\nimport { Logger } from '@arco-cli/core/dist/logger';\nimport { Command, CommandOptions } from '@arco-cli/legacy/dist/cli/command';\nimport { CLI_COMPONENT_PATTERN_HELP, CLI_LOGIN_FIRST_TIP } from '@arco-cli/legacy/dist/constants';\nimport { Workspace } from '@arco-cli/aspect/dist/workspace';\nimport { WorkspaceNotFoundError } from '@arco-cli/aspect/dist/workspace/exceptions';\nimport ArcoError from '@arco-cli/legacy/dist/error/arcoError';\nimport { formatComponentResultError } from '@arco-cli/legacy/dist/workspace/componentResult';\nimport { checkUserLogin } from '@arco-cli/legacy/dist/cli/user';\n\nimport { SyncerMain } from './syncer.main.runtime';\n\ntype SyncOptions = {\n  skipArtifactsUpload?: boolean;\n  parallelTaskCount?: number;\n};\n\nexport class SyncCmd implements Command {\n  name = 'sync [component-pattern]';\n\n  description = 'sync components in the workspace to Arco material market';\n\n  arguments = [{ name: 'component-pattern', description: CLI_COMPONENT_PATTERN_HELP }];\n\n  alias = '';\n\n  group = 'collaborate';\n\n  options = [\n    ['', 'skipArtifactsUpload', 'skip uploading artifacts dir to file server'],\n    [\n      '',\n      'parallelTaskCount <parallel-task-count>',\n      'count of upload tasks executed in parallel (default to 10)',\n    ],\n  ] as CommandOptions;\n\n  constructor(private logger: Logger, private syncer: SyncerMain, private workspace: Workspace) {}\n\n  async report(\n    [pattern]: [string],\n    { skipArtifactsUpload, parallelTaskCount }: SyncOptions\n  ): Promise<string> {\n    if (!this.workspace) throw new WorkspaceNotFoundError();\n\n    const components = await this.workspace.getManyByPattern(pattern);\n    if (!components.length) {\n      return chalk.bold('no components found to sync');\n    }\n    this.logger.consoleSuccess(`found ${components.length} components to sync`);\n\n    const { loggedIn, user } = await checkUserLogin();\n    if (!loggedIn) {\n      return chalk.red(CLI_LOGIN_FIRST_TIP);\n    }\n\n    const results = await this.syncer.sync({\n      components,\n      currentUser: user.username,\n      skipArtifactsUpload,\n      parallelTaskCount: Number(parallelTaskCount) > 0 ? Number(parallelTaskCount) : 10,\n    });\n    const errorMsg = formatComponentResultError(results);\n\n    if (errorMsg) {\n      throw new ArcoError(errorMsg);\n    }\n\n    return chalk.green(`sync components completed. total: ${components.length} components`);\n  }\n}\n"
  },
  {
    "path": "packages/service/src/syncer/syncer.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const SyncerAspect = Aspect.create({\n  id: 'arco.service/syncer',\n});\n"
  },
  {
    "path": "packages/service/src/syncer/syncer.main.runtime.ts",
    "content": "import path from 'path';\nimport fs from 'fs-extra';\nimport { mergeWith } from 'lodash';\nimport { CLIAspect, CLIMain, MainRuntime } from '@arco-cli/core/dist/cli';\nimport { LoggerAspect, LoggerMain, Logger } from '@arco-cli/core/dist/logger';\nimport { WorkspaceAspect, Workspace } from '@arco-cli/aspect/dist/workspace';\nimport { Doc, DocsAspect, DocsMain } from '@arco-cli/aspect/dist/docs';\nimport { Component } from '@arco-cli/aspect/dist/component';\nimport request from '@arco-cli/legacy/dist/cli/request';\nimport { uploadFile } from '@arco-cli/legacy/dist/cli/uploadFile';\nimport type { ComponentResult } from '@arco-cli/legacy/dist/workspace/componentResult';\nimport {\n  DEFAULT_MATERIAL_GROUP_ID,\n  MATERIAL_GENERATION,\n  DIR_ARTIFACTS,\n  DIR_SOURCE,\n  PACKAGE_JSON,\n  CFG_HOST_ARCO_KEY,\n} from '@arco-cli/legacy/dist/constants';\nimport { toFsCompatible, TaskManager } from '@arco-cli/legacy/dist/utils';\nimport { zipFiles } from '@arco-cli/legacy/dist/utils/fs/zipFiles';\nimport { getSync } from '@arco-cli/legacy/dist/globalConfig';\nimport { toComponentForkConfigFilename } from '@arco-cli/legacy/dist/workspace/componentIdTo';\n\nimport { SyncerAspect } from './syncer.aspect';\nimport { SyncCmd } from './sync.cmd';\nimport { SyncParams } from './type/syncParams';\n\ntype SyncerConfig = {\n  defaultMaterialMeta: {\n    group?: number;\n    author?: string;\n    repository?: string;\n  };\n};\n\nexport class SyncerMain {\n  static runtime = MainRuntime;\n\n  static dependencies = [LoggerAspect, CLIAspect, WorkspaceAspect, DocsAspect];\n\n  static provider(\n    [loggerMain, cli, workspace, docs]: [LoggerMain, CLIMain, Workspace, DocsMain],\n    config\n  ) {\n    const logger = loggerMain.createLogger(SyncerAspect.id);\n    const syncer = new SyncerMain(config, logger, docs, workspace);\n    cli.register(new SyncCmd(logger, syncer, workspace));\n    return syncer;\n  }\n\n  constructor(\n    private config: SyncerConfig,\n    private logger: Logger,\n    private docs: DocsMain,\n    private workspace: Workspace\n  ) {}\n\n  private copingFilePaths: string[] = [];\n\n  private getCacheDir() {\n    return this.workspace.getCacheDir(SyncerAspect.id);\n  }\n\n  private getTempDirToUpload(component: Component) {\n    return path.join(this.getCacheDir(), toFsCompatible(component.packageName));\n  }\n\n  private async copyIfNotExist(src: string, dest: string) {\n    if (!fs.existsSync(dest) && this.copingFilePaths.indexOf(dest) === -1) {\n      this.copingFilePaths.push(dest);\n      await fs.copy(src, dest);\n      this.copingFilePaths = this.copingFilePaths.filter((filePath) => filePath !== dest);\n    }\n  }\n\n  private extendSyncParamsWithDefaultMaterialMeta(params: SyncParams) {\n    const { defaultMaterialMeta = {} } = this.config;\n    defaultMaterialMeta.group ||= DEFAULT_MATERIAL_GROUP_ID;\n    mergeWith(params, defaultMaterialMeta, (paramValue, defaultValue) => {\n      return paramValue === undefined ? defaultValue : paramValue;\n    });\n  }\n\n  private async preparePackageFilesToUpload(component: Component) {\n    const tempDir = this.getTempDirToUpload(component);\n    const artifactsDir = path.join(component.packageDirAbs, DIR_ARTIFACTS);\n\n    await fs.ensureDir(tempDir);\n    await this.copyIfNotExist(\n      path.join(component.packageDirAbs, PACKAGE_JSON),\n      path.join(tempDir, PACKAGE_JSON)\n    );\n    await this.copyIfNotExist(artifactsDir, path.join(tempDir, DIR_ARTIFACTS));\n\n    // prepare files which are needed by forking\n    if (component.forkable) {\n      // user has specified which files are belong to this component\n      if (typeof component.forkable === 'object' && Array.isArray(component.forkable.sources)) {\n        // copy component source files to temp dir\n        await Promise.all(\n          component.forkable.sources.map((sourceDir) =>\n            // keep its origin directory name after copied to dest dir\n            this.copyIfNotExist(\n              path.join(this.workspace.path, component.rootDir, sourceDir),\n              path.join(tempDir, DIR_SOURCE, sourceDir)\n            )\n          )\n        );\n      } else {\n        // copy all package source files to dest dir\n        await this.copyIfNotExist(\n          path.join(this.workspace.path, component.rootDir),\n          path.join(tempDir, DIR_SOURCE)\n        );\n      }\n\n      // write component fork config\n      await fs.writeJSON(\n        path.join(tempDir, DIR_SOURCE, toComponentForkConfigFilename(component.id)),\n        {\n          [WorkspaceAspect.id]: {\n            component: component.rawConfig,\n          },\n        },\n        {\n          spaces: 2,\n        }\n      );\n    }\n  }\n\n  private async uploadPackageFiles(components: Component[], parallelTaskCount: number) {\n    const uploadResults: Record<\n      string,\n      {\n        data?: {\n          zip: string;\n          files: Record<string, string>;\n        };\n        errors: string[];\n      }\n    > = {};\n    const cacheDir = this.getCacheDir();\n    const packagesUploading: string[] = [];\n\n    // clear cache dir at first\n    await fs.emptyDir(cacheDir);\n\n    // prepare all component files to upload before uploading\n    // because we only upload once if components come from the same package\n    await Promise.all(components.map(this.preparePackageFilesToUpload.bind(this)));\n\n    // upload all artifacts files\n    await new TaskManager({\n      parallelTaskCount,\n      tasks: components.map((component) => {\n        return async () => {\n          const { packageName } = component;\n          uploadResults[packageName] ||= { errors: [] };\n\n          // components may come from the same package, upload the package files only once\n          if (packagesUploading.indexOf(packageName) === -1) {\n            packagesUploading.push(packageName);\n\n            const pathOfDirToUpload = this.getTempDirToUpload(component);\n            const pathOfZipToUpload = `${pathOfDirToUpload}.zip`;\n\n            let error = null;\n            const longProcessLogger = this.logger.createLongProcessLogger(\n              `upload artifacts of ${packageName} to material market`\n            );\n\n            try {\n              await zipFiles({\n                sourceDir: pathOfDirToUpload,\n                targetPath: pathOfZipToUpload,\n              });\n            } catch (err) {\n              error = err.toString();\n            }\n\n            if (fs.existsSync(pathOfZipToUpload)) {\n              const { code, data, msg } = await uploadFile({\n                filePath: pathOfZipToUpload,\n                cdnGlobs: [`${DIR_ARTIFACTS}/**/*.*`],\n              });\n              if (code === 0) {\n                uploadResults[packageName].data = data;\n              } else {\n                error = msg;\n              }\n            }\n\n            longProcessLogger.end();\n\n            if (error) {\n              uploadResults[packageName].errors.push(error);\n              this.logger.consoleFailure();\n            } else {\n              this.logger.consoleSuccess();\n            }\n          }\n        };\n      }),\n    }).runAll();\n\n    return uploadResults;\n  }\n\n  async sync({\n    components,\n    currentUser,\n    parallelTaskCount,\n    skipArtifactsUpload,\n  }: {\n    components: Component[];\n    currentUser: string;\n    parallelTaskCount: number;\n    skipArtifactsUpload?: boolean;\n  }): Promise<ComponentResult[]> {\n    const hostArco = getSync(CFG_HOST_ARCO_KEY);\n    const syncResults: ComponentResult[] = [];\n    const uploadResultMap = skipArtifactsUpload\n      ? {}\n      : await this.uploadPackageFiles(components, parallelTaskCount);\n\n    await new TaskManager({\n      parallelTaskCount,\n      tasks: components.map((component) => {\n        return async () => {\n          const uploadResult = uploadResultMap[component.packageName] || { errors: [] };\n          const syncResult: ComponentResult = {\n            id: component.id,\n            errors: uploadResult.errors.slice() || [],\n          };\n          const doc = this.docs.getDoc(component);\n          const docManifest = await this.docs.getDocsManifestFromArtifact(component);\n\n          const pickComponentFileCDNInfo = () => {\n            const result: any = {};\n            const keyword = toFsCompatible(component.id);\n\n            if (uploadResult.data) {\n              result.zip = uploadResult.data.zip;\n              result.files = {};\n\n              Object.entries(uploadResult.data.files || {}).forEach(([filePath, url]) => {\n                // many components may come from the same package\n                // we should only sync file info for the current component, otherwise the data size will be too large\n                if (filePath.indexOf(keyword) > -1) {\n                  result.files[filePath] = url;\n                }\n              });\n            }\n\n            return result;\n          };\n\n          const meta: SyncParams = {\n            name: component.id,\n            title: doc.title || component.name,\n            description: doc.description,\n            category: Doc.mergeDocProperty(doc.labels || [], component.labels),\n            repository: component.repository,\n            uiResource: component.uiResource,\n            group: component.group,\n            author: component.author || currentUser,\n            package: {\n              name: component.packageName,\n              version: component.version,\n              peerDependencies: Object.keys(component.peerDependencies),\n            },\n            outline: doc.outline,\n            fileManifest: {\n              extraStyle: component.extraStyles,\n              docs: docManifest.extraDocs,\n              cdn: pickComponentFileCDNInfo(),\n            },\n            forkable: !!component.forkable,\n            _generation: MATERIAL_GENERATION,\n          };\n\n          this.extendSyncParamsWithDefaultMaterialMeta(meta);\n\n          let error = null;\n          const longProcessLogger = this.logger.createLongProcessLogger(\n            `sync metadata of ${component.id} to material market`\n          );\n\n          try {\n            const { ok, msg } = await request.post('material/update', {\n              meta,\n              createIfNotExists: true,\n            });\n            if (!ok) {\n              error = msg;\n            }\n          } catch (err) {\n            error = err.toString();\n          }\n\n          longProcessLogger.end();\n\n          if (error) {\n            syncResult.errors.push(error);\n            this.logger.consoleFailure();\n          } else {\n            this.logger.consoleSuccess(\n              `${component.id} has successfully synced to https://${hostArco}/material/detail?name=${component.id}`\n            );\n          }\n\n          syncResults.push(syncResult);\n        };\n      }),\n    }).runAll();\n\n    return syncResults;\n  }\n}\n\nSyncerAspect.addRuntime(SyncerMain);\n"
  },
  {
    "path": "packages/service/src/syncer/type/syncParams.ts",
    "content": "export type SyncParams = {\n  name: string;\n  title: string;\n  description?: string;\n  category?: string[];\n  repository?: string;\n  uiResource?: string;\n  group: number;\n  author: string;\n  forkable?: boolean;\n  package: {\n    name: string;\n    version: string;\n    peerDependencies: string[];\n  };\n  outline?: Array<{ depth: number; text: string }>;\n  fileManifest?: Record<string, any>;\n  _generation: 2;\n};\n"
  },
  {
    "path": "packages/service/src/tester/index.ts",
    "content": "import { TesterAspect } from './tester.aspect';\n\nexport default TesterAspect;\nexport { TesterAspect };\nexport { TesterMain } from './tester.main.runtime';\nexport { Tester, TesterContext, Tests } from './tester';\n"
  },
  {
    "path": "packages/service/src/tester/test.cmd.tsx",
    "content": "import React, { ReactElement } from 'react';\nimport { Box, Text, render } from 'ink';\nimport { Logger } from '@arco-cli/core/dist/logger';\nimport { Command, CommandOptions } from '@arco-cli/legacy/dist/cli/command';\nimport { Timer } from '@arco-cli/legacy/dist/utils/timer';\nimport { Workspace } from '@arco-cli/aspect/dist/workspace';\nimport { CLI_COMPONENT_PATTERN_HELP } from '@arco-cli/legacy/dist/constants';\nimport { TesterMain } from './tester.main.runtime';\nimport { TesterOptions } from './tester';\n\ntype TestFlags = Pick<TesterOptions, 'watch' | 'rawTesterArgs'>;\n\nexport class TestCmd implements Command {\n  name = 'test [component-pattern]';\n\n  arguments = [{ name: 'component-pattern', description: CLI_COMPONENT_PATTERN_HELP }];\n\n  description = 'test components in the workspace';\n\n  alias = 'at';\n\n  group = 'development';\n\n  options = [\n    ['w', 'watch', 'start the tester in watch mode.'],\n    [\n      '',\n      'rawTesterArgs [args]',\n      'specify the arguments for raw tester, e.g. \"jest -u --cache=false\"',\n    ],\n  ] as CommandOptions;\n\n  constructor(private tester: TesterMain, private logger: Logger, private workspace: Workspace) {}\n\n  inkRender(element: ReactElement) {\n    return render(element);\n  }\n\n  async render([pattern]: [string], { watch, rawTesterArgs }: TestFlags) {\n    this.logger.console(`testing components in workspace in workspace`);\n\n    const timer = Timer.create();\n    timer.start();\n    const components = await this.workspace.getManyByPattern(pattern);\n    this.logger.consoleSuccess(`found ${components.length} components to test`);\n    if (!components.length) {\n      return {\n        code: 1,\n        data: <Text color=\"yellow\">no components found to test</Text>,\n      };\n    }\n\n    const testResults = await this.tester.test(components, { watch, rawTesterArgs, pattern });\n    const code = testResults.hasErrors() ? 1 : 0;\n    const { seconds } = timer.stop();\n\n    return {\n      code,\n      data: (\n        <Box>\n          <Text>Test has been completed in </Text>\n          <Text color=\"cyan\">{seconds}</Text>\n          <Text> seconds.</Text>\n        </Box>\n      ),\n    };\n  }\n}\n"
  },
  {
    "path": "packages/service/src/tester/tester.aspect.ts",
    "content": "import { Aspect } from '@arco-cli/stone';\n\nexport const TesterAspect = Aspect.create({\n  id: 'arco.service/tester',\n});\n\nexport default TesterAspect;\n"
  },
  {
    "path": "packages/service/src/tester/tester.main.runtime.ts",
    "content": "import { LoggerAspect, LoggerMain } from '@arco-cli/core/dist/logger';\nimport { CLIAspect, CLIMain, MainRuntime } from '@arco-cli/core/dist/cli';\nimport { Component } from '@arco-cli/aspect/dist/component';\nimport { EnvsAspect, EnvsMain, EnvsExecutionResult } from '@arco-cli/aspect/dist/envs';\nimport { Workspace, WorkspaceAspect } from '@arco-cli/aspect/dist/workspace';\nimport { Tests } from './tester';\nimport { TestCmd } from './test.cmd';\nimport TesterAspect from './tester.aspect';\nimport { TesterOptions, TesterService } from './tester.service';\n\nexport class TesterMain {\n  static runtime = MainRuntime;\n\n  static dependencies = [CLIAspect, EnvsAspect, LoggerAspect, WorkspaceAspect];\n\n  static slots = [];\n\n  static provider([cli, envs, loggerMain, workspace]: [CLIMain, EnvsMain, LoggerMain, Workspace]) {\n    const logger = loggerMain.createLogger(TesterAspect.id);\n    const testerService = new TesterService(logger, workspace);\n    const tester = new TesterMain(envs, testerService);\n    cli.register(new TestCmd(tester, logger, workspace));\n    return tester;\n  }\n\n  constructor(private envs: EnvsMain, private service: TesterService) {}\n\n  private getOptions(options?: TesterOptions): TesterOptions {\n    const defaults: TesterOptions = {\n      watch: false,\n    };\n\n    return { ...defaults, ...options };\n  }\n\n  async test(components: Component[], opts?: TesterOptions): Promise<EnvsExecutionResult<Tests>> {\n    const options = this.getOptions(opts);\n    const envsRuntime = await this.envs.createEnvironment(components);\n    const result = await envsRuntime.run(this.service, options);\n    return result;\n  }\n}\n\nTesterAspect.addRuntime(TesterMain);\n"
  },
  {
    "path": "packages/service/src/tester/tester.service.tsx",
    "content": "import chalk from 'chalk';\nimport { Logger } from '@arco-cli/core/dist/logger';\nimport { Workspace } from '@arco-cli/aspect/dist/workspace';\nimport { EnvService, ExecutionContext, EnvDefinition } from '@arco-cli/aspect/dist/envs';\nimport { Tester, Tests, TesterOptions } from './tester';\n\nexport { TesterOptions };\n\nexport type TesterDescriptor = {\n  /**\n   * id of the tester (e.g. jest/mocha)\n   */\n  id: string;\n\n  /**\n   * display name of the tester (e.g. Jest / Mocha)\n   */\n  displayName: string;\n\n  /**\n   * string containing the config for display.\n   */\n  config: string;\n\n  version?: string;\n};\n\nexport class TesterService implements EnvService<Tests, TesterDescriptor> {\n  name = 'tester';\n\n  constructor(private logger: Logger, private workspace: Workspace) {}\n\n  getDescriptor(environment: EnvDefinition) {\n    if (!environment.env.getTester) return null;\n    const tester: Tester = environment.env.getTester();\n    return {\n      id: tester.id || '',\n      displayName: tester.displayName || '',\n      config: tester.displayConfig ? tester.displayConfig() : '',\n      version: tester.version ? tester.version() : '?',\n    };\n  }\n\n  async run(context: ExecutionContext, options: TesterOptions) {\n    this.logger.console(`testing components with environment ${chalk.cyan(context.id)}\\n`);\n    const tester: Tester = context.env.getTester();\n    const results = await tester.test(\n      Object.assign(context, {\n        rootPath: this.workspace.path,\n        ...options,\n      })\n    );\n    return results;\n  }\n}\n"
  },
  {
    "path": "packages/service/src/tester/tester.ts",
    "content": "import { ExecutionContext } from '@arco-cli/aspect/dist/envs';\nimport { ComponentResult } from '@arco-cli/legacy/dist/workspace/componentResult';\n\nexport class Tests {\n  constructor(public componentResults: ComponentResult[]) {}\n\n  get errors(): Array<string | Error> {\n    return this.componentResults.map((comp) => comp.errors).flat(1);\n  }\n}\n\nexport interface TesterOptions {\n  /**\n   * determines whether to start the tester in watch mode.\n   */\n  watch?: boolean;\n\n  /**\n   * pass the raw tester cli options, e.g. \"$jest: -u --testMatch=['test.js']\";\n   */\n  rawTesterArgs?: string;\n\n  /**\n   * component pattern passed via 'arco test component-pattern'\n   */\n  pattern?: string;\n}\n\nexport interface TesterContext extends ExecutionContext, TesterOptions {\n  /**\n   * rootPath of the component workspace\n   */\n  rootPath: string;\n}\n\n/**\n * tester interface allows extensions to implement a component tester\n */\nexport interface Tester {\n  /**\n   * id of the tester.\n   */\n  id: string;\n\n  /**\n   * display name of the tester.\n   */\n  displayName?: string;\n\n  /**\n   * serialized config of the tester.\n   */\n  displayConfig?(): string;\n\n  /**\n   * return the tester version.\n   */\n  version(): string;\n\n  /**\n   * path to the config in the filesystem.\n   */\n  configPath?: string;\n\n  /**\n   * execute tests on all components in the given execution context.\n   */\n  test(context: TesterContext): Promise<Tests>;\n\n  /**\n   * on test run complete. (applies only during watch)\n   * @param callback\n   */\n  onTestRunComplete?(callback: () => void): Promise<void>;\n}\n"
  },
  {
    "path": "packages/service/src/ui/cli/time.tsx",
    "content": "import React from 'react';\nimport { Text } from 'ink';\n\nexport type TimeProps = {\n  /**\n   * time to render.\n   */\n  time?: Date;\n};\n\nexport function Time(props: TimeProps) {\n  const { time } = props;\n  return <Text>{time.toLocaleTimeString()}</Text>;\n}\n"
  },
  {
    "path": "packages/service/src/ui/cli/uiServerConsole.tsx",
    "content": "import React, { ComponentType, useEffect, useState } from 'react';\nimport { Text, Newline } from 'ink';\nimport { UIServerLoader } from './uiServerLoader';\nimport type { UIServer } from '../uiServer';\n\nexport type UIServerConsoleProps = {\n  /**\n   * future of the ui server.\n   */\n  futureUiServer: Promise<UIServer>;\n\n  /**\n   * name of the app.\n   */\n  appName?: string;\n\n  /**\n   * explicit server url\n   */\n  url?: string;\n};\n\nexport function UIServerConsole({ appName, futureUiServer, url }: UIServerConsoleProps) {\n  const [uiServer, setUiServer] = useState<UIServer>();\n  const [plugins, setPlugins] = useState<ComponentType[]>();\n\n  useEffect(() => {\n    futureUiServer\n      .then((server) => {\n        setUiServer(server);\n        setPlugins(server.getPluginsComponents());\n      })\n      .catch((err) => {\n        throw err;\n      });\n  }, []);\n\n  if (!uiServer) return <UIServerLoader name={appName} />;\n\n  return (\n    <>\n      {plugins?.map((Plugin, key) => {\n        return <Plugin key={key} />;\n      })}\n      <Newline />\n      <Text>\n        You can now view [<Text color=\"cyan\">{uiServer?.getName()}</Text>] components in the\n        browser.\n      </Text>\n      <Text>Arco dev server is running on {url || uiServer.fullUrl}</Text>\n    </>\n  );\n}\n"
  },
  {
    "path": "packages/service/src/ui/cli/uiServerLoader.tsx",
    "content": "import React from 'react';\nimport { Box, Text } from 'ink';\nimport Spinner from 'ink-spinner';\n\nexport type UIServerLoaderProps = {\n  /**\n   * name of the ui root.\n   */\n  name?: string;\n};\n\nexport function UIServerLoader({ name }: UIServerLoaderProps) {\n  return (\n    <Box paddingTop={1}>\n      <Text>\n        <Text color=\"green\">\n          <Spinner type=\"dots\" />\n        </Text>{' '}\n        Starting UI servers\n        {name && (\n          <>\n            {' '}\n            for [<Text color=\"cyan\">{name}</Text>]\n          </>\n        )}\n        ...\n      </Text>\n    </Box>\n  );\n}\n"
  },
  {
    "path": "packages/service/src/ui/createRoot.ts",
    "content": "import { parse } from 'path';\nimport { camelCase } from 'lodash';\nimport { AspectDefinition } from '@arco-cli/core/dist/aspect-loader';\nimport { toWindowsCompatiblePath } from '@arco-cli/legacy/dist/utils/path';\nimport { UIAspect } from './ui.aspect';\n\nexport type CreateRootOptions = {\n  aspectDefs: AspectDefinition[];\n  config?: object;\n  runtimeName?: string;\n  rootAspect?: string;\n  rootExtensionName?: string;\n};\n\nexport async function createRoot({\n  aspectDefs,\n  rootExtensionName,\n  rootAspect = UIAspect.id,\n  runtimeName = 'ui',\n  config = {},\n}: CreateRootOptions) {\n  const rootId = rootExtensionName ? `'${rootExtensionName}'` : '';\n  const identifiers = getIdentifiers(aspectDefs, 'Aspect');\n  const idSetters = getIdSetters(aspectDefs, 'Aspect');\n\n  config['arco.app/arco'] = rootExtensionName;\n\n  // Escaping \"'\" in case for example in the config you have something like:\n  // description: \"team's scope\"\n  const stringifiedConfig = toWindowsCompatiblePath(JSON.stringify(config)).replace(/'/g, \"\\\\'\");\n\n  return `\n${createImports(aspectDefs)}\n\nconst config = JSON.parse('${stringifiedConfig}');\n\n${idSetters.join('\\n')}\n\nexport default function render(...props){\n  return Stone.load([${identifiers.join(', ')}], '${runtimeName}', config)\n    .then((stone) => {\n      return stone\n      .run()\n      .then(() => stone.get('${rootAspect}'))\n      .then((rootExtension) => {\n        return rootExtension.render(${rootId}, ...props);\n      })\n      .catch((err) => {\n        throw err;\n      });\n    });\n}\n\nrender();\n`;\n}\n\nfunction createImports(aspectDefs: AspectDefinition[]) {\n  const defs = aspectDefs.filter((def) => def.runtimePath);\n\n  return `import { Stone } from '@arco-cli/stone';\n${getImportStatements(aspectDefs, 'aspectPath', 'Aspect')}\n${getImportStatements(defs, 'runtimePath', 'Runtime')}`;\n}\n\nfunction getImportStatements(\n  aspectDefs: AspectDefinition[],\n  pathProp: string,\n  suffix: string\n): string {\n  return aspectDefs\n    .map(\n      (aspectDef) =>\n        `import ${getIdentifier(aspectDef, suffix)} from '${toWindowsCompatiblePath(\n          aspectDef[pathProp]\n        )}';`\n    )\n    .join('\\n');\n}\n\nfunction getIdentifiers(aspectDefs: AspectDefinition[], suffix: string): string[] {\n  return aspectDefs.map((aspectDef) => `${getIdentifier(aspectDef, suffix)}`);\n}\n\nfunction getIdSetters(defs: AspectDefinition[], suffix: string) {\n  return defs\n    .map((def) => def.id && `${getIdentifier(def, suffix)}.id = '${def.id}';`)\n    .filter((val) => !!val);\n}\n\nfunction getIdentifier(aspectDef: AspectDefinition, suffix: string): string {\n  if (!aspectDef.local) {\n    return getCoreIdentifier(aspectDef.aspectPath, suffix);\n  }\n  return getRegularAspectIdentifier(aspectDef, suffix);\n}\n\nfunction getRegularAspectIdentifier(aspectDef: AspectDefinition, suffix: string): string {\n  return camelCase(\n    `${parse(aspectDef.aspectPath).base.replace(/\\./, '__').replace('@', '__')}${suffix}`\n  );\n}\n\nfunction getCoreIdentifier(path: string, suffix: string): string {\n  return camelCase(`${parse(path).name.split('.')[0]}${suffix}`);\n}\n"
  },
  {
    "path": "packages/service/src/ui/exceptions/index.ts",
    "content": "export { UnknownUIError } from './unknownUIError';\n"
  },
  {
    "path": "packages/service/src/ui/exceptions/unknownUIError.ts",
    "content": "export class UnknownUIError extends Error {\n  constructor(readonly uiRoot: string = '', readonly available?: string[]) {\n    super();\n  }\n\n  toString() {\n    return `Unknown UI root: \"${this.uiRoot}\". Available ui roots are: [${this.available?.join(\n      ', '\n    )}]`;\n  }\n}\n"
  },
  {
    "path": "packages/service/src/ui/index.ts",
    "content": "import { UIAspect } from './ui.aspect';\n\nexport default UIAspect;\nexport { UIAspect };\nexport { UIRuntime } from './ui.aspect';\nexport type { UIMain } from './ui.main.runtime';\nexport type { UIRoot, ProxyEntry } from './uiRoot';\nexport type { StartPlugin, StartPluginOptions } from './startPlugin';\n"
  },
  {
    "path": "packages/service/src/ui/start.cmd.tsx",
    "content": "import React, { ReactElement } from 'react';\nimport { render } from 'ink';\nimport { Logger } from '@arco-cli/core/dist/logger';\nimport { Command, CommandOptions } from '@arco-cli/legacy/dist/cli/command';\nimport { CLI_COMPONENT_PATTERN_HELP } from '@arco-cli/legacy/dist/constants';\n\nimport { UIServerConsole } from './cli/uiServerConsole';\nimport type { UIMain } from './ui.main.runtime';\n\ntype StartFlags = {\n  port: string;\n  noBrowser: boolean;\n};\n\nexport class StartCmd implements Command {\n  name = 'start [component-pattern]';\n\n  description = 'run the development server';\n\n  arguments = [{ name: 'component-pattern', description: CLI_COMPONENT_PATTERN_HELP }];\n\n  alias = 'c';\n\n  group = 'development';\n\n  options = [['p', 'port [port-number]', 'port of the UI server']] as CommandOptions;\n\n  constructor(\n    /**\n     * access to the extension instance.\n     */\n    private ui: UIMain,\n\n    private logger: Logger\n  ) {}\n\n  inkRender(element: ReactElement) {\n    return render(element);\n  }\n\n  async render([pattern]: [string], { port }: StartFlags): Promise<React.ReactElement> {\n    this.logger.off();\n\n    const uiServer = this.ui.createRuntime({\n      port: +port,\n      pattern,\n    });\n\n    this.logger.clearConsole();\n\n    return <UIServerConsole futureUiServer={uiServer} url={this.ui.publicUrl} />;\n  }\n}\n"
  },
  {
    "path": "packages/service/src/ui/startPlugin.ts",
    "content": "import type { ComponentType } from 'react';\nimport type { ProxyEntry } from './uiRoot';\n\nexport type StartPluginOptions = {\n  /**\n   * indicates whether the start in on verbose mode.\n   */\n  verbose?: boolean;\n\n  /**\n   * component pattern it applies on.\n   */\n  pattern?: string;\n};\n\nexport interface StartPlugin {\n  initiate(startOptions: StartPluginOptions): void;\n\n  getProxy?(): ProxyEntry[];\n\n  render: ComponentType;\n\n  /** promise that resolves when the plugin completed initiation */\n  readonly whenReady: Promise<void>;\n}\n"
  },
  {
    "path": "packages/service/src/ui/ui.aspect.ts",
    "content": "import { Aspect, RuntimeDefinition } from '@arco-cli/stone';\n\nexport const UIRuntime = new RuntimeDefinition('ui');\n\nexport const UIAspect = Aspect.create({\n  id: 'arco.service/ui',\n  declareRuntime: UIRuntime,\n});\n\nexport default UIAspect;\n"
  },
  {
    "path": "packages/service/src/ui/ui.main.runtime.ts",
    "content": "import fs from 'fs-extra';\nimport { join, resolve } from 'path';\nimport pMapSeries from 'p-map-series';\nimport { Slot, SlotRegistry, Stone } from '@arco-cli/stone';\nimport { MainRuntime, CLIAspect, CLIMain } from '@arco-cli/core/dist/cli';\nimport { Logger, LoggerAspect, LoggerMain } from '@arco-cli/core/dist/logger';\nimport { sha1 } from '@arco-cli/legacy/dist/utils';\nimport { GraphqlAspect, GraphqlMain } from '@arco-cli/core/dist/graphql';\nimport { ExpressAspect, ExpressMain } from '@arco-cli/core/dist/express';\n\nimport UIAspect, { UIRuntime } from './ui.aspect';\nimport { StartCmd } from './start.cmd';\nimport { UIServer } from './uiServer';\nimport { UIRoot } from './uiRoot';\nimport { UnknownUIError } from './exceptions';\nimport { createRoot, CreateRootOptions } from './createRoot';\nimport { StartPlugin, StartPluginOptions } from './startPlugin';\n\ntype UIDeps = [GraphqlMain, ExpressMain, CLIMain, LoggerMain];\n\ntype UIRootSlot = SlotRegistry<UIRoot>;\n\ntype StartPluginSlot = SlotRegistry<StartPlugin>;\n\nexport type UIConfig = {\n  /**\n   * port for the UI root to use.\n   */\n  port?: number;\n\n  /**\n   * port range for the UI root to use.\n   */\n  portRange: [number, number];\n\n  /**\n   * host for the UI root\n   */\n  host: string;\n\n  /**\n   * directory in workspace to use for public assets.\n   * always relative to the workspace root directory.\n   */\n  publicDir: string;\n\n  /**\n   * the url to display when server is listening\n   */\n  publicUrl?: string;\n};\n\nexport type RuntimeOptions = {\n  /**\n   * port of the config.\n   */\n  port?: number;\n\n  /**\n   * determine whether to initiate on verbose mode.\n   */\n  verbose?: boolean;\n\n  /**\n   * name of the UI root to load.\n   */\n  uiRootName?: string;\n\n  /**\n   * component selector pattern to load.\n   */\n  pattern?: string;\n};\n\nexport class UIMain {\n  static dependencies = [GraphqlAspect, ExpressAspect, CLIAspect, LoggerAspect];\n\n  static slots = [Slot.withType<UIRoot>(), Slot.withType<StartPlugin>()];\n\n  static runtime = MainRuntime;\n\n  static provider(\n    [graphql, express, cli, loggerMain]: UIDeps,\n    config,\n    [uiRootSlot, startPluginSlot]: [UIRootSlot, StartPluginSlot],\n    stone\n  ) {\n    const logger = loggerMain.createLogger(UIAspect.id);\n    const ui = new UIMain(graphql, express, config, logger, stone, uiRootSlot, startPluginSlot);\n    cli.register(new StartCmd(ui, logger));\n    return ui;\n  }\n\n  constructor(\n    private graphql: GraphqlMain,\n    private express: ExpressMain,\n    private config: UIConfig,\n    private logger: Logger,\n    private stone: Stone,\n    private uiRootSlot: UIRootSlot,\n    private startPluginSlot: StartPluginSlot\n  ) {}\n\n  get publicUrl() {\n    return this.config.publicUrl;\n  }\n\n  private addSignalListener() {\n    process.on('SIGTERM', () => {\n      process.exit();\n    });\n\n    process.on('SIGINT', () => {\n      process.exit();\n    });\n  }\n\n  private async initiateStartPlugins(options: StartPluginOptions) {\n    const plugins = this.startPluginSlot.values();\n    await pMapSeries(plugins, (plugin) => plugin.initiate(options));\n    return plugins;\n  }\n\n  registerUiRoot(uiRoot: UIRoot) {\n    return this.uiRootSlot.register(uiRoot);\n  }\n\n  registerStartPlugin(startPlugin: StartPlugin) {\n    this.startPluginSlot.register(startPlugin);\n    return this;\n  }\n\n  getUi(uiRootName?: string): [string, UIRoot] | undefined {\n    if (uiRootName) {\n      const root = this.uiRootSlot.get(uiRootName);\n      return root ? [uiRootName, root] : undefined;\n    }\n    const uis = this.uiRootSlot.toArray();\n    return uis[0];\n  }\n\n  async generateRoot({\n    path,\n    aspectDefs,\n    runtimeName = UIRuntime.name,\n    rootAspect = UIAspect.id,\n    rootExtensionName,\n    config = this.stone.config.toObject(),\n  }: { path?: string } & CreateRootOptions) {\n    const contents = await createRoot({\n      aspectDefs,\n      runtimeName,\n      rootAspect,\n      rootExtensionName,\n      config,\n    });\n    const filePath = resolve(join(path || __dirname, `${runtimeName}.root${sha1(contents)}.js`));\n    if (!fs.existsSync(filePath)) {\n      fs.outputFileSync(filePath, contents);\n    }\n    return filePath;\n  }\n\n  async createRuntime({ port, uiRootName, verbose, pattern }: RuntimeOptions) {\n    const maybeUIRoot = this.getUi(uiRootName);\n    if (!maybeUIRoot) throw new UnknownUIError(uiRootName);\n\n    const startPlugins = await this.initiateStartPlugins({\n      verbose,\n      pattern,\n    });\n\n    const [name, uiRoot] = maybeUIRoot || [];\n    const uiServer = UIServer.create({\n      graphql: this.graphql,\n      express: this.express,\n      logger: this.logger,\n      ui: this,\n      uiRoot,\n      uiRootExtension: name,\n      startPlugins,\n    });\n    // Adding signal listeners to make sure we immediately close the process on sigint / sigterm (otherwise webpack dev server closing will take time)\n    this.addSignalListener();\n    await uiServer.dev({ portRange: port || this.config.portRange });\n    return uiServer;\n  }\n}\n\nUIAspect.addRuntime(UIMain);\n"
  },
  {
    "path": "packages/service/src/ui/uiRoot.ts",
    "content": "import { ProxyConfigArrayItem } from 'webpack-dev-server';\nimport { AspectDefinition } from '@arco-cli/core/dist/aspect-loader';\n\nexport type ProxyEntry = ProxyConfigArrayItem & {\n  context: string[];\n};\n\nexport interface UIRoot {\n  /**\n   * unique name of the ui.\n   */\n  name: string;\n\n  /**\n   * path of the ui root.\n   */\n  path: string;\n\n  /**\n   * name of the UI root config file.\n   */\n  // configFile: string;\n\n  /**\n   * option for build\n   */\n  buildOptions?: {\n    launchBrowserOnStart?: boolean;\n  };\n\n  /**\n   * resolve aspects in the UI root\n   */\n  resolveAspects(runtimeName: string): Promise<AspectDefinition[]>;\n\n  /**\n   * resolve components from a given pattern.\n   */\n  resolvePattern?(pattern: string): Promise<string[]>;\n}\n"
  },
  {
    "path": "packages/service/src/ui/uiRuntime/index.ts",
    "content": "export { UIUI } from './ui.ui.runtime';\nexport { UIAspect, UIRuntime } from '../ui.aspect';\nexport type { UIRootUI, UIRootFactory } from './uiRoot.ui';\n"
  },
  {
    "path": "packages/service/src/ui/uiRuntime/ui.ui.runtime.tsx",
    "content": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport { BrowserRouter } from 'react-router-dom';\nimport { Slot, SlotRegistry } from '@arco-cli/stone';\nimport { ReactRouterAspect, ReactRouterUI } from '@arco-cli/aspect/dist/react-router/uiRuntime';\n\nimport UIAspect, { UIRuntime } from '../ui.aspect';\nimport { UIRootFactory } from './uiRoot.ui';\n\ntype UIRootSlot = SlotRegistry<UIRootFactory>;\n\nconst MOUNT_ROOT_ID = 'root';\n\nexport class UIUI {\n  static runtime = UIRuntime;\n\n  static dependencies = [ReactRouterAspect];\n\n  static slots = [Slot.withType<UIRootFactory>()];\n\n  static provider([router]: [ReactRouterUI], _config, [uiRootSlot]: [UIRootSlot]) {\n    return new UIUI(router, uiRootSlot);\n  }\n\n  constructor(private router: ReactRouterUI, private uiRootSlot: UIRootSlot) {}\n\n  private getRoot(rootExtension: string) {\n    return this.uiRootSlot.get(rootExtension);\n  }\n\n  registerRoot(uiRoot: UIRootFactory) {\n    return this.uiRootSlot.register(uiRoot);\n  }\n\n  render(rootExtension: string) {\n    const rootFactory = this.getRoot(rootExtension);\n    if (!rootFactory) throw new Error(`root: ${rootExtension} was not found`);\n\n    const uiRoot = rootFactory();\n    const routes = this.router.renderRoutes(uiRoot.routes);\n\n    ReactDOM.render(\n      <BrowserRouter>{routes}</BrowserRouter>,\n      document.querySelector(`#${MOUNT_ROOT_ID}`)\n    );\n  }\n}\n\nUIAspect.addRuntime(UIUI);\n"
  },
  {
    "path": "packages/service/src/ui/uiRuntime/uiRoot.ui.ts",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport { RouteProps } from 'react-router-dom';\n\nexport type UIRootUI = {\n  routes: RouteProps[];\n};\n\nexport type UIRootFactory = () => UIRootUI;\n"
  },
  {
    "path": "packages/service/src/ui/uiServer.ts",
    "content": "import webpack from 'webpack';\nimport WebpackDevServer, { Configuration as WdsConfiguration } from 'webpack-dev-server';\nimport { Server } from 'http';\nimport { Express } from 'express';\nimport httpProxy from 'http-proxy';\nimport { flatten } from 'lodash';\nimport { Logger } from '@arco-cli/core/dist/logger';\nimport { ExpressMain } from '@arco-cli/core/dist/express';\nimport { GraphqlMain } from '@arco-cli/core/dist/graphql';\nimport { Port } from '@arco-cli/legacy/dist/utils/network/port';\nimport { devConfig } from './webpack/webpack.dev.config';\nimport { ProxyEntry, UIRoot } from './uiRoot';\nimport { UIMain } from './ui.main.runtime';\nimport { UIRuntime } from './ui.aspect';\nimport { StartPlugin } from './startPlugin';\n\nexport type StartOptions = {\n  /**\n   * port range for the UI server to bind. default is a port range of 4000-4200.\n   */\n  portRange?: number[] | number;\n};\n\nexport type UIServerProps = {\n  graphql: GraphqlMain;\n  express: ExpressMain;\n  ui: UIMain;\n  uiRoot: UIRoot;\n  uiRootExtension: string;\n  logger: Logger;\n  startPlugins: StartPlugin[];\n};\n\nexport class UIServer {\n  private _port = 0;\n\n  static create({\n    graphql,\n    express,\n    ui,\n    uiRoot,\n    uiRootExtension,\n    logger,\n    startPlugins,\n  }: UIServerProps) {\n    return new UIServer(graphql, express, ui, uiRoot, uiRootExtension, logger, startPlugins);\n  }\n\n  constructor(\n    private graphql: GraphqlMain,\n    private express: ExpressMain,\n    private ui: UIMain,\n    private uiRoot: UIRoot,\n    private uiRootExtension: string,\n    private logger: Logger,\n    private startPlugins: StartPlugin[]\n  ) {}\n\n  getName() {\n    return this.uiRoot.name;\n  }\n\n  get whenReady() {\n    return Promise.all([this.startPromise, ...this.startPlugins.map((x) => x?.whenReady)]);\n  }\n\n  get port() {\n    return this._port;\n  }\n\n  get host() {\n    return 'localhost';\n  }\n\n  get fullUrl() {\n    const port = this.port !== 80 ? `:${this.port}` : '';\n    return `http://${this.host}${port}`;\n  }\n\n  get buildOptions() {\n    return this.uiRoot.buildOptions;\n  }\n\n  private setReady: () => void;\n\n  private startPromise = new Promise<void>((resolve) => {\n    this.setReady = resolve;\n  });\n\n  private async selectPort(portRange?: number[] | number) {\n    return Port.getPortFromRange(portRange || [3100, 3200]);\n  }\n\n  private async getProxyFromPlugins(): Promise<ProxyEntry[]> {\n    const proxiesByPlugin = this.startPlugins.map((plugin) => {\n      return plugin.getProxy ? plugin.getProxy() : [];\n    });\n\n    return flatten(await Promise.all(proxiesByPlugin));\n  }\n\n  private async getProxy(port = 4000): Promise<ProxyEntry[]> {\n    const proxyEntries = await this.getProxyFromPlugins();\n    const gqlProxies: ProxyEntry[] = [\n      {\n        context: ['/graphql', '/api'],\n        target: `http://${this.host}:${port}`,\n        changeOrigin: true,\n      },\n    ];\n    return gqlProxies.concat(proxyEntries);\n  }\n\n  private async configureProxy(app: Express, server: Server) {\n    const proxServer = httpProxy.createProxyServer();\n    proxServer.on('error', (e) => this.logger.error(e.message));\n    const proxyEntries = await this.getProxyFromPlugins();\n\n    server.on('upgrade', function (req, socket, head) {\n      const entry = proxyEntries.find((proxy) => proxy.context.some((item) => item === req.url));\n      if (!entry) return;\n      proxServer.ws(req, socket, head, {\n        target: entry.target,\n      });\n    });\n\n    proxyEntries.forEach((entry) => {\n      entry.context.forEach((route) => {\n        app.use(`${route}/*`, (req, res) => {\n          proxServer.web(req, res, { ...entry, target: `${entry.target}/${req.originalUrl}` });\n        });\n      });\n    });\n  }\n\n  private async getDevConfig() {\n    const aspects = await this.uiRoot.resolveAspects(UIRuntime.name);\n    const entryFilePath = await this.ui.generateRoot({\n      aspectDefs: aspects,\n      rootExtensionName: this.uiRootExtension,\n    });\n    return devConfig(this.uiRoot.path, [entryFilePath], this.uiRoot.name);\n  }\n\n  private async getDevServerConfig(\n    appPort: number,\n    gqlPort: number,\n    config?: WdsConfiguration\n  ): Promise<WdsConfiguration> {\n    const proxy = await this.getProxy(gqlPort);\n    return { ...config, proxy, port: appPort };\n  }\n\n  getPluginsComponents() {\n    return this.startPlugins.map((plugin) => plugin.render);\n  }\n\n  async start({ portRange }: StartOptions = {}) {\n    const app = this.express.createApp();\n    const server = await this.graphql.createServer({ app });\n    await this.configureProxy(app, server);\n    const port = await Port.getPortFromRange(portRange || [3100, 3200]);\n    server.listen(port);\n    this._port = port;\n\n    this.logger.info(`UI server of ${this.uiRootExtension} is listening to port ${port}`);\n    this.setReady();\n  }\n\n  async dev({ portRange }: StartOptions) {\n    const devServerPort = await this.selectPort(portRange);\n    await this.start({ portRange: [4100, 4200] });\n    const expressAppPort = this._port;\n\n    const config = await this.getDevConfig();\n    const compiler = webpack(config);\n    const devServerConfig = await this.getDevServerConfig(\n      devServerPort,\n      expressAppPort,\n      config.devServer\n    );\n    const devServer = new WebpackDevServer(devServerConfig, compiler);\n\n    await devServer.start();\n    this._port = devServerPort;\n    return devServer;\n  }\n}\n"
  },
  {
    "path": "packages/service/src/ui/webpack/html.ts",
    "content": "/** fallback html template for the main UI, in case ssr is not active */\nexport function html(title: string, withDevTools?: boolean) {\n  return () => `\n  <!DOCTYPE html>\n  <html lang=\"en\">\n    <head>\n      <meta charset=\"utf-8\">\n      <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n      <link rel=\"shortcut icon\" type=\"image/x-icon\" href=\"//unpkg.byted-static.com/byted/arco-config/1.0.12/assets/arco_material.ico\">\n      <title>${title}</title>\n      <script>\n      ${\n        withDevTools\n          ? ''\n          : 'try { window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__; } catch {}'\n      }\n      </script>\n    </head>\n    <body>\n      <div id=\"root\"></div>\n    </body>\n  </html>  \n  `;\n}\n"
  },
  {
    "path": "packages/service/src/ui/webpack/webpack.dev.config.ts",
    "content": "import path, { sep } from 'path';\nimport { ProvidePlugin } from 'webpack';\nimport openBrowser from 'react-dev-utils/openBrowser';\nimport * as stylesRegexps from '@arco-cli/legacy/dist/utils/regexp/style';\nimport { pathNormalizeToLinux } from '@arco-cli/legacy/dist/utils/path';\nimport HtmlWebpackPlugin from 'html-webpack-plugin';\nimport ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';\nimport errorOverlayMiddleware from 'react-dev-utils/errorOverlayMiddleware';\nimport evalSourceMapMiddleware from 'react-dev-utils/evalSourceMapMiddleware';\nimport noopServiceWorkerMiddleware from 'react-dev-utils/noopServiceWorkerMiddleware';\nimport redirectServedPath from 'react-dev-utils/redirectServedPathMiddleware';\nimport getPublicUrlOrPath from 'react-dev-utils/getPublicUrlOrPath';\nimport type { WebpackConfigWithDevServer } from '@arco-cli/aspect/dist/webpack';\nimport { fallbacks, fallbacksProvidePluginConfig } from '@arco-cli/aspect/dist/webpack/config';\n\nimport { html } from './html';\n\nconst matchNothingRegex = 'a^';\n\nconst publicUrlOrPath = getPublicUrlOrPath(\n  process.env.NODE_ENV === 'development',\n  sep,\n  `${sep}public`\n);\n\nconst moduleFileExtensions = [\n  'web.mjs',\n  'mjs',\n  'web.js',\n  'js',\n  'web.ts',\n  'ts',\n  'web.tsx',\n  'tsx',\n  'json',\n  'web.jsx',\n  'jsx',\n];\n\nexport function devConfig(\n  workspaceDir: string,\n  entryFiles: string[],\n  title: string\n): WebpackConfigWithDevServer {\n  const resolveWorkspacePath = (relativePath) => path.resolve(workspaceDir, relativePath);\n\n  // Host\n  const host = process.env.HOST || 'localhost';\n\n  // Required for babel-preset-react-app\n  process.env.NODE_ENV = 'development';\n\n  return {\n    mode: 'development',\n    entry: {\n      main: entryFiles,\n    },\n    output: {\n      pathinfo: false,\n      path: resolveWorkspacePath('/'),\n      // Development filename output\n      filename: 'static/js/[name].bundle.js',\n      publicPath: publicUrlOrPath,\n      chunkFilename: 'static/js/[name].chunk.js',\n      // point sourcemap entries to original disk locations (format as URL on windows)\n      devtoolModuleFilenameTemplate: (info) =>\n        pathNormalizeToLinux(path.resolve(info.absoluteResourcePath)),\n    },\n    // improves HMR - assume node_modules might change\n    snapshot: {\n      managedPaths: [],\n    },\n    infrastructureLogging: {\n      level: 'error',\n    },\n    stats: {\n      errorDetails: true,\n    },\n    devtool: 'inline-source-map',\n    devServer: {\n      host,\n      hot: true,\n      compress: true,\n      allowedHosts: 'all',\n      onListening: (devServer) => {\n        if (!devServer) {\n          throw new Error('webpack-dev-server is not defined');\n        }\n        const addr = devServer.server.address();\n        const ipListOfLocalhost = ['::1', '127.0.0.1'];\n        openBrowser(\n          typeof addr === 'string'\n            ? addr\n            : `http://${\n                ipListOfLocalhost.indexOf(addr.address) > -1 ? 'localhost' : ipListOfLocalhost\n              }:${addr.port}`\n        );\n      },\n      static: [\n        {\n          directory: resolveWorkspacePath(publicUrlOrPath),\n          staticOptions: {},\n          // Don't be confused with `dev.publicPath`, it is `publicPath` for static directory\n          // Can be:\n          // publicPath: ['/static-public-path-one/', '/static-public-path-two/'],\n          publicPath: publicUrlOrPath,\n          // Can be:\n          // serveIndex: {} (options for the `serveIndex` option you can find https://github.com/expressjs/serve-index)\n          serveIndex: true,\n          // Can be:\n          // watch: {} (options for the `watch` option you can find https://github.com/paulmillr/chokidar)\n          watch: true,\n        },\n      ],\n      historyApiFallback: {\n        index: publicUrlOrPath,\n        disableDotRule: true,\n      },\n      devMiddleware: {\n        // forward static files\n        publicPath: publicUrlOrPath.slice(0, -1),\n      },\n      setupMiddlewares: (middlewares, devServer) => {\n        middlewares.unshift(\n          // Keep `evalSourceMapMiddleware` and `errorOverlayMiddleware`\n          // middlewares before `redirectServedPath` otherwise will not have any effect\n          // This lets us fetch source contents from webpack for the error overlay\n          // @ts-ignore @types/wds mismatch\n          evalSourceMapMiddleware(devServer),\n          // This lets us open files from the runtime error overlay.\n          errorOverlayMiddleware()\n        );\n\n        middlewares.push(\n          // Redirect to `PUBLIC_URL` or `homepage` from `package.json` if url not match\n          redirectServedPath(publicUrlOrPath),\n          // This service worker file is effectively a 'no-op' that will reset any\n          // previous service worker registered for the same host:port combination.\n          // We do this in development to avoid hitting the production cache if\n          // it used the same host and port.\n          // https://github.com/facebook/create-react-app/issues/2272#issuecomment-302832432\n          noopServiceWorkerMiddleware(publicUrlOrPath)\n        );\n\n        return middlewares;\n      },\n    },\n    resolve: {\n      // These are the reasonable defaults supported by the Node ecosystem.\n      // We also include JSX as a common component filename extension to support\n      // some tools, although we do not recommend using it, see:\n      // https://github.com/facebook/create-react-app/issues/290\n      // `web` extension prefixes have been added for better support\n      // for React Native Web.\n      extensions: moduleFileExtensions.map((ext) => `.${ext}`),\n      alias: {\n        react: require.resolve('react'),\n        'react-dom': require.resolve('react-dom'),\n        'react-router-dom': require.resolve('react-router-dom'),\n      },\n      fallback: {\n        fs: false,\n        stream: false,\n        path: fallbacks.path,\n        process: fallbacks.process,\n      },\n    },\n    module: {\n      // Webpack by default includes node_modules under its managed paths which cause the whole directory to be cached\n      // Watch mode requires us to turn off unsafeCache as well\n      // this de-optimizes the dev build but ensures hmr works when writing/linking into node modules.\n      // However, we do not lose the caching entirely like cache: false\n      unsafeCache: false,\n      rules: [\n        {\n          test: /\\.m?js/,\n          resolve: {\n            fullySpecified: false,\n          },\n        },\n        {\n          test: /\\.js$/,\n          enforce: 'pre',\n          include: /node_modules/,\n          // only apply to packages with componentId in their package.json\n          descriptionData: { componentId: (value) => !!value },\n          use: [\n            require.resolve('@pmmmwh/react-refresh-webpack-plugin/loader'),\n            require.resolve('source-map-loader'),\n          ],\n        },\n        {\n          test: /\\.(js|jsx|tsx|ts)$/,\n          exclude: /node_modules/,\n          include: workspaceDir,\n          use: [\n            require.resolve('@pmmmwh/react-refresh-webpack-plugin/loader'),\n            {\n              loader: require.resolve('babel-loader'),\n              options: {\n                configFile: false,\n                babelrc: false,\n                presets: [\n                  // Preset includes JSX, TypeScript, and some ESnext features\n                  require.resolve('babel-preset-react-app'),\n                ],\n                plugins: [require.resolve('react-refresh/babel')],\n              },\n            },\n          ],\n        },\n        {\n          test: stylesRegexps.sassModuleRegex,\n          use: [\n            require.resolve('style-loader'),\n            {\n              loader: require.resolve('css-loader'),\n              options: {\n                modules: {\n                  localIdentName: '[name]__[local]--[hash:base64:5]',\n                },\n                sourceMap: true,\n              },\n            },\n            {\n              loader: require.resolve('sass-loader'),\n              options: {\n                sourceMap: true,\n              },\n            },\n          ],\n        },\n        {\n          test: stylesRegexps.sassNoModuleRegex,\n          use: [\n            require.resolve('style-loader'),\n            require.resolve('css-loader'),\n            {\n              loader: require.resolve('sass-loader'),\n              options: {\n                sourceMap: true,\n              },\n            },\n          ],\n        },\n        {\n          test: stylesRegexps.lessModuleRegex,\n          use: [\n            require.resolve('style-loader'),\n            {\n              loader: require.resolve('css-loader'),\n              options: {\n                modules: {\n                  localIdentName: '[name]__[local]--[hash:base64:5]',\n                },\n                sourceMap: true,\n              },\n            },\n            {\n              loader: require.resolve('less-loader'),\n              options: {\n                sourceMap: true,\n              },\n            },\n          ],\n        },\n        {\n          test: stylesRegexps.lessNoModuleRegex,\n          use: [\n            require.resolve('style-loader'),\n            require.resolve('css-loader'),\n            {\n              loader: require.resolve('less-loader'),\n              options: {\n                sourceMap: true,\n              },\n            },\n          ],\n        },\n        {\n          test: stylesRegexps.cssModuleRegex,\n          use: [\n            require.resolve('style-loader'),\n            {\n              loader: require.resolve('css-loader'),\n              options: {\n                modules: {\n                  localIdentName: '[name]__[local]--[hash:base64:5]',\n                },\n                sourceMap: true,\n              },\n            },\n          ],\n        },\n        {\n          test: stylesRegexps.cssNoModulesRegex,\n          use: [require.resolve('style-loader'), require.resolve('css-loader')],\n        },\n        {\n          test: /\\.svg$/,\n          use: [\n            {\n              loader: require.resolve('@svgr/webpack'),\n              options: { titleProp: true, ref: true },\n            },\n          ],\n        },\n      ],\n    },\n    plugins: [\n      new ReactRefreshWebpackPlugin({\n        // we use '@pmmmwh/react-refresh-webpack-plugin/loader' directly where relevant.\n        // FYI, original defaults of the plugin are:\n        // include: /\\.([cm]js|[jt]sx?|flow)$/i, exclude: /node_modules/,\n        include: matchNothingRegex,\n      }),\n      // Re-generate index.html with injected script tag.\n      // The injected script tag contains a src value of the\n      // filename output defined above.\n      new HtmlWebpackPlugin({\n        inject: true,\n        templateContent: html(title || 'Workspace'),\n        chunks: ['main'],\n        filename: 'index.html',\n      }),\n      new ProvidePlugin({ process: fallbacksProvidePluginConfig.process }),\n    ],\n  };\n}\n"
  },
  {
    "path": "packages/service/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"dist\",\n    \"paths\": {\n      \"@service/*\": [\"src/*\"],\n      \"@arco-cli/stone\": [\"../stone/src\"],\n      \"@arco-cli/generator\": [\"../generator/src\"],\n      \"@arco-cli/legacy/dist/*\": [\"../legacy/src/*\"],\n      \"@arco-cli/core/dist/*\": [\"../core/src/*\"],\n      \"@arco-cli/aspect/dist/*\": [\"../aspect/src/*\"],\n      \"@arco-cli/service/dist*\": [\"../service/src/*\"],\n      \"@arco-cli/ui-foundation-react\": [\"../ui-foundation-react/src\"],\n      \"@arco-cli/ui-foundation-react/dist/*\": [\"../ui-foundation-react/src/*\"]\n    }\n  }\n}\n"
  },
  {
    "path": "packages/stone/package.json",
    "content": "{\n  \"name\": \"@arco-cli/stone\",\n  \"version\": \"2.0.0-beta.0\",\n  \"description\": \"Plugin system for Arco cli\",\n  \"homepage\": \"https://github.com/arco-design/arco-cli\",\n  \"repository\": \"https://github.com/arco-design/arco-cli\",\n  \"main\": \"./dist/index.js\",\n  \"scripts\": {\n    \"dev\": \"sh ../../.scripts/build.sh dev\",\n    \"build\": \"sh ../../.scripts/build.sh\",\n    \"build-type\": \"sh ../../.scripts/build-type.sh\",\n    \"clean\": \"rm -rf dist\",\n    \"clean-type\": \"find dist -name *.d.ts |xargs rm -rf\",\n    \"prepublishOnly\": \"npm run build\"\n  },\n  \"dependencies\": {\n    \"cleargraph\": \"^5.8.0\",\n    \"comment-json\": \"^4.2.3\",\n    \"fs-extra\": \"^10.1.0\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "packages/stone/src/aspect/aspect.ts",
    "content": "import { SlotProvider } from '../slot';\nimport { AspectManifest } from './aspectManifest';\nimport { RuntimeManifest, RuntimeDefinition } from '../runtimes';\n\nexport class Aspect {\n  constructor(\n    public id: string,\n    public dependencies: Aspect[],\n    readonly slots: SlotProvider<unknown>[],\n    readonly defaultConfig = {},\n    readonly declareRuntime: RuntimeDefinition | undefined,\n    readonly files: string[]\n  ) {}\n\n  private _runtimes: RuntimeManifest[] = [];\n\n  addRuntime(runtimeManifest: RuntimeManifest) {\n    this._runtimes.push(runtimeManifest);\n    return this;\n  }\n\n  getRuntime(runtimeDef: RuntimeDefinition): undefined | RuntimeManifest {\n    return this._runtimes.find((runtime) => {\n      if (typeof runtime.runtime === 'string') return runtime.runtime === runtimeDef.name;\n      return runtime.runtime.name === runtimeDef.name;\n    });\n  }\n\n  getRuntimes(): RuntimeManifest[] {\n    return this._runtimes;\n  }\n\n  static create(manifest: AspectManifest) {\n    return new Aspect(\n      manifest.id,\n      manifest.dependencies || [],\n      manifest.slots || [],\n      manifest.defaultConfig,\n      manifest.declareRuntime,\n      manifest.files || []\n    );\n  }\n}\n"
  },
  {
    "path": "packages/stone/src/aspect/aspectManifest.ts",
    "content": "import { Aspect } from './aspect';\nimport { SlotProvider } from '../slot';\nimport { RuntimeDefinition } from '../runtimes';\n\nexport type AspectManifest = {\n  id: string;\n  dependencies?: Aspect[];\n  slots?: SlotProvider<unknown>[];\n  defaultConfig?: Record<string, any>;\n  declareRuntime?: RuntimeDefinition;\n  files?: string[];\n};\n"
  },
  {
    "path": "packages/stone/src/aspect/index.ts",
    "content": "export { Aspect } from './aspect';\nexport { AspectManifest } from './aspectManifest';\n"
  },
  {
    "path": "packages/stone/src/config/config.ts",
    "content": "export class Config {\n  constructor(readonly raw: Map<string, object>) {}\n\n  toObject() {\n    return Array.from(this.raw.entries()).reduce<any>((acc, [id, config]) => {\n      acc[id] = config;\n      return acc;\n    }, {});\n  }\n\n  set(id: string, config: object) {\n    this.raw.set(id, config);\n  }\n\n  get(id: string) {\n    return this.raw.get(id);\n  }\n\n  static from(raw: { [key: string]: object }) {\n    return new Config(new Map(Object.entries(raw)));\n  }\n}\n"
  },
  {
    "path": "packages/stone/src/config/index.ts",
    "content": "export { Config } from './config';\n"
  },
  {
    "path": "packages/stone/src/exception/extensionInitError.ts",
    "content": "export class ExtensionInitError extends Error {}\n"
  },
  {
    "path": "packages/stone/src/exception/extensionLoadError.ts",
    "content": "import { Extension } from '../extension';\n\nexport class ExtensionLoadError extends Error {\n  constructor(\n    /**\n     * failed extension\n     */\n    private extension: Extension,\n\n    /**\n     * extension error\n     */\n    private originalError: Error,\n\n    /**\n     * extension formatted / handled error message\n     */\n    private msg?: string\n  ) {\n    super();\n  }\n\n  toString() {\n    return `failed to load extension: ${this.extension.name} with error:\n\n${this.msg || this.originalError.stack}`;\n  }\n}\n"
  },
  {
    "path": "packages/stone/src/exception/extensionPotentialCircularError.ts",
    "content": "import { Extension } from '../extension';\n\nexport class ExtensionPotentialCircularError extends Error {\n  constructor(public extension: Extension, public validDeps: Extension[]) {\n    super();\n  }\n\n  toString() {\n    return `Failed to load the dependencies for extension . \nThis may result from a wrong import or from circular dependencies in imports. \nThe following dependencies succeeded loading:`;\n  }\n}\n"
  },
  {
    "path": "packages/stone/src/exception/index.ts",
    "content": "export { ReadConfigError } from './readConfigError';\nexport { RuntimeModuleError } from './runtimeModuleError';\nexport { RuntimeNotDefinedError } from './runtimeNotDefinedError';\nexport { ExtensionInitError } from './extensionInitError';\nexport { ExtensionLoadError } from './extensionLoadError';\nexport { ExtensionPotentialCircularError } from './extensionPotentialCircularError';\n"
  },
  {
    "path": "packages/stone/src/exception/readConfigError.ts",
    "content": "export class ReadConfigError extends Error {\n  constructor(path: string, private err: Error) {\n    super(`failed to read config from path: ${path}`);\n  }\n\n  get stack() {\n    return this.err.stack;\n  }\n}\n"
  },
  {
    "path": "packages/stone/src/exception/runtimeModuleError.ts",
    "content": "export class RuntimeModuleError extends Error {\n  constructor(private err: Error) {\n    super(`failed to load Stone aspect with error message: ${err.message}`);\n  }\n\n  get stack() {\n    return this.err.stack;\n  }\n}\n"
  },
  {
    "path": "packages/stone/src/exception/runtimeNotDefinedError.ts",
    "content": "export class RuntimeNotDefinedError extends Error {\n  constructor(name: string) {\n    super(`runtime: '${name}' was not defined by any aspect`);\n  }\n}\n"
  },
  {
    "path": "packages/stone/src/extension/extension.ts",
    "content": "import { Stone } from '../stone';\nimport { ExtensionManifest } from './extensionManifest';\nimport { RuntimeDefinition } from '../runtimes';\nimport { ExtensionInitError } from '../exception';\n\nexport class Extension {\n  static from(manifest: ExtensionManifest) {\n    return new Extension(manifest);\n  }\n\n  constructor(readonly manifest: ExtensionManifest) {}\n\n  private _instance = null;\n\n  private _loaded = false;\n\n  get instance() {\n    return this._instance;\n  }\n\n  get name() {\n    return this.manifest.id || this.manifest.name;\n  }\n\n  get id() {\n    return this.name;\n  }\n\n  get dependencies(): ExtensionManifest[] {\n    return this.manifest.dependencies || [];\n  }\n\n  get provider() {\n    return this.manifest.provider;\n  }\n\n  get files() {\n    return this.manifest.files;\n  }\n\n  /**\n   * returns an indication of the extension already loaded (the provider run)\n   * We don't rely on the instance since an extension provider might return null\n   */\n  get loaded() {\n    return this._loaded;\n  }\n\n  get declareRuntime() {\n    return this.manifest.declareRuntime;\n  }\n\n  toString(): string {\n    return JSON.stringify(this.name);\n  }\n\n  private buildSlotRegistries(slots: ((registerFn: () => void) => any)[], context: Stone) {\n    return slots.map((slot) => {\n      return slot(() => {\n        return context.current;\n      });\n    });\n  }\n\n  getRuntime(runtime: RuntimeDefinition) {\n    return this.manifest.getRuntime(runtime);\n  }\n\n  getRuntimes() {\n    return this.manifest.getRuntimes();\n  }\n\n  getSlots(extensionRuntime: any) {\n    if (extensionRuntime.slots && extensionRuntime.slots.length) {\n      return extensionRuntime.slots;\n    }\n\n    return this.manifest.slots || [];\n  }\n\n  getConfig(context: Stone, extensionRuntime: any) {\n    const defaultConfig = extensionRuntime.defaultConfig || this.manifest.defaultConfig || {};\n    const config = context.config.get(this.name) || {};\n    return { ...defaultConfig, ...config };\n  }\n\n  async __run(dependencies: any[], context: Stone, runtime: RuntimeDefinition) {\n    const name = this.name;\n    context.initExtension(name);\n    const extensionRuntime = this.getRuntime(runtime);\n\n    if (!extensionRuntime) {\n      return null;\n    }\n\n    // @ts-ignore\n    const registries = this.buildSlotRegistries(this.getSlots(extensionRuntime), context);\n    const config = this.getConfig(context, extensionRuntime);\n\n    if (!this.loaded) {\n      if (extensionRuntime.provider) {\n        this._instance = await extensionRuntime.provider(dependencies, config, registries, context);\n      } else {\n        try {\n          // eslint-disable-next-line new-cap\n          this._instance = new extensionRuntime.manifest(...dependencies);\n        } catch (err) {\n          throw new ExtensionInitError(err.toString());\n        }\n      }\n\n      this._loaded = true;\n      return this._instance;\n    }\n\n    context.endExtension();\n    return Promise.resolve(this.instance);\n  }\n}\n"
  },
  {
    "path": "packages/stone/src/extension/extensionManifest.ts",
    "content": "import { ProviderFn } from '../types';\nimport { SlotProvider } from '../slot';\n\nexport type ExtensionManifest = {\n  /**\n   * extension name.\n   */\n  name: string;\n\n  /**\n   * extension unique ID.\n   */\n  id?: string;\n\n  /**\n   * array of slots the extension is exposing.\n   */\n  slots?: SlotProvider<unknown>[];\n\n  /**\n   * array of extension dependencies.\n   * these other extensions will be installed and resolved prior to this extension activation.\n   */\n  dependencies?: ExtensionManifest[];\n\n  /**\n   * reference to the extension factory function.\n   */\n  provider?: ProviderFn;\n\n  /**\n   *\n   * default config of the extension.\n   */\n  defaultConfig?: object;\n\n  /**\n   * any further keys which might be expected by other extensions.\n   */\n  [key: string]: any;\n};\n"
  },
  {
    "path": "packages/stone/src/extension/index.ts",
    "content": "export { Extension } from './extension';\nexport { ExtensionManifest } from './extensionManifest';\n"
  },
  {
    "path": "packages/stone/src/extensionGraph/extensionGraph.ts",
    "content": "import { Graph } from 'cleargraph';\nimport { fromExtension, fromExtensions } from './fromExtension';\nimport { ExtensionManifest, Extension } from '../extension';\nimport { RuntimeDefinition, Runtimes } from '../runtimes';\nimport { RequireFn } from '../stone';\n\nexport type Edge = {\n  type: string;\n  runtime?: string;\n};\n\nexport class ExtensionGraph extends Graph<Extension, Edge> {\n  private cache = new Map<string, Extension>();\n\n  getRuntimeDependencies(aspect: Extension, runtime: RuntimeDefinition): Extension[] {\n    const dependencies = this.successors(aspect.name);\n    const runtimeDeps = this.successors(aspect.name, (edge) => {\n      if (!edge.runtime) return false;\n      return edge.runtime === runtime.name;\n    });\n    const runtimeManifest = aspect.getRuntime(runtime);\n    if (!runtimeManifest) return Array.from(dependencies.values());\n\n    if (runtimeDeps && runtimeDeps.size)\n      return this.sortDeps(runtimeManifest.dependencies, Array.from(runtimeDeps.values()));\n    return this.sortDeps(runtimeManifest.dependencies, Array.from(dependencies.values()));\n  }\n\n  private sortDeps(originalDependencies: any[], targetDependencies: any[]) {\n    return targetDependencies.sort((a, b) => {\n      return (\n        originalDependencies.findIndex((item) => item.id === a.id) -\n        originalDependencies.findIndex((item) => item.id === b.id)\n      );\n    });\n  }\n\n  byExecutionOrder() {\n    return this.toposort(true);\n  }\n\n  private async enrichRuntimeExtension(\n    id: string,\n    aspect: Extension,\n    runtime: RuntimeDefinition,\n    runtimes: Runtimes,\n    requireFn: RequireFn\n  ) {\n    await requireFn(aspect, runtime);\n    const runtimeManifest = aspect.getRuntime(runtime);\n    if (!runtimeManifest) return null;\n    const deps = runtimeManifest.dependencies;\n    if (!deps) return null;\n    const promises = deps.map(async (dep: any) => {\n      if (!this.hasNode(dep.id)) {\n        this.add(dep);\n        if (dep.declareRuntime) {\n          runtimes.add(dep.declareRuntime);\n        }\n\n        await requireFn(this.get(dep.id), runtime);\n        await this.enrichRuntimeExtension(dep.id, this.get(dep.id), runtime, runtimes, requireFn);\n      }\n\n      this.setEdge(id, dep.id, {\n        runtime: runtime.name,\n        type: 'runtime-dependency',\n      });\n    });\n\n    return Promise.all(promises);\n  }\n\n  async enrichRuntime(runtime: RuntimeDefinition, runtimes: Runtimes, requireFn: RequireFn) {\n    const promises = Array.from(this.nodes.entries()).map(async ([id, aspect]) => {\n      return this.enrichRuntimeExtension(id, aspect, runtime, runtimes, requireFn);\n    });\n\n    return Promise.all(promises);\n  }\n\n  add(manifest: ExtensionManifest) {\n    const { vertices, edges } = fromExtension(manifest);\n    this.setNodes(vertices);\n    this.setEdges(edges);\n\n    return this;\n  }\n\n  load(extensions: ExtensionManifest[]) {\n    const newExtensions = extensions.filter((extension) => {\n      if (!extension.id) return false;\n      return !this.get(extension.id);\n    });\n\n    const { vertices, edges } = fromExtensions(newExtensions);\n    // only set new vertices\n    // false because we don't want to override already-loaded extensions\n    this.setNodes(vertices, false);\n    this.setEdges(edges);\n\n    return this;\n  }\n\n  getExtension(manifest: ExtensionManifest): Extension {\n    const id = manifest.id || manifest.name;\n    const cachedVertex = this.cache.get(id);\n    if (cachedVertex) return cachedVertex;\n\n    const res = this.node(id);\n    if (res) {\n      this.cache.set(res.name, res);\n      return res;\n    }\n\n    return null;\n  }\n\n  get extensions(): ExtensionManifest[] {\n    return Array.from(this.nodes.values());\n  }\n\n  get aspects() {\n    return this.extensions;\n  }\n\n  get(id: string): Extension {\n    const cachedVertex = this.cache.get(id);\n    if (cachedVertex) return cachedVertex;\n\n    const res = this.node(id);\n    if (res) {\n      this.cache.set(res.name, res);\n      return res;\n    }\n\n    return null;\n  }\n\n  /**\n   * build graph from a single extension.\n   */\n  static fromRoot(extension: ExtensionManifest) {\n    const { vertices, edges } = fromExtension(extension);\n    return new ExtensionGraph(vertices, edges);\n  }\n\n  /**\n   * build graph from set of extensions\n   */\n  static from(extensions: ExtensionManifest[]) {\n    const { vertices, edges } = fromExtensions(extensions);\n    return new ExtensionGraph(vertices, edges);\n  }\n}\n"
  },
  {
    "path": "packages/stone/src/extensionGraph/fromExtension.ts",
    "content": "import { ExtensionManifest, Extension } from '../extension';\nimport { ExtensionPotentialCircularError } from '../exception';\nimport { Edge } from './extensionGraph';\n\n/**\n * build vertices and edges from the given extension\n */\nexport function fromExtension(extension: ExtensionManifest) {\n  const vertices: { [id: string]: Extension } = {};\n  let edges: { sourceId: string; targetId: string; edge: Edge }[] = [];\n\n  function iterate(root: ExtensionManifest) {\n    const id = root.id || root.name;\n    if (vertices[id]) return;\n\n    const instance = Extension.from(root);\n    const validDeps = instance.dependencies.filter((dep) => dep).map((dep) => Extension.from(dep));\n    if (instance.dependencies.length > validDeps.length) {\n      throw new ExtensionPotentialCircularError(instance, validDeps);\n    }\n    vertices[id] = instance;\n\n    const newEdges = validDeps.map((dep) => {\n      return {\n        sourceId: id,\n        targetId: dep.name,\n        edge: {\n          type: 'dependency',\n        },\n      };\n    });\n\n    edges = edges.concat(newEdges);\n    instance.dependencies.forEach((dep) => iterate(dep));\n  }\n\n  iterate(extension);\n\n  const vertexArray: { id: string; node: Extension }[] = [];\n  for (const [key, value] of Object.entries(vertices)) {\n    vertexArray.push({ id: key, node: value });\n  }\n\n  return {\n    vertices: vertexArray,\n    edges,\n  };\n}\n\n/**\n * build vertices and edges from the given list of extensions\n */\nexport function fromExtensions(extensions: ExtensionManifest[]) {\n  const perExtension = extensions.map((ext) => fromExtension(ext));\n  return perExtension.reduce(\n    (acc, subgraph) => {\n      acc.edges = acc.edges.concat(subgraph.edges);\n      acc.vertices = acc.vertices.concat(subgraph.vertices);\n      return acc;\n    },\n    { vertices: [], edges: [] }\n  );\n}\n"
  },
  {
    "path": "packages/stone/src/extensionGraph/index.ts",
    "content": "export { ExtensionGraph } from './extensionGraph';\n"
  },
  {
    "path": "packages/stone/src/index.ts",
    "content": "export { Aspect } from './aspect';\nexport { Slot, SlotRegistry } from './slot';\nexport { Stone, GlobalConfig } from './stone';\nexport { Extension, ExtensionManifest } from './extension';\nexport { RuntimeDefinition, RuntimeManifest } from './runtimes';\nexport type { ProviderFn } from './types';\n"
  },
  {
    "path": "packages/stone/src/runtimes/index.ts",
    "content": "export { Runtimes } from './runtimes';\nexport { RuntimeManifest } from './runtimeManifest';\nexport { RuntimeDefinition } from './runtimeDefinition';\n"
  },
  {
    "path": "packages/stone/src/runtimes/runtimeDefinition.ts",
    "content": "export type RuntimeDefProps = {\n  name: string;\n};\n\nconst DEFAULT_PREDICATE = (filePath: string, name: string) => {\n  return filePath.includes(`.${name}.`);\n};\n\nexport class RuntimeDefinition {\n  constructor(\n    readonly name: string,\n    readonly filePredicate: (filePath: string, name: string) => boolean = DEFAULT_PREDICATE\n  ) {}\n\n  getRuntimeFile(paths: string[]): string | undefined {\n    return paths.find((path) => this.filePredicate(path, this.name));\n  }\n\n  require(_file: string) {\n    // try {\n    //   require(_file);\n    // } catch (err) {\n    //   throw new RuntimeModuleError(err);\n    // }\n  }\n\n  static create(def: RuntimeDefProps) {\n    return new RuntimeDefinition(def.name);\n  }\n}\n"
  },
  {
    "path": "packages/stone/src/runtimes/runtimeManifest.ts",
    "content": "import { RuntimeDefinition } from './runtimeDefinition';\nimport { ProviderFn } from '../types';\nimport { Aspect } from '../aspect';\nimport { SlotProvider } from '../slot';\n\nexport interface RuntimeManifest {\n  runtime: RuntimeDefinition | string;\n  provider: ProviderFn;\n  dependencies?: Aspect[];\n  slots?: SlotProvider<unknown>[];\n  defaultConfig?: Record<string, any>;\n}\n"
  },
  {
    "path": "packages/stone/src/runtimes/runtimes.ts",
    "content": "import { RuntimeDefinition } from './runtimeDefinition';\nimport { RuntimeNotDefinedError } from '../exception';\nimport { ExtensionGraph } from '../extensionGraph';\n\nexport class Runtimes {\n  constructor(readonly runtimeDefinition: { [key: string]: RuntimeDefinition }) {}\n\n  add(runtime: RuntimeDefinition) {\n    this.runtimeDefinition[runtime.name] = runtime;\n    return this;\n  }\n\n  get(name: string): RuntimeDefinition {\n    const runtime = this.runtimeDefinition[name];\n    if (!runtime) throw new RuntimeNotDefinedError(name);\n    return this.runtimeDefinition[name];\n  }\n\n  static async load(graph: ExtensionGraph) {\n    const runtimes: { [key: string]: RuntimeDefinition } = {};\n    graph.extensions.forEach((manifest) => {\n      if (!manifest.declareRuntime) return;\n      runtimes[manifest.declareRuntime.name] = manifest.declareRuntime;\n    });\n\n    return new Runtimes(runtimes);\n  }\n}\n"
  },
  {
    "path": "packages/stone/src/slot/index.ts",
    "content": "export { Slot, SlotProvider } from './slot';\nexport { SlotRegistry } from './registry';\n"
  },
  {
    "path": "packages/stone/src/slot/registry.ts",
    "content": "export class SlotRegistry<T> {\n  constructor(private registerFn: () => string, readonly map = new Map<string, T>()) {}\n\n  get(id: string): T | undefined {\n    return this.map.get(id);\n  }\n\n  toArray() {\n    return Array.from(this.map.entries());\n  }\n\n  values() {\n    return Array.from(this.map.values());\n  }\n\n  register(value: T) {\n    const id = this.registerFn();\n    this.map.set(id, value);\n  }\n}\n"
  },
  {
    "path": "packages/stone/src/slot/slot.ts",
    "content": "import { SlotRegistry } from './registry';\n\nexport class Slot {\n  static withType<T>() {\n    return (registerFn: () => string) => {\n      return new SlotRegistry<T>(registerFn);\n    };\n  }\n}\n\nexport type SlotProvider<T> = (registerFn: () => string) => SlotRegistry<T>;\n"
  },
  {
    "path": "packages/stone/src/stone.ts",
    "content": "import { Config } from './config';\nimport { Aspect } from './aspect';\nimport { ExtensionLoadError, RuntimeNotDefinedError } from './exception';\nimport { Extension, ExtensionManifest } from './extension';\nimport { ExtensionGraph } from './extensionGraph';\nimport { Runtimes, RuntimeDefinition } from './runtimes';\nimport { asyncForEach } from './utils/asyncForEach';\n\nexport type GlobalConfig = {\n  [key: string]: object;\n};\n\nexport type RequireFn = (aspect: Extension, runtime: RuntimeDefinition) => Promise<void>;\n\nexport class Stone {\n  constructor(\n    readonly graph: ExtensionGraph,\n\n    readonly config: Config,\n\n    readonly runtimes: Runtimes,\n\n    readonly activeRuntime: string\n  ) {}\n\n  public current: string | null = null;\n\n  private runtime: RuntimeDefinition | undefined;\n\n  get extensions() {\n    return this.graph.nodes;\n  }\n\n  get extensionsIds() {\n    return [...this.graph.nodes.keys()];\n  }\n\n  private async runOne(extension: Extension, runtime: RuntimeDefinition) {\n    if (extension.loaded) return null;\n    // create an index of all vertices in a dependency graph\n    const deps = this.graph.getRuntimeDependencies(extension, runtime);\n    const instances = deps.map((extension) => extension.instance);\n\n    try {\n      return extension.__run(instances, this, runtime);\n    } catch (err) {\n      throw new ExtensionLoadError(extension, err);\n    }\n  }\n\n  getDependencies(aspect: Extension) {\n    if (!this.runtime) throw new RuntimeNotDefinedError(this.activeRuntime);\n    return this.graph.getRuntimeDependencies(aspect, this.runtime);\n  }\n\n  initExtension(id: string) {\n    this.current = id;\n  }\n\n  endExtension() {\n    this.current = null;\n  }\n\n  /**\n   * get an extension\n   */\n  get<T>(id: string): T {\n    const extension = this.graph.get(id);\n    if (!extension || !extension.instance) throw new Error(`failed loading extension ${id}`);\n    return extension.instance;\n  }\n\n  resolveRuntime(name: string): RuntimeDefinition {\n    return this.runtimes.get(name);\n  }\n\n  /**\n   * load an Aspect into the dependency graph.\n   */\n  async load(extensions: ExtensionManifest[]) {\n    this.graph.load(extensions);\n    // Only load new extensions and their dependencies\n    const extensionsToLoad = extensions.map((ext) => {\n      return ext.id || ext.name;\n    });\n\n    // @ts-ignore\n    await this.graph.enrichRuntime(this.runtime, this.runtimes, () => {});\n    const subGraphs = this.graph.successorsSubgraph(extensionsToLoad);\n    if (subGraphs) {\n      const executionOrder = subGraphs.toposort(true);\n      await asyncForEach(executionOrder, async (ext: Extension) => {\n        if (!this.runtime) throw new RuntimeNotDefinedError(this.activeRuntime);\n        await this.runOne(ext, this.runtime);\n      });\n    }\n  }\n\n  async run(requireFn?: RequireFn) {\n    const runtime = this.resolveRuntime(this.activeRuntime);\n    this.runtime = runtime;\n    const defaultRequireFn: RequireFn = async (aspect: Extension, runtime: RuntimeDefinition) => {\n      const runtimeFile = runtime.getRuntimeFile(aspect.files);\n      // eslint-disable-next-line no-useless-return\n      if (!runtimeFile) return;\n      // runtime.require(runtimeFile);\n    };\n    await this.graph.enrichRuntime(runtime, this.runtimes, requireFn || defaultRequireFn);\n    const executionOrder = this.graph.byExecutionOrder();\n    await asyncForEach(executionOrder, async (ext: Extension) => {\n      await this.runOne(ext, runtime);\n    });\n  }\n\n  static async load(aspects: Aspect[], runtime: string, globalConfig: GlobalConfig) {\n    const aspectGraph = ExtensionGraph.from(aspects as any);\n    const runtimes = await Runtimes.load(aspectGraph);\n    return new Stone(aspectGraph, Config.from(globalConfig), runtimes, runtime);\n  }\n}\n"
  },
  {
    "path": "packages/stone/src/stoneConfig/configReader.ts",
    "content": "import path from 'path';\nimport { parse } from 'comment-json';\nimport { readFileSync, existsSync } from 'fs-extra';\nimport { ReadConfigError } from '../exception';\n\nexport function readConfigFile(filePath: string, mustExist = true) {\n  if (!mustExist && !existsSync(filePath)) {\n    return {};\n  }\n  if (path.extname(filePath) === '.js') {\n    // eslint-disable-next-line @typescript-eslint/no-var-requires\n    const config = require(filePath);\n    if (typeof config === 'function') {\n      return config();\n    }\n    return config;\n  }\n\n  try {\n    return parse(readFileSync(filePath, 'utf8'));\n  } catch (err) {\n    throw new ReadConfigError(filePath, err);\n  }\n}\n"
  },
  {
    "path": "packages/stone/src/stoneConfig/index.ts",
    "content": "// StoneConfig should not be exported to root index.js\n// because it can ONLY run in node envs, will cause error in browser\nexport { StoneConfig, ConfigOptions } from './stoneConfig';\n"
  },
  {
    "path": "packages/stone/src/stoneConfig/stoneConfig.ts",
    "content": "import { stringify, assign } from 'comment-json';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport { readConfigFile } from './configReader';\n\nexport type GlobalConfigOpts = {\n  dir?: string;\n  name: string;\n};\n\nexport type ConfigOptions = {\n  cwd?: string;\n  global?: GlobalConfigOpts;\n  shouldThrow?: boolean;\n};\n\nconst defaultConfig = {\n  cwd: process.cwd(),\n  shouldThrow: true,\n};\n\nexport class StoneConfig {\n  constructor(private raw: Record<string, any>) {}\n\n  toObject() {\n    return this.raw;\n  }\n\n  toString() {\n    return stringify(this.raw);\n  }\n\n  static load(fileName: string, opts?: ConfigOptions) {\n    const mergedOpts = Object.assign(defaultConfig, opts);\n    const config = readConfigFile(join(mergedOpts.cwd, fileName), mergedOpts.shouldThrow);\n\n    if (mergedOpts.global) {\n      return StoneConfig.loadGlobal(mergedOpts.global, config);\n    }\n\n    return new StoneConfig(config);\n  }\n\n  static loadGlobal(globalOpts: GlobalConfigOpts, config: any = {}) {\n    const globalConfig = readConfigFile(join(globalOpts.dir || homedir(), globalOpts.name), false);\n    return new StoneConfig(assign(config, globalConfig));\n  }\n}\n"
  },
  {
    "path": "packages/stone/src/types.ts",
    "content": "import { Stone } from './stone';\n\n/**\n * type definition for the extension provider function.\n */\nexport type ProviderFn = (deps: any, config: any, slots: any, stone: Stone) => any | Promise<any>;\n"
  },
  {
    "path": "packages/stone/src/utils/asyncForEach.ts",
    "content": "export async function asyncForEach(array: any[], callback: any) {\n  for (let index = 0; index < array.length; index += 1) {\n    // eslint-disable-next-line no-await-in-loop\n    await callback(array[index], index, array);\n  }\n}\n"
  },
  {
    "path": "packages/stone/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"],\n  \"compilerOptions\": {\n    \"outDir\": \"dist\"\n  }\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/package.json",
    "content": "{\n  \"name\": \"@arco-cli/ui-foundation-react\",\n  \"version\": \"2.4.5\",\n  \"homepage\": \"https://github.com/arco-design/arco-cli\",\n  \"repository\": \"https://github.com/arco-design/arco-cli\",\n  \"main\": \"./dist/index.js\",\n  \"scripts\": {\n    \"dev\": \"sh ../../.scripts/build-esm.sh dev\",\n    \"build\": \"sh ../../.scripts/build-esm.sh\",\n    \"build-type\": \"sh ../../.scripts/build-type.sh\",\n    \"clean\": \"rm -rf dist\",\n    \"clean-type\": \"find dist -name *.d.ts |xargs rm -rf\",\n    \"prepublishOnly\": \"npm run build\"\n  },\n  \"dependencies\": {\n    \"@apollo/client\": \"^3.7.2\",\n    \"@arco-cli/aspect\": \"^2.4.5\",\n    \"@arco-design/web-react\": \"^2.42.2\",\n    \"@babel/runtime\": \"^7.20.6\",\n    \"@mdx-js/react\": \"^1.6.22\",\n    \"@types/mdx-js__react\": \"^1.5.5\",\n    \"classnames\": \"^2.3.2\",\n    \"copy-to-clipboard\": \"^3.3.3\",\n    \"lodash-es\": \"^4.17.21\",\n    \"react-error-boundary\": \"^3.1.4\",\n    \"react-markdown\": \"^8.0.6\",\n    \"react-syntax-highlighter\": \"^15.5.0\",\n    \"remark-gfm\": \"^3.0.1\",\n    \"uuid\": \"^9.0.0\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/backTop/index.ts",
    "content": "export { BackTop } from '@arco-design/web-react';\nexport type { BackTopProps } from '@arco-design/web-react';\n"
  },
  {
    "path": "packages/ui-foundation-react/src/baseUI/grid/grid.module.scss",
    "content": ".gridContainer {\n  display: grid;\n  grid-gap: 16px;\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/baseUI/grid/grid.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { PureComponent } from 'react';\nimport classNames from 'classnames';\nimport {\n  colGrid,\n  colGridL,\n  colGridLg,\n  colGridMd,\n  colGridSm,\n  colGridXl,\n  colGridXs,\n} from './gridTemplate';\n\nimport styles from './grid.module.scss';\n\nexport type ColCount = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;\n\nexport interface GridProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'className'> {\n  className?: string | string[];\n  /**\n   * default column count (1-12)\n   */\n  col?: ColCount;\n  /**\n   * column count at extremely small devices\n   */\n  colXs?: ColCount;\n  /**\n   * column count at mobile screens\n   */\n  colSm?: ColCount;\n  /**\n   * column count at medium devices\n   */\n  colMd?: ColCount;\n  /**\n   * column count at tablets\n   */\n  colL?: ColCount;\n  /**\n   * default column count at laptops\n   */\n  colLg?: ColCount;\n  /**\n   * default column count at desktop\n   */\n  colXl?: ColCount;\n}\n\n/**\n * A responsive css-grid wrapper.\n * Use the `col` properties to set column count in each resolution.\n */\nexport class Grid extends PureComponent<GridProps> {\n  render() {\n    const { className, col, colL, colLg, colMd, colSm, colXl, colXs, ...rest } = this.props;\n\n    const classes = [className, styles.gridContainer];\n\n    if (col !== undefined) classes.push(colGrid[col]);\n    if (colL !== undefined) classes.push(colGridL[colL]);\n    if (colLg !== undefined) classes.push(colGridLg[colLg]);\n    if (colMd !== undefined) classes.push(colGridMd[colMd]);\n    if (colSm !== undefined) classes.push(colGridSm[colSm]);\n    if (colXl !== undefined) classes.push(colGridXl[colXl]);\n    if (colXs !== undefined) classes.push(colGridXs[colXs]);\n\n    return <div {...rest} className={classNames(...classes)} />;\n  }\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/baseUI/grid/gridTemplate/gridTemplate.module.scss",
    "content": "$br-xs: 360px;\n\n// mobile\n$br-sm: 480px;\n$br-md: 768px;\n\n// tablet\n$br-l: 920px;\n$br-lg: 1200px;\n$br-xl: 1440px;\n$br-xxl: 1920px;\n\n// name val\n$breakpoints: xs $br-xs, sm $br-sm, md $br-md, l $br-l, lg $br-lg, xl $br-xl;\n\n@for $i from 1 through 12 {\n  @each $breakpoint in $breakpoints {\n    $br-name: nth($breakpoint, 1);\n    $br-val: nth($breakpoint, 2);\n\n    @media only screen and (min-width: $br-val) {\n      .colTemplate {\n        &--#{$br-name}-#{$i} {\n          grid-template-columns: repeat($i, 1fr);\n        }\n      }\n    }\n  }\n\n  .colTemplate {\n    &--all-#{$i} {\n      grid-template-columns: repeat($i, 1fr);\n    }\n  }\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/baseUI/grid/gridTemplate/index.ts",
    "content": "import styles from './gridTemplate.module.scss';\n\ntype ColumnPreset = {\n  1: string;\n  2: string;\n  3: string;\n  4: string;\n  5: string;\n  6: string;\n  7: string;\n  8: string;\n  9: string;\n  10: string;\n  11: string;\n  12: string;\n};\n\nfunction makePreset(breakPoints: string): ColumnPreset {\n  const obj: any = {};\n\n  for (let i = 1; i <= 12; i++) {\n    obj[i] = styles[`colTemplate--${breakPoints}-${i}`];\n  }\n\n  return obj;\n}\n\nexport const colGrid = makePreset('all');\nexport const colGridXs = makePreset('xs');\nexport const colGridSm = makePreset('sm');\nexport const colGridMd = makePreset('md');\nexport const colGridL = makePreset('l');\nexport const colGridLg = makePreset('lg');\nexport const colGridXl = makePreset('xl');\n"
  },
  {
    "path": "packages/ui-foundation-react/src/baseUI/grid/index.tsx",
    "content": "export { Grid } from './grid';\nexport type { GridProps } from './grid';\nexport type { ColCount } from './grid';\n"
  },
  {
    "path": "packages/ui-foundation-react/src/baseUI/highlighter/codeHighlighter.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { memo } from 'react';\nimport type { SyntaxHighlighterProps } from 'react-syntax-highlighter';\nimport Highlighter from 'react-syntax-highlighter/dist/esm/light';\nimport ts from 'react-syntax-highlighter/dist/esm/languages/hljs/typescript';\nimport defaultTheme from 'react-syntax-highlighter/dist/esm/styles/hljs/darkula';\n\nHighlighter.registerLanguage('typescript', ts);\n\nexport const CodeHighlighter = memo((props: SyntaxHighlighterProps) => {\n  return <Highlighter style={defaultTheme} {...props} />;\n});\n"
  },
  {
    "path": "packages/ui-foundation-react/src/baseUI/highlighter/index.ts",
    "content": "export { SyntaxHighlighter } from './syntaxHighlighter';\nexport { CodeHighlighter } from './codeHighlighter';\nexport type { SyntaxHighlighterProps } from 'react-syntax-highlighter';\n"
  },
  {
    "path": "packages/ui-foundation-react/src/baseUI/highlighter/syntaxHighlighter.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { memo } from 'react';\nimport type { SyntaxHighlighterProps } from 'react-syntax-highlighter';\nimport PrismHighlighter from 'react-syntax-highlighter/dist/esm/prism-light';\nimport tsxSyntax from 'react-syntax-highlighter/dist/esm/languages/prism/tsx';\nimport defaultTheme from 'react-syntax-highlighter/dist/esm/styles/prism/vsc-dark-plus';\n\nPrismHighlighter.registerLanguage('tsx', tsxSyntax);\n\nexport const SyntaxHighlighter = memo((props: SyntaxHighlighterProps) => {\n  return <PrismHighlighter style={defaultTheme} {...props} />;\n});\n\nexport { SyntaxHighlighterProps };\n"
  },
  {
    "path": "packages/ui-foundation-react/src/baseUI/index.ts",
    "content": "// these components should avoid importing the Arco UI library\n// because it will be used in the component preview page\n// which may cause conflicts if users use Arco UI too.\nexport { Grid } from './grid';\nexport type { GridProps } from './grid';\nexport { Table } from './table';\nexport type { TableProps } from './table';\n"
  },
  {
    "path": "packages/ui-foundation-react/src/baseUI/table/index.ts",
    "content": "export { Table } from './table';\nexport type { TableProps } from './table';\n"
  },
  {
    "path": "packages/ui-foundation-react/src/baseUI/table/table.module.scss",
    "content": ".table {\n  * {\n    color: var(--preview-color-text-2);\n    font-size: var(--preview-font-size-body-1);\n  }\n\n  > div {\n    grid-gap: 16px 24px;\n  }\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/baseUI/table/table.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React from 'react';\nimport classNames from 'classnames';\nimport { GridProps } from '../grid';\nimport { HeadingRow } from './tableHeadingRow';\nimport { TableRow, RowType } from './tableRow';\n\nimport styles from './table.module.scss';\n\nexport interface TableProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'className'> {\n  className?: string | string[];\n  /**\n   * the heading row, by which the table data is ordered\n   */\n  headings: string[];\n  /**\n   * the data to be shown in the table\n   */\n  rows: RowType[];\n  /**\n   * the number of columns to show in the table\n   */\n  colNumber?: GridProps['col'];\n  /**\n   * display mobile styles\n   */\n  isListView?: boolean;\n}\n\n/**\n * A table component that renders the properties of a component.\n */\nexport function Table({\n  headings,\n  rows,\n  colNumber = 4,\n  isListView,\n  className,\n  ...rest\n}: TableProps) {\n  return (\n    <div {...rest} className={classNames(styles.table, className)}>\n      <HeadingRow isListView={isListView} colNumber={colNumber} headings={headings} />\n      {rows.map((row: RowType, index: number) => {\n        return <TableRow key={index} headings={headings} row={row} colNumber={colNumber} />;\n      })}\n    </div>\n  );\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/baseUI/table/tableColumn.module.scss",
    "content": ".tableColumn {\n  display: flex;\n  align-items: center;\n\n  code {\n    white-space: normal !important;\n  }\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/baseUI/table/tableColumn.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React from 'react';\nimport classNames from 'classnames';\n\nimport styles from './tableColumn.module.scss';\n\nexport interface TableColumnProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'className'> {\n  className?: string | string[];\n}\n\n/**\n *\n * a column to be shown in the table\n */\nexport function TableColumn({ children, className, ...rest }: TableColumnProps) {\n  return (\n    <div className={classNames(styles.tableColumn, className)} {...rest}>\n      {children}\n    </div>\n  );\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/baseUI/table/tableHeadingColumn.module.scss",
    "content": ".headingColumn {\n  display: flex;\n  align-items: center;\n  flex-wrap: wrap;\n  font-weight: bold;\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/baseUI/table/tableHeadingColumn.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React from 'react';\nimport classNames from 'classnames';\n\nimport styles from './tableHeadingColumn.module.scss';\n\nexport interface TableHeadingColumnProps\n  extends Omit<React.HTMLAttributes<HTMLDivElement>, 'className'> {\n  className?: string | string[];\n}\n\n/**\n * Title heading column for using in the table heading\n */\nexport function HeadingColumn({ children, className, ...rest }: TableHeadingColumnProps) {\n  return (\n    <div className={classNames(styles.headingColumn, className)} {...rest}>\n      <div className={classNames(styles.title)}>{children}</div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/baseUI/table/tableHeadingRow.module.scss",
    "content": ".titleRow {\n  display: grid;\n  padding: 12px 20px;\n  border-bottom: 1px solid var(--preview-color-border);\n\n  &.hide {\n    display: none;\n  }\n}\n\n.titleCol {\n  text-transform: uppercase;\n  color: var(--preview-color-text-1);\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/baseUI/table/tableHeadingRow.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React from 'react';\nimport classNames from 'classnames';\nimport { Grid, GridProps } from '../grid';\nimport { HeadingColumn } from './tableHeadingColumn';\n\nimport styles from './tableHeadingRow.module.scss';\n\nexport type HeadingRowProps = {\n  /**\n   * array of strings to be displayed in the title row\n   */\n  headings: string[];\n  /**\n   * number of columns in the row\n   */\n  colNumber: GridProps['col'];\n  /**\n   * display mobile styles\n   */\n  isListView?: boolean;\n} & GridProps;\n\nexport function HeadingRow({\n  headings,\n  colNumber,\n  isListView = false,\n  className,\n  ...rest\n}: HeadingRowProps) {\n  return (\n    <Grid\n      {...rest}\n      col={colNumber}\n      className={classNames(styles.titleRow, { [styles.hide]: isListView }, className)}\n    >\n      {headings.map((title: string, index: number) => {\n        return title === 'required' ? null : (\n          <HeadingColumn key={index} className={styles.titleCol}>\n            {title}\n          </HeadingColumn>\n        );\n      })}\n    </Grid>\n  );\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/baseUI/table/tableRow.module.scss",
    "content": ".propRow {\n  border-bottom: 1px solid var(--preview-color-border);\n  padding: 8px 20px;\n}\n\n.column {\n  display: flex;\n  align-items: center;\n  flex-wrap: wrap;\n}\n\n.columnContent {\n  display: flex;\n  align-items: center;\n  flex-wrap: wrap;\n}\n\n.title {\n  margin: unset;\n  text-transform: capitalize;\n}\n\n.version,\n.required {\n  margin: 0 4px;\n  padding: 2px 4px;\n  border-radius: 2px;\n  font-size: 10px;\n  white-space: nowrap;\n  background: var(--preview-color-fill-1);\n  color: var(--preview-color-text-3);\n}\n\n.name {\n  margin-right: 5px;\n  color: var(--preview-color-primary);\n}\n\n.type {\n  display: inline-block;\n  background-color: var(--preview-color-fill-1);\n  width: fit-content;\n  padding: 5px;\n  border-radius: 4px;\n}\n\n.typeColumn {\n  .highlighted {\n    display: flex !important; // override syntax highlighter inline styles\n    flex-grow: 1;\n    background: unset !important; // override syntax highlighter inline styles\n    padding: 0 !important; // override syntax highlighter inline styles\n    word-break: break-word;\n    white-space: pre-wrap;\n    margin: 0; // reset browser's default css\n\n    > code > span {\n      color: #397300;\n    }\n\n    > code {\n      font-family: inherit; // reset browser's default css\n    }\n  }\n}\n\n.breakWord {\n  word-break: break-word;\n}\n\n.link {\n  color: var(--preview-color-primary) !important;\n  text-decoration: none;\n  opacity: 0.7;\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/baseUI/table/tableRow.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { ReactElement, ReactNode } from 'react';\nimport classNames from 'classnames';\n\nimport { Grid, GridProps } from '../grid';\nimport { TableColumn } from './tableColumn';\nimport { CodeHighlighter } from '../../baseUI/highlighter';\nimport { MarkdownLive } from '../../markdown/live';\n\nimport styles from './tableRow.module.scss';\n\nexport type RowType = {\n  name: string;\n  type: string;\n  description: string;\n  required: boolean;\n  version?: string;\n  default?: string;\n  [key: string]: string | any;\n};\n\nexport type CustomRowType = {\n  // eslint-disable-next-line no-unused-vars\n  [K in keyof RowType]?: ReactElement;\n};\n\nexport type TableRowProps = {\n  /**\n   * the number of columns to show in the row\n   */\n  colNumber: GridProps['col'];\n  /**\n   * the data to be shown in the row\n   */\n  row: RowType;\n  /**\n   * the heading row, by which the row data is ordered\n   */\n  headings: string[];\n} & GridProps;\n\n/**\n *\n * Renders a row in the table according to the order of the headings.\n */\nexport function TableRow({ row, colNumber = 4, headings, className, ...rest }: TableRowProps) {\n  return (\n    <Grid col={colNumber} className={classNames(styles.propRow, className)} {...rest}>\n      {headings.map((title, index) => {\n        if (title === 'name') {\n          return (\n            <TableColumn className={styles.breakWord} key={index}>\n              <div className={styles.columnContent}>\n                <div className={styles.name}>{row[title]}</div>\n                {row.required && <div className={styles.required}>(Required)</div>}\n                {row.version && <div className={styles.version}>{row.version}</div>}\n              </div>\n            </TableColumn>\n          );\n        }\n\n        if (title === 'type' || title === 'default') {\n          const text = row[title] || '-';\n          const matches = text.match(/^\\[([^\\]]+)]\\(([^)]+)\\)$/);\n          let columnContent: ReactNode = null;\n\n          if (matches) {\n            const [, typeText, href] = matches;\n            columnContent = (\n              <a className={styles.link} href={href}>\n                {typeText}\n              </a>\n            );\n          } else {\n            columnContent = (\n              <CodeHighlighter language=\"typescript\" className={styles.highlighted}>\n                {text}\n              </CodeHighlighter>\n            );\n          }\n\n          return (\n            <TableColumn className={classNames(styles.breakWord, styles.typeColumn)} key={index}>\n              {columnContent}\n            </TableColumn>\n          );\n        }\n\n        // default\n        return (\n          <TableColumn className={styles.breakWord} key={index}>\n            <MarkdownLive children={row[title]} />\n          </TableColumn>\n        );\n      })}\n    </Grid>\n  );\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/constants.ts",
    "content": "/**\n * Domain info\n */\nexport const BASE_WEB_DOMAIN = 'arco.design';\n\nexport const BASE_DOCS_DOMAIN = `${BASE_WEB_DOMAIN}/material`;\n\n/**\n * HTML element classnames\n */\nexport const CLASSNAME_MARKDOWN_CONTENT = 'a-md-content';\n\n/**\n * LocalStorage keys\n */\nexport const LOCAL_STORAGE_KEY_WORKSPACE_DARK_MODE = 'arco_workspace_dark_mode';\n\n/**\n * Valid message type received from parent window\n */\nexport enum VALID_MESSAGE_TYPE_FROM_PARENT_WINDOW {\n  updateAnchorOffset = 'updateAnchorOffset',\n  appendExtraStyle = 'appendExtraStyle',\n  switchDarkMode = 'switchDarkMode',\n  scrollIntoView = 'scrollIntoView',\n  switchActiveTab = 'switchActiveTab',\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/globalLoader/index.ts",
    "content": "export { useLoader } from './useLoader';\nexport { useLoaderApi } from './useLoaderApi';\nexport { LoaderContext } from './loaderContext';\n"
  },
  {
    "path": "packages/ui-foundation-react/src/globalLoader/loaderContext.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport { createContext, Context } from 'react';\n\nexport type LoaderApi = {\n  isActive: (id: string) => boolean;\n  update: (id: string, value: boolean) => boolean;\n  remove: (id: string) => boolean;\n};\n\nconst defaultLoaderApi: LoaderApi = {\n  isActive: () => false,\n  update: () => false,\n  remove: () => false,\n};\n\nexport const LoaderContext: Context<LoaderApi> = createContext<LoaderApi>(defaultLoaderApi);\n"
  },
  {
    "path": "packages/ui-foundation-react/src/globalLoader/useLoader.ts",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport { useContext, useEffect, useState } from 'react';\nimport { v1 } from 'uuid';\n\nimport { LoaderContext } from './loaderContext';\n\nexport function useLoader(loading: boolean) {\n  const [id] = useState(() => v1());\n  const ctx = useContext(LoaderContext);\n\n  useEffect(() => {\n    ctx.update(id, loading);\n    return () => {\n      ctx.remove(id);\n    };\n  }, [loading, ctx, id]);\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/globalLoader/useLoaderApi.ts",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport { useCallback, useMemo, useRef, useState } from 'react';\nimport { LoaderApi } from './loaderContext';\n\nexport function useLoaderApi(): [LoaderApi, boolean] {\n  const { current: loaders } = useRef(new Set<string>());\n  const [isLoading, setIsLoading] = useState(false);\n\n  const reevaluate = useCallback(() => {\n    // setState hook does not trigger re-render\n    // unless value differs\n    setIsLoading(loaders.size > 0);\n  }, [loaders]);\n\n  const api = useMemo<LoaderApi>(\n    () => ({\n      isActive: (id: string) => loaders.has(id),\n      update: (id: string, value: boolean) => {\n        const res = value ? !!loaders.add(id) : loaders.delete(id);\n        reevaluate();\n        return res;\n      },\n      remove: (id: string) => {\n        const res = loaders.delete(id);\n        reevaluate();\n        return res;\n      },\n    }),\n    [loaders, reevaluate]\n  );\n\n  return [api, isLoading];\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/hooks/useDataQuery.ts",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport { useEffect } from 'react';\nimport {\n  useQuery,\n  OperationVariables,\n  QueryResult,\n  QueryHookOptions,\n  DocumentNode,\n} from '@apollo/client';\nimport { Message } from '@arco-design/web-react';\nimport { useLoader } from '../globalLoader';\n\nexport function useDataQuery<TData = any, TVariables = OperationVariables>(\n  query: DocumentNode,\n  options?: QueryHookOptions<TData, TVariables>\n): QueryResult<TData, TVariables> {\n  const res = useQuery(query, options);\n  const { loading, error } = res;\n\n  useLoader(loading);\n\n  useEffect(() => {\n    if (error) {\n      Message.error(error.toString());\n    }\n  }, [error]);\n\n  return res;\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/index.ts",
    "content": "export * from './constants';\nexport { Grid, Table } from './baseUI';\nexport type { GridProps, TableProps } from './baseUI';\nexport { BackTop } from './backTop';\nexport type { BackTopProps } from './backTop';\nexport { LoaderContext, useLoader, useLoaderApi } from './globalLoader';\nexport { useDataQuery } from './hooks/useDataQuery';\nexport { Navbar } from './navbar';\nexport type { NavbarProps } from './navbar';\nexport { ErrorPage, NotFoundPage, ContactFooter } from './pages';\nexport { SideBar } from './sideBar';\nexport { WorkspaceContext, WorkspaceContextProvider } from './workspaceContext';\nexport { WorkspaceOverview } from './workspaceOverview';\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/components/anchor/anchor.module.scss",
    "content": ".anchor {\n  text-decoration: none;\n  color: var(--preview-color-link) !important;\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/components/anchor/anchor.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { AnchorHTMLAttributes } from 'react';\nimport cs from 'classnames';\n\nimport styles from './anchor.module.scss';\n\nexport function Anchor({\n  href,\n  children,\n  className,\n  ...rest\n}: AnchorHTMLAttributes<HTMLAnchorElement>) {\n  return (\n    <a\n      {...rest}\n      href={href}\n      target=\"_blank\"\n      rel=\"noreferrer\"\n      className={cs(styles.anchor, className)}\n    >\n      {children}\n    </a>\n  );\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/components/anchor/index.ts",
    "content": "export { Anchor } from './anchor';\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/components/demoView/demoView.module.scss",
    "content": ".demoView {\n  margin-top: 16px;\n  border-radius: 4px;\n  margin-bottom: 36px;\n  border: 1px solid var(--preview-color-border);\n\n  .demo {\n    padding: 12px;\n    overflow: auto;\n  }\n\n  .code {\n    border-radius: 0 0 4px 4px;\n  }\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/components/demoView/demoView.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { PropsWithChildren } from 'react';\nimport { CodeSnippet } from '../snippet/codeSnippet';\n\nimport styles from './demoView.module.scss';\n\nexport interface DemoViewProps {\n  language?: string;\n  code?: string | { needDecode: boolean; value: string };\n}\n\nfunction decodeRawCode(uint8ArrayStr) {\n  const decoder = new TextDecoder();\n  return decoder.decode(new Uint8Array(uint8ArrayStr.split(',')));\n}\n\nexport function DemoView({ children, code, language }: PropsWithChildren<DemoViewProps>) {\n  const codeText = code ? (typeof code === 'string' ? code : code.value) : null;\n  const needDecodeCodeText = code && typeof code === 'object' ? code.needDecode : false;\n\n  return (\n    <div className={styles.demoView}>\n      <div className={styles.demo}>{children}</div>\n      {codeText ? (\n        <CodeSnippet className={styles.code} language={language} codeSandbox>\n          {needDecodeCodeText ? decodeRawCode(codeText) : codeText}\n        </CodeSnippet>\n      ) : null}\n    </div>\n  );\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/components/demoView/index.ts",
    "content": "export { DemoView } from './demoView';\nexport type { DemoViewProps } from './demoView';\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/components/docAnchor/docAnchor.module.scss",
    "content": "@import '../../style/variable';\n\n.docAnchor {\n  position: fixed;\n  right: 0;\n  top: 40px;\n  max-height: 600px;\n  box-sizing: border-box;\n  width: $doc-anchor-width;\n  padding-left: 6px !important;\n  border-left: 2px solid var(--preview-color-border);\n  list-style: none;\n  overflow: auto;\n\n  .anchor {\n    display: block;\n    line-height: 1.5715;\n    margin-bottom: 2px;\n    padding: 4px 8px;\n    border-radius: 2px;\n    cursor: pointer;\n    text-overflow: ellipsis;\n    overflow: hidden;\n    white-space: nowrap;\n    text-decoration: none;\n    font-size: var(--preview-font-size-body-3);\n    color: var(--preview-color-text-2);\n\n    &:hover {\n      background-color: var(--preview-color-fill-2);\n      color: var(--preview-color-text-1);\n      font-weight: 500;\n    }\n  }\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/components/docAnchor/docAnchor.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { useContext, useEffect, useRef, useState } from 'react';\n\nimport { VALID_MESSAGE_TYPE_FROM_PARENT_WINDOW } from '../../../constants';\nimport { textToHTMLId } from '../heading';\nimport { PreviewContext } from '../../../preview/previewContext';\n\nimport styles from './docAnchor.module.scss';\n\nexport function DocAnchor() {\n  const { pubsub, pubsubTopicParent } = useContext(PreviewContext);\n  const [anchorList, setAnchorList] = useState<Array<{ text: string; depth: number; id?: string }>>(\n    []\n  );\n\n  const refHeadingQueryTimer = useRef(null);\n  const [pageOffset, setPageOffset] = useState(0);\n\n  useEffect(() => {\n    refHeadingQueryTimer.current = setInterval(() => {\n      const titles = document.querySelectorAll('h1, h2');\n      if (titles?.length) {\n        setAnchorList(\n          [...titles]\n            .map((title) => {\n              return {\n                id: title.getAttribute('id'),\n                text: title.textContent,\n                depth: +title.tagName.slice(-1),\n              };\n            })\n            .filter(({ id }) => !!id)\n        );\n      }\n    }, 500);\n\n    return () => {\n      window.clearInterval(refHeadingQueryTimer.current);\n    };\n  }, []);\n\n  useEffect(() => {\n    pubsub?.sub(pubsubTopicParent, (message) => {\n      const { type, data } = message;\n      if (\n        type === VALID_MESSAGE_TYPE_FROM_PARENT_WINDOW.updateAnchorOffset &&\n        typeof data.offset === 'number'\n      ) {\n        setPageOffset(data.offset);\n      }\n    });\n  }, [pubsub]);\n\n  return anchorList.length ? (\n    <ul\n      className={styles.docAnchor}\n      style={pageOffset ? { transform: `translateY(${pageOffset}px)` } : {}}\n    >\n      {anchorList.map(({ depth, text, id }, index) => {\n        return (\n          <li key={index}>\n            <a\n              className={styles.anchor}\n              style={{ marginLeft: 16 * (depth - 1) }}\n              href={`#${id || textToHTMLId(text)}`}\n            >\n              {text}\n            </a>\n          </li>\n        );\n      })}\n    </ul>\n  ) : null;\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/components/docAnchor/index.ts",
    "content": "export { DocAnchor } from './docAnchor';\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/components/heading/heading.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { HTMLAttributes, useMemo } from 'react';\nimport { extractChildrenText, textToHTMLId } from './utils';\n\ninterface HeadingProps extends HTMLAttributes<HTMLHeadingElement> {\n  depth: 1 | 2 | 3 | 4 | 5 | 6;\n}\n\nexport function Heading({ children, depth, ...rest }: HeadingProps) {\n  const id = useMemo(() => {\n    const text = extractChildrenText(children);\n    return textToHTMLId(text);\n  }, [children]);\n  const attributes = { ...rest, id };\n\n  switch (depth) {\n    case 1:\n      return <h1 {...attributes}>{children}</h1>;\n    case 2:\n      return <h2 {...attributes}>{children}</h2>;\n    case 3:\n      return <h3 {...attributes}>{children}</h3>;\n    case 4:\n      return <h4 {...attributes}>{children}</h4>;\n    case 5:\n      return <h5 {...attributes}>{children}</h5>;\n    default:\n      return <h6 {...attributes}>{children}</h6>;\n  }\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/components/heading/index.ts",
    "content": "export { Heading } from './heading';\nexport { textToHTMLId } from './utils';\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/components/heading/utils.ts",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport { Children, ReactNode, ReactElement } from 'react';\n\nexport function extractChildrenText(children: ReactNode, text = ''): string {\n  if (!children) return '';\n\n  Children.toArray(children).forEach((child) => {\n    if (!child) return;\n\n    if ((child as ReactElement).props?.children) {\n      text += extractChildrenText((child as ReactElement).props?.children);\n    } else {\n      text += child.toString();\n    }\n  });\n\n  return text;\n}\n\nexport function textToHTMLId(text: string): string {\n  return typeof text === 'string' ? text.replace(/\\s/g, '') : undefined;\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/components/index.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React from 'react';\nimport type { MDXProviderComponents } from '@mdx-js/react';\nimport { Anchor } from './anchor';\nimport { Snippet } from './snippet';\nimport { DemoView } from './demoView';\nimport { DocAnchor } from './docAnchor';\nimport { Heading } from './heading';\nimport { Tabs } from './tabs';\n\nexport const COMPONENT_NAME_DEMO_VIEW = 'ArcoDemoView';\n\nexport const COMPONENT_NAME_DOC_ANCHOR = 'ArcoDocAnchor';\n\nexport const COMPONENT_NAME_TABS = 'ArcoMDXPreviewSplit';\n\nexport const DEFAULT_MDX_COMPONENTS: MDXProviderComponents = {\n  a: Anchor,\n  code: Snippet,\n  h1: (props) => <Heading {...props} depth={1} />,\n  h2: (props) => <Heading {...props} depth={2} />,\n  h3: (props) => <Heading {...props} depth={3} />,\n  h4: (props) => <Heading {...props} depth={4} />,\n  h5: (props) => <Heading {...props} depth={5} />,\n  h6: (props) => <Heading {...props} depth={6} />,\n  [COMPONENT_NAME_DEMO_VIEW]: DemoView,\n  [COMPONENT_NAME_DOC_ANCHOR]: DocAnchor,\n  [COMPONENT_NAME_TABS]: Tabs,\n};\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/components/snippet/codeSnippet.module.scss",
    "content": ".snippetWrapper {\n  position: relative;\n  border-radius: 4px;\n  overflow: hidden;\n\n  code {\n    font-family: inherit !important;\n  }\n\n  .codeSnippet {\n    max-height: 240px;\n    padding: 16px !important;\n    background-color: white;\n    font-size: var(--preview-font-size-body-1);\n\n    // this is so that the copy icon will consistently sit at the corner of the snippet\n    margin: 0 !important;\n\n    &.expanded {\n      max-height: unset;\n    }\n  }\n\n  .operationButtons {\n    display: flex;\n    align-items: center;\n    position: absolute;\n    top: 20px;\n    right: 20px;\n    color: white;\n    opacity: 0;\n    transition: opacity 0.1s ease-in-out;\n\n    button {\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      width: 28px;\n      height: 28px;\n      margin-left: 8px;\n      padding: 0;\n      border: 1px solid #f2f3f51a;\n      border-radius: 2px;\n      background: rgb(255 255 255 / 10%);\n      backdrop-filter: blur(8px);\n      color: #fff;\n      box-shadow: 0 2px 4px 0 #1f23291a;\n      cursor: pointer;\n\n      &:hover {\n        background: rgb(255 255 255 / 15%);\n      }\n\n      &:active {\n        background: rgb(255 255 255 / 20%);\n      }\n\n      svg {\n        display: inline-block;\n        color: inherit;\n      }\n    }\n  }\n\n  &:hover {\n    .operationButtons {\n      opacity: 1;\n    }\n  }\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/components/snippet/codeSnippet.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { useMemo, useState, useEffect, useRef } from 'react';\nimport classNames from 'classnames';\nimport copy from 'copy-to-clipboard';\nimport { IconCodeSandbox } from '@arco-design/web-react/icon';\n\nimport { SyntaxHighlighter, SyntaxHighlighterProps } from '../../../baseUI/highlighter';\n\nimport styles from './codeSnippet.module.scss';\nimport IconCopy from '../asset/icon-copy.svg';\nimport IconCheck from '../asset/icon-check.svg';\nimport IconShrink from '../asset/icon-shrink.svg';\nimport IconExpand from '../asset/icon-expand.svg';\n\nconst customStyles = { fontSize: 12 };\n\nexport type ArcoDemoContext = {\n  gotoCodeSandbox: (info: { code: string; language: 'js' | 'jsx' | 'ts' | 'tsx' }) => void;\n};\n\nexport type CodeSnippetProps = {\n  /**\n   * the code string to show and to be copied to clipboard\n   */\n  children: string;\n  /**\n   * a class to override the highlighter class\n   */\n  frameClass?: string;\n  /**\n   * whether codeSandbox button is needed\n   */\n  codeSandbox?: boolean;\n} & SyntaxHighlighterProps;\n\n/**\n * A code snippet component\n */\nexport function CodeSnippet({\n  className,\n  frameClass,\n  language = 'tsx',\n  children,\n  codeSandbox,\n  ...rest\n}: CodeSnippetProps) {\n  const [codeCopied, setCodeCopied] = useState(false);\n  const [codeExpanded, setCodeExpanded] = useState(false);\n\n  const refResetCopyStatusTimer = useRef<any>(null);\n  const trimmedChildren = useMemo(() => children.trim(), [children]);\n\n  useEffect(() => {\n    clearTimeout(refResetCopyStatusTimer.current);\n    refResetCopyStatusTimer.current = setTimeout(() => {\n      setCodeCopied(false);\n    }, 1000);\n  }, [codeCopied]);\n\n  useEffect(() => {\n    return () => {\n      clearTimeout(refResetCopyStatusTimer.current);\n    };\n  }, []);\n\n  const demoContext: ArcoDemoContext = (window as any).arcoDemoContext;\n\n  return (\n    <div className={classNames(styles.snippetWrapper, className)}>\n      <SyntaxHighlighter\n        {...rest}\n        className={classNames(styles.codeSnippet, frameClass, { [styles.expanded]: codeExpanded })}\n        language={language}\n        customStyle={customStyles}\n      >\n        {trimmedChildren}\n      </SyntaxHighlighter>\n\n      <div className={styles.operationButtons}>\n        {codeSandbox && typeof demoContext?.gotoCodeSandbox === 'function' ? (\n          // eslint-disable-next-line jsx-a11y/control-has-associated-label\n          <button onClick={() => demoContext?.gotoCodeSandbox({ code: trimmedChildren, language })}>\n            <IconCodeSandbox />\n          </button>\n        ) : null}\n        <button\n          onClick={() => {\n            const result = copy(children.toString());\n            setCodeCopied(result);\n          }}\n        >\n          {codeCopied ? <IconCheck /> : <IconCopy />}\n        </button>\n        <button onClick={() => setCodeExpanded(!codeExpanded)}>\n          {codeExpanded ? <IconShrink /> : <IconExpand />}\n        </button>\n      </div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/components/snippet/index.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React from 'react';\nimport { CodeSnippet } from './codeSnippet';\n\nexport type SnippetProps = {\n  children: string;\n  live?: boolean | string;\n};\n\nexport function Snippet({ children, live }: SnippetProps) {\n  // TODO live code snippet\n  if (live) {\n    return null;\n  }\n\n  return <CodeSnippet>{children}</CodeSnippet>;\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/components/tabs/index.tsx",
    "content": "export { Tabs } from './tabs';\nexport type { TabsProps } from './tabs';\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/components/tabs/tabs.module.scss",
    "content": ".tabs {\n  .header {\n    display: flex;\n    align-items: center;\n    margin-bottom: 12px;\n    overflow: auto;\n\n    .title {\n      display: inline-block;\n      padding: 3px 12px;\n      max-width: 180px;\n      border-radius: 20px;\n      border: 1px solid var(--preview-color-border);\n      overflow: hidden;\n      white-space: nowrap;\n      text-overflow: ellipsis;\n      cursor: pointer;\n\n      &:not(:last-child) {\n        margin-right: 12px;\n      }\n\n      &.active {\n        font-weight: 500;\n        border-color: var(--preview-color-primary);\n        color: var(--preview-color-primary);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/components/tabs/tabs.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { ReactNode, useContext, useEffect, useState } from 'react';\nimport cs from 'classnames';\nimport { VALID_MESSAGE_TYPE_FROM_PARENT_WINDOW } from '../../../constants';\nimport { PreviewContext } from '../../../preview/previewContext';\n\nimport styles from './tabs.module.scss';\n\nexport interface TabsProps {\n  panes: Array<{ title: string; content: ReactNode }>;\n}\n\nexport function Tabs({ panes = [] }: TabsProps) {\n  const { pubsub, pubsubTopic, pubsubTopicParent } = useContext(PreviewContext);\n  const [activeKey, setActiveKey] = useState<string>('0');\n\n  useEffect(() => {\n    pubsub?.reportActiveTab(pubsubTopic, { activeTab: `${activeKey}` });\n  }, [activeKey]);\n\n  useEffect(() => {\n    pubsub?.sub(pubsubTopicParent, (message) => {\n      const { type, data } = message;\n      if (type === VALID_MESSAGE_TYPE_FROM_PARENT_WINDOW.switchActiveTab && data.tab) {\n        setActiveKey(data.tab);\n      }\n    });\n  }, [pubsub]);\n\n  return (\n    <div className={styles.tabs}>\n      <div className={styles.header}>\n        {panes.map(({ title }, index) => {\n          const isActive = index.toString() === activeKey;\n          return (\n            <div\n              key={index}\n              title={typeof title === 'string' ? title : undefined}\n              className={cs(styles.title, { [styles.active]: isActive })}\n              onClick={() => setActiveKey(index.toString())}\n            >\n              {title}\n            </div>\n          );\n        })}\n      </div>\n      <div>\n        {panes.map(({ content }, index) => {\n          const isActive = index.toString() === activeKey;\n          return isActive ? <div key={index}>{content}</div> : null;\n        })}\n      </div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/live/index.ts",
    "content": "export { MarkdownLive } from './markdownLive';\nexport type { MarkdownLiveProps } from './markdownLive';\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/live/markdownLive.module.scss",
    "content": ".markdownLive {\n\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/live/markdownLive.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { ReactNode } from 'react';\nimport gfm from 'remark-gfm';\nimport ReactMarkdown from 'react-markdown';\nimport cs from 'classnames';\n\nimport { Heading } from '../components/heading';\nimport { CodeSnippet } from '../components/snippet/codeSnippet';\n\nimport styles from './markdownLive.module.scss';\n\nconst MARKDOWN_BODY_CLASSNAME = 'markdown-body';\n\nexport interface MarkdownLiveProps {\n  className?: string;\n  children?: string;\n}\n\nfunction H1(props) {\n  return <Heading depth={1} {...props} />;\n}\nfunction H2(props) {\n  return <Heading depth={2} {...props} />;\n}\nfunction H3(props) {\n  return <Heading depth={3} {...props} />;\n}\nfunction H4(props) {\n  return <Heading depth={4} {...props} />;\n}\nfunction H5(props) {\n  return <Heading depth={5} {...props} />;\n}\nfunction H6(props) {\n  return <Heading depth={6} {...props} />;\n}\nfunction Code(props: { children: ReactNode; inline?: boolean }) {\n  const { inline, children } = props;\n  const code = children?.[0] || '';\n  return inline ? <code>{code}</code> : <CodeSnippet children={code} />;\n}\n\nexport function MarkdownLive(props: MarkdownLiveProps) {\n  const { children, className } = props;\n\n  return (\n    <ReactMarkdown\n      children={children}\n      className={cs(MARKDOWN_BODY_CLASSNAME, styles.markdownLive, className)}\n      remarkPlugins={[gfm]}\n      components={{\n        code: Code,\n        h1: H1,\n        h2: H2,\n        h3: H3,\n        h4: H4,\n        h5: H5,\n        h6: H6,\n      }}\n    />\n  );\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/mdxLayout/index.ts",
    "content": "export { MDXLayout } from './mdxLayout';\nexport {\n  DEFAULT_MDX_COMPONENTS,\n  COMPONENT_NAME_DEMO_VIEW,\n  COMPONENT_NAME_DOC_ANCHOR,\n} from '../components';\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/mdxLayout/mdxLayout.module.scss",
    "content": "@import '../style/variable';\n\n:global(body[arco-theme='dark']) {\n  color-scheme: dark;\n  background: var(--preview-color-bg-1);\n}\n\n.mdxContent {\n  line-height: 1.5;\n  padding-right: calc($doc-anchor-width + 60px);\n\n  img {\n    max-width: 100%;\n  }\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/mdxLayout/mdxLayout.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { useMemo, ReactNode } from 'react';\nimport { MDXProvider, MDXProviderComponents } from '@mdx-js/react';\nimport classNames from 'classnames';\nimport { DEFAULT_MDX_COMPONENTS } from '../components';\n\n// use markdown-limit.css, not markdown.css\nimport '../style/markdown-limit.css';\nimport styles from './mdxLayout.module.scss';\n\nconst MARKDOWN_BODY_CLASSNAME = 'markdown-body';\n\nexport type { MDXProviderComponents } from '@mdx-js/react';\n\nexport interface MDXLayoutProps extends React.HTMLAttributes<HTMLDivElement> {\n  children: ReactNode;\n  components?: MDXProviderComponents;\n}\n\n/** Arco flavored MDX theme */\nexport function MDXLayout({ children, components, className, ...rest }: MDXLayoutProps) {\n  const _components = useMemo(() => {\n    // add classname 'markdown-element' to these markdown elements\n    // then we can apply css styles to them\n    const tagNames: Array<keyof MDXProviderComponents> = [\n      'a',\n      'abbr',\n      'b',\n      'button',\n      'code',\n      'dfn',\n      'em',\n      'figure',\n      'hr',\n      'img',\n      'input',\n      'kbd',\n      'li',\n      'mark',\n      'ol',\n      'p',\n      'samp',\n      'small',\n      'span',\n      'strong',\n      'sub',\n      'summary',\n      'sup',\n      'table',\n      'td',\n      'th',\n      'tr',\n      'ul',\n    ];\n    const interExtendedComponents = {};\n\n    tagNames.forEach((tag) => {\n      if (typeof tag === 'string') {\n        interExtendedComponents[tag] = (props) => {\n          return React.createElement(tag, {\n            ...props,\n            className: classNames(props.className, 'a-md-element'),\n          });\n        };\n      }\n    });\n\n    return {\n      ...interExtendedComponents,\n      ...DEFAULT_MDX_COMPONENTS,\n      ...components,\n    };\n  }, [DEFAULT_MDX_COMPONENTS, components]);\n\n  return (\n    <MDXProvider components={_components}>\n      <div className={classNames(MARKDOWN_BODY_CLASSNAME, styles.mdxContent, className)} {...rest}>\n        {children}\n      </div>\n    </MDXProvider>\n  );\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/style/markdown-limit.css",
    "content": "/**\n * partially copied from markdown.css, only applies styles to elements with classname 'a-md-element'\n */\n.markdown-body {\n  margin: 0;\n  font-size: 14px;\n  line-height: 1.5;\n  word-wrap: break-word;\n  color: var(--preview-color-text-1);\n}\n\n.markdown-body::before {\n  display: table;\n  content: '';\n}\n\n.markdown-body::after {\n  display: table;\n  clear: both;\n  content: '';\n}\n\n.markdown-body > *:first-child {\n  margin-top: 0 !important;\n}\n\n.markdown-body > *:last-child {\n  margin-bottom: 0 !important;\n}\n\n.markdown-body .a-md-element[hidden] {\n  display: none !important;\n}\n\n.markdown-body a.a-md-element {\n  background-color: transparent;\n  color: var(--preview-color-primary);\n  text-decoration: none;\n}\n\n.markdown-body abbr.a-md-element[title] {\n  border-bottom: none;\n  text-decoration: underline dotted;\n}\n\n.markdown-body b.a-md-element,\n.markdown-body strong.a-md-element {\n  font-weight: 600;\n}\n\n.markdown-body dfn.a-md-element {\n  font-style: italic;\n}\n\n.markdown-body h1.a-md-element {\n  margin: 0.67em 0;\n  font-weight: 600;\n  padding-bottom: 0.3em;\n  font-size: 2em;\n}\n\n.markdown-body mark.a-md-element {\n  background-color: var(--preview-color-fill-1);\n  color: var(--preview-color-text-1);\n}\n\n.markdown-body small.a-md-element {\n  font-size: 90%;\n}\n\n.markdown-body sub.a-md-element,\n.markdown-body sup.a-md-element {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\n\n.markdown-body sub.a-md-element {\n  bottom: -0.25em;\n}\n\n.markdown-body sup.a-md-element {\n  top: -0.5em;\n}\n\n.markdown-body img.a-md-element {\n  border-style: none;\n  max-width: 100%;\n  box-sizing: content-box;\n  background-color: var(--preview-color-bg-1);\n}\n\n.markdown-body .a-md-element code,\n.markdown-body .a-md-element kbd,\n.markdown-body .a-md-element pre,\n.markdown-body .a-md-element samp {\n  font-family: monospace;\n  font-size: 1em;\n}\n\n.markdown-body figure.a-md-element {\n  margin: 1em 40px;\n}\n\n.markdown-body hr.a-md-element {\n  box-sizing: content-box;\n  overflow: hidden;\n  height: 0.25em;\n  padding: 0;\n  margin: 24px 0;\n  background-color: var(--preview-color-border);\n  border: 0;\n}\n\n.markdown-body input.a-md-element {\n  font: inherit;\n  margin: 0;\n  overflow: visible;\n  font-family: inherit;\n  font-size: inherit;\n  line-height: inherit;\n}\n\n.markdown-body .a-md-element[type='button'],\n.markdown-body .a-md-element[type='reset'],\n.markdown-body .a-md-element[type='submit'] {\n  -webkit-appearance: button;\n}\n\n.markdown-body .a-md-element[type='checkbox'],\n.markdown-body .a-md-element[type='radio'] {\n  box-sizing: border-box;\n  padding: 0;\n}\n\n.markdown-body .a-md-element[type='number']::-webkit-inner-spin-button,\n.markdown-body .a-md-element[type='number']::-webkit-outer-spin-button {\n  height: auto;\n}\n\n.markdown-body .a-md-element[type='search']::-webkit-search-cancel-button,\n.markdown-body .a-md-element[type='search']::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n\n.markdown-body hr.a-md-element::before {\n  display: table;\n  content: '';\n}\n\n.markdown-body hr.a-md-element::after {\n  display: table;\n  clear: both;\n  content: '';\n}\n\n.markdown-body table.a-md-element {\n  border-spacing: 0;\n  border-collapse: collapse;\n  display: block;\n  width: max-content;\n  max-width: 100%;\n  overflow: auto;\n}\n\n.markdown-body td.a-md-element,\n.markdown-body th.a-md-element {\n  padding: 0;\n}\n\n.markdown-body a.a-md-element:focus,\n.markdown-body .a-md-element[role='button']:focus,\n.markdown-body input[type='radio'].a-md-element:focus,\n.markdown-body input[type='checkbox'].a-md-element:focus {\n  outline: 2px solid var(--preview-color-primary);\n  outline-offset: -2px;\n  box-shadow: none;\n}\n\n.markdown-body a.a-md-element:focus:not(:focus-visible),\n.markdown-body .a-md-element[role='button']:focus:not(:focus-visible),\n.markdown-body input[type='radio'].a-md-element:focus:not(:focus-visible),\n.markdown-body input[type='checkbox'].a-md-element:focus:not(:focus-visible) {\n  outline: solid 1px transparent;\n}\n\n.markdown-body a.a-md-element:focus-visible,\n.markdown-body .a-md-element[role='button']:focus-visible,\n.markdown-body input[type='radio'].a-md-element:focus-visible,\n.markdown-body input[type='checkbox'].a-md-element:focus-visible {\n  outline: 2px solid var(--preview-color-primary);\n  outline-offset: -2px;\n  box-shadow: none;\n}\n\n.markdown-body a.a-md-element:not([class]):focus,\n.markdown-body a.a-md-element:not([class]):focus-visible,\n.markdown-body input.a-md-element[type='radio']:focus,\n.markdown-body input.a-md-element[type='radio']:focus-visible,\n.markdown-body input.a-md-element[type='checkbox']:focus,\n.markdown-body input.a-md-element[type='checkbox']:focus-visible {\n  outline-offset: 0;\n}\n\n.markdown-body kbd.a-md-element {\n  display: inline-block;\n  padding: 3px 5px;\n  font: 11px ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;\n  line-height: 10px;\n  color: var(--preview-color-text-1);\n  vertical-align: middle;\n  background-color: var(--preview-color-fill-1);\n  border: solid 1px var(--preview-color-border);\n  border-radius: 6px;\n}\n\n.markdown-body h1.a-md-element,\n.markdown-body h2.a-md-element,\n.markdown-body h3.a-md-element,\n.markdown-body h4.a-md-element,\n.markdown-body h5.a-md-element,\n.markdown-body h6.a-md-element {\n  margin-top: 24px;\n  margin-bottom: 16px;\n  font-weight: 600;\n  line-height: 1.25;\n}\n\n.markdown-body h2.a-md-element {\n  font-weight: 600;\n  padding-bottom: 0.3em;\n  font-size: 1.5em;\n}\n\n.markdown-body h3.a-md-element {\n  font-weight: 600;\n  font-size: 1.25em;\n}\n\n.markdown-body h4.a-md-element {\n  font-weight: 600;\n  font-size: 1em;\n}\n\n.markdown-body h5.a-md-element {\n  font-weight: 600;\n  font-size: 0.875em;\n}\n\n.markdown-body h6.a-md-element {\n  font-weight: 600;\n  font-size: 0.85em;\n  color: var(--preview-color-text-3);\n}\n\n.markdown-body p.a-md-element {\n  margin-top: 0;\n  margin-bottom: 10px;\n}\n\n.markdown-body blockquote.a-md-element {\n  margin: 0;\n  padding: 0 1em;\n  color: var(--preview-color-text-3);\n  border-left: 0.25em solid var(--preview-color-border);\n}\n\n.markdown-body ul.a-md-element,\n.markdown-body ol.a-md-element {\n  margin-top: 0;\n  margin-bottom: 0;\n  padding-left: 2em;\n}\n\n.markdown-body ol ol.a-md-element,\n.markdown-body ul ol.a-md-element {\n  list-style-type: lower-roman;\n}\n\n.markdown-body ul ul ol.a-md-element,\n.markdown-body ul ol ol.a-md-element,\n.markdown-body ol ul ol.a-md-element,\n.markdown-body ol ol ol.a-md-element {\n  list-style-type: lower-alpha;\n}\n\n.markdown-body dd.a-md-element {\n  margin-left: 0;\n}\n\n.markdown-body .a-md-element code,\n.markdown-body .a-md-element samp {\n  font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;\n  font-size: 12px;\n}\n\n.markdown-body pre.a-md-element {\n  margin-top: 0;\n  margin-bottom: 0;\n  font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;\n  font-size: 12px;\n  word-wrap: normal;\n}\n\n.markdown-body input.a-md-element::-webkit-outer-spin-button,\n.markdown-body input.a-md-element::-webkit-inner-spin-button {\n  margin: 0;\n  -webkit-appearance: none;\n  appearance: none;\n}\n\n.markdown-body a.a-md-element:not([href]) {\n  color: inherit;\n  text-decoration: none;\n}\n\n.markdown-body .a-md-element.absent {\n  color: var(--preview-color-danger);\n}\n\n.markdown-body .a-md-element.anchor {\n  float: left;\n  padding-right: 4px;\n  margin-left: -20px;\n  line-height: 1;\n}\n\n.markdown-body .a-md-element.anchor:focus {\n  outline: none;\n}\n\n.markdown-body p.a-md-element,\n.markdown-body blockquote.a-md-element,\n.markdown-body ul.a-md-element,\n.markdown-body ol.a-md-element,\n.markdown-body dl.a-md-element,\n.markdown-body table.a-md-element,\n.markdown-body pre.a-md-element {\n  margin-top: 0;\n  margin-bottom: 16px;\n}\n\n.markdown-body blockquote.a-md-element > :first-child {\n  margin-top: 0;\n}\n\n.markdown-body blockquote.a-md-element > :last-child {\n  margin-bottom: 0;\n}\n\n.markdown-body h1.a-md-element:hover .anchor,\n.markdown-body h2.a-md-element:hover .anchor,\n.markdown-body h3.a-md-element:hover .anchor,\n.markdown-body h4.a-md-element:hover .anchor,\n.markdown-body h5.a-md-element:hover .anchor,\n.markdown-body h6.a-md-element:hover .anchor {\n  text-decoration: none;\n}\n\n.markdown-body h1.a-md-element code,\n.markdown-body h2.a-md-element code,\n.markdown-body h3.a-md-element code,\n.markdown-body h4.a-md-element code,\n.markdown-body h5.a-md-element code,\n.markdown-body h6.a-md-element code {\n  padding: 0 0.2em;\n  font-size: inherit;\n}\n\n.markdown-body summary.a-md-element h1,\n.markdown-body summary.a-md-element h2,\n.markdown-body summary.a-md-element h3,\n.markdown-body summary.a-md-element h4,\n.markdown-body summary.a-md-element h5,\n.markdown-body summary.a-md-element h6 {\n  display: inline-block;\n}\n\n.markdown-body summary.a-md-element h1 .anchor,\n.markdown-body summary.a-md-element h2 .anchor,\n.markdown-body summary.a-md-element h3 .anchor,\n.markdown-body summary.a-md-element h4 .anchor,\n.markdown-body summary.a-md-element h5 .anchor,\n.markdown-body summary.a-md-element h6 .anchor {\n  margin-left: -40px;\n}\n\n.markdown-body summary.a-md-element h1,\n.markdown-body summary.a-md-element h2 {\n  padding-bottom: 0;\n  border-bottom: 0;\n}\n\n.markdown-body ul.no-list.a-md-element,\n.markdown-body ol.no-list.a-md-element {\n  padding: 0;\n  list-style-type: none;\n}\n\n.markdown-body ol.a-md-element[type='a'] {\n  list-style-type: lower-alpha;\n}\n\n.markdown-body ol.a-md-element[type='A'] {\n  list-style-type: upper-alpha;\n}\n\n.markdown-body ol.a-md-element[type='i'] {\n  list-style-type: lower-roman;\n}\n\n.markdown-body ol.a-md-element[type='I'] {\n  list-style-type: upper-roman;\n}\n\n.markdown-body ol.a-md-element[type='1'] {\n  list-style-type: decimal;\n}\n\n.markdown-body div > ol.a-md-element:not([type]) {\n  list-style-type: decimal;\n}\n\n.markdown-body ul.a-md-element ul,\n.markdown-body ul.a-md-element ol,\n.markdown-body ol.a-md-element ol,\n.markdown-body ol.a-md-element ul {\n  margin-top: 0;\n  margin-bottom: 0;\n}\n\n.markdown-body li.a-md-element > p {\n  margin-top: 16px;\n}\n\n.markdown-body li.a-md-element + li {\n  margin-top: 0.25em;\n}\n\n.markdown-body dl.a-md-element {\n  padding: 0;\n}\n\n.markdown-body dl dt.a-md-element {\n  padding: 0;\n  margin-top: 16px;\n  font-size: 1em;\n  font-style: italic;\n  font-weight: 600;\n}\n\n.markdown-body dl dd.a-md-element {\n  padding: 0 16px;\n  margin-bottom: 16px;\n}\n\n.markdown-body table.a-md-element th {\n  font-weight: 600;\n}\n\n.markdown-body table.a-md-element th,\n.markdown-body table.a-md-element td {\n  padding: 6px 13px;\n  border: 1px solid var(--preview-color-border);\n}\n\n.markdown-body table.a-md-element tr {\n  background-color: var(--preview-color-bg-1);\n  border-top: 1px solid var(--preview-color-border);\n}\n\n.markdown-body table.a-md-element tr:nth-child(2n) {\n  background-color: var(--preview-color-fill-1);\n}\n\n.markdown-body table.a-md-element img {\n  background-color: transparent;\n}\n\n.markdown-body img.a-md-element[align='right'] {\n  padding-left: 20px;\n}\n\n.markdown-body img.a-md-element[align='left'] {\n  padding-right: 20px;\n}\n\n.markdown-body .emoji.a-md-element {\n  max-width: none;\n  vertical-align: text-top;\n  background-color: transparent;\n}\n\n.markdown-body span.frame.a-md-element {\n  display: block;\n  overflow: hidden;\n}\n\n.markdown-body span.frame.a-md-element > span {\n  display: block;\n  float: left;\n  width: auto;\n  padding: 7px;\n  margin: 13px 0 0;\n  overflow: hidden;\n  border: 1px solid var(--preview-color-border);\n}\n\n.markdown-body span.frame.a-md-element span img {\n  display: block;\n  float: left;\n}\n\n.markdown-body span.frame.a-md-element span span {\n  display: block;\n  padding: 5px 0 0;\n  clear: both;\n  color: var(--preview-color-text-1);\n}\n\n.markdown-body span.align-center.a-md-element {\n  display: block;\n  overflow: hidden;\n  clear: both;\n}\n\n.markdown-body span.align-center.a-md-element > span {\n  display: block;\n  margin: 13px auto 0;\n  overflow: hidden;\n  text-align: center;\n}\n\n.markdown-body span.align-center.a-md-element span img {\n  margin: 0 auto;\n  text-align: center;\n}\n\n.markdown-body span.align-right.a-md-element {\n  display: block;\n  overflow: hidden;\n  clear: both;\n}\n\n.markdown-body span.align-right.a-md-element > span {\n  display: block;\n  margin: 13px 0 0;\n  overflow: hidden;\n  text-align: right;\n}\n\n.markdown-body span.align-right.a-md-element span img {\n  margin: 0;\n  text-align: right;\n}\n\n.markdown-body span.float-left.a-md-element {\n  display: block;\n  float: left;\n  margin-right: 13px;\n  overflow: hidden;\n}\n\n.markdown-body span.float-left.a-md-element span {\n  margin: 13px 0 0;\n}\n\n.markdown-body span.float-right.a-md-element {\n  display: block;\n  float: right;\n  margin-left: 13px;\n  overflow: hidden;\n}\n\n.markdown-body span.float-right.a-md-element > span {\n  display: block;\n  margin: 13px auto 0;\n  overflow: hidden;\n  text-align: right;\n}\n\n.markdown-body .a-md-element code {\n  padding: 0.2em 0.4em;\n  margin: 0;\n  font-size: 85%;\n  white-space: break-spaces;\n  background-color: var(--preview-color-fill-1);\n  border-radius: 4px;\n}\n\n.markdown-body .a-md-element code br {\n  display: none;\n}\n\n.markdown-body del.a-md-element code {\n  text-decoration: inherit;\n}\n\n.markdown-body samp.a-md-element {\n  font-size: 85%;\n}\n\n.markdown-body .highlight.a-md-element {\n  margin-bottom: 16px;\n}\n\n.markdown-body .csv-data td.a-md-element,\n.markdown-body .csv-data th.a-md-element {\n  padding: 5px;\n  overflow: hidden;\n  font-size: 12px;\n  line-height: 1;\n  text-align: left;\n  white-space: nowrap;\n}\n\n.markdown-body .csv-data .blob-num.a-md-element {\n  padding: 10px 8px 9px;\n  text-align: right;\n  background: var(--preview-color-bg-1);\n  border: 0;\n}\n\n.markdown-body .csv-data tr.a-md-element {\n  border-top: 0;\n}\n\n.markdown-body .csv-data th.a-md-element {\n  font-weight: 600;\n  background: var(--preview-color-fill-1);\n  border-top: 0;\n}\n\n.markdown-body .task-list-item.a-md-element {\n  list-style-type: none;\n}\n\n.markdown-body .task-list-item.a-md-element label {\n  font-weight: 400;\n}\n\n.markdown-body .task-list-item.enabled.a-md-element label {\n  cursor: pointer;\n}\n\n.markdown-body .task-list-item.a-md-element + .task-list-item {\n  margin-top: 4px;\n}\n\n.markdown-body .task-list-item.a-md-element .handle {\n  display: none;\n}\n\n.markdown-body .task-list-item-checkbox.a-md-element {\n  margin: 0 0.2em 0.25em -1.4em;\n  vertical-align: middle;\n}\n\n.markdown-body .contains-task-list:dir(rtl) .task-list-item-checkbox.a-md-element {\n  margin: 0 -1.6em 0.25em 0.2em;\n}\n\n.markdown-body .contains-task-list.a-md-element {\n  position: relative;\n}\n\n.markdown-body .contains-task-list.a-md-element:hover .task-list-item-convert-container,\n.markdown-body .contains-task-list.a-md-element:focus-within .task-list-item-convert-container {\n  display: block;\n  width: auto;\n  height: 24px;\n  overflow: visible;\n  clip: auto;\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/style/markdown.css",
    "content": ".markdown-body {\n  margin: 0;\n  font-size: 14px;\n  line-height: 1.5;\n  word-wrap: break-word;\n  color: var(--preview-color-text-1);\n}\n\n.markdown-body::before {\n  display: table;\n  content: '';\n}\n\n.markdown-body::after {\n  display: table;\n  clear: both;\n  content: '';\n}\n\n.markdown-body > *:first-child {\n  margin-top: 0 !important;\n}\n\n.markdown-body > *:last-child {\n  margin-bottom: 0 !important;\n}\n\n.markdown-body [hidden] {\n  display: none !important;\n}\n\n.markdown-body a {\n  background-color: transparent;\n  color: var(--preview-color-primary);\n  text-decoration: none;\n}\n\n.markdown-body abbr[title] {\n  border-bottom: none;\n  text-decoration: underline dotted;\n}\n\n.markdown-body b,\n.markdown-body strong {\n  font-weight: 600;\n}\n\n.markdown-body dfn {\n  font-style: italic;\n}\n\n.markdown-body mark {\n  background-color: var(--preview-color-fill-1);\n  color: var(--preview-color-text-1);\n}\n\n.markdown-body small {\n  font-size: 90%;\n}\n\n.markdown-body sub,\n.markdown-body sup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\n\n.markdown-body sub {\n  bottom: -0.25em;\n}\n\n.markdown-body sup {\n  top: -0.5em;\n}\n\n.markdown-body img {\n  border-style: none;\n  max-width: 100%;\n  box-sizing: content-box;\n  background-color: var(--preview-color-bg-1);\n}\n\n.markdown-body code,\n.markdown-body kbd,\n.markdown-body pre,\n.markdown-body samp {\n  font-family: monospace;\n  font-size: 1em;\n}\n\n.markdown-body figure {\n  margin: 1em 40px;\n}\n\n.markdown-body hr {\n  box-sizing: content-box;\n  overflow: hidden;\n  height: 0.25em;\n  padding: 0;\n  margin: 24px 0;\n  background-color: var(--preview-color-fill-1);\n  border: 0;\n}\n\n.markdown-body input {\n  font: inherit;\n  margin: 0;\n  overflow: visible;\n  font-family: inherit;\n  font-size: inherit;\n  line-height: inherit;\n}\n\n.markdown-body [type='button'],\n.markdown-body [type='reset'],\n.markdown-body [type='submit'] {\n  -webkit-appearance: button;\n}\n\n.markdown-body [type='checkbox'],\n.markdown-body [type='radio'] {\n  box-sizing: border-box;\n  padding: 0;\n}\n\n.markdown-body [type='number']::-webkit-inner-spin-button,\n.markdown-body [type='number']::-webkit-outer-spin-button {\n  height: auto;\n}\n\n.markdown-body [type='search']::-webkit-search-cancel-button,\n.markdown-body [type='search']::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n\n.markdown-body ::-webkit-input-placeholder {\n  color: inherit;\n  opacity: 0.54;\n}\n\n.markdown-body ::-webkit-file-upload-button {\n  -webkit-appearance: button;\n  font: inherit;\n}\n\n.markdown-body ::placeholder {\n  color: var(--preview-color-text-3);\n  opacity: 1;\n}\n\n.markdown-body hr::before {\n  display: table;\n  content: '';\n}\n\n.markdown-body hr::after {\n  display: table;\n  clear: both;\n  content: '';\n}\n\n.markdown-body table {\n  border-spacing: 0;\n  border-collapse: collapse;\n  display: block;\n  width: max-content;\n  max-width: 100%;\n  overflow: auto;\n}\n\n.markdown-body td,\n.markdown-body th {\n  padding: 0;\n}\n\n.markdown-body a:focus,\n.markdown-body [role='button']:focus,\n.markdown-body input[type='radio']:focus,\n.markdown-body input[type='checkbox']:focus {\n  outline: 2px solid var(--preview-color-primary);\n  outline-offset: -2px;\n  box-shadow: none;\n}\n\n.markdown-body a:focus:not(:focus-visible),\n.markdown-body [role='button']:focus:not(:focus-visible),\n.markdown-body input[type='radio']:focus:not(:focus-visible),\n.markdown-body input[type='checkbox']:focus:not(:focus-visible) {\n  outline: solid 1px transparent;\n}\n\n.markdown-body a:focus-visible,\n.markdown-body [role='button']:focus-visible,\n.markdown-body input[type='radio']:focus-visible,\n.markdown-body input[type='checkbox']:focus-visible {\n  outline: 2px solid var(--preview-color-primary);\n  outline-offset: -2px;\n  box-shadow: none;\n}\n\n.markdown-body a:not([class]):focus,\n.markdown-body a:not([class]):focus-visible,\n.markdown-body input[type='radio']:focus,\n.markdown-body input[type='radio']:focus-visible,\n.markdown-body input[type='checkbox']:focus,\n.markdown-body input[type='checkbox']:focus-visible {\n  outline-offset: 0;\n}\n\n.markdown-body kbd {\n  display: inline-block;\n  padding: 3px 5px;\n  font: 11px ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;\n  line-height: 10px;\n  color: #24292f;\n  vertical-align: middle;\n  background-color: #f6f8fa;\n  border: solid 1px var(--preview-color-border);\n  border-radius: 6px;\n}\n\n.markdown-body p {\n  margin-top: 0;\n  margin-bottom: 10px;\n}\n\n.markdown-body blockquote {\n  margin: 0;\n  padding: 0 1em;\n  color: var(--preview-color-text-3);\n  border-left: 0.25em solid var(--preview-color-border);\n}\n\n.markdown-body ul,\n.markdown-body ol {\n  margin-top: 0;\n  margin-bottom: 0;\n  padding-left: 2em;\n}\n\n.markdown-body ol ol,\n.markdown-body ul ol {\n  list-style-type: lower-roman;\n}\n\n.markdown-body ul ul ol,\n.markdown-body ul ol ol,\n.markdown-body ol ul ol,\n.markdown-body ol ol ol {\n  list-style-type: lower-alpha;\n}\n\n.markdown-body dd {\n  margin-left: 0;\n}\n\n.markdown-body code,\n.markdown-body samp {\n  font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;\n  font-size: 12px;\n}\n\n.markdown-body pre {\n  margin-top: 0;\n  margin-bottom: 0;\n  font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;\n  font-size: 12px;\n  word-wrap: normal;\n}\n\n.markdown-body input::-webkit-outer-spin-button,\n.markdown-body input::-webkit-inner-spin-button {\n  margin: 0;\n  appearance: none;\n}\n\n.markdown-body a:not([href]) {\n  color: inherit;\n  text-decoration: none;\n}\n\n.markdown-body .absent {\n  color: var(--preview-color-danger);\n}\n\n.markdown-body .anchor {\n  float: left;\n  padding-right: 4px;\n  margin-left: -20px;\n  line-height: 1;\n}\n\n.markdown-body .anchor:focus {\n  outline: none;\n}\n\n.markdown-body p,\n.markdown-body blockquote,\n.markdown-body ul,\n.markdown-body ol,\n.markdown-body dl,\n.markdown-body table,\n.markdown-body pre {\n  margin-top: 0;\n  margin-bottom: 16px;\n}\n\n.markdown-body blockquote > :first-child {\n  margin-top: 0;\n}\n\n.markdown-body blockquote > :last-child {\n  margin-bottom: 0;\n}\n\n.markdown-body h1:hover .anchor,\n.markdown-body h2:hover .anchor,\n.markdown-body h3:hover .anchor,\n.markdown-body h4:hover .anchor,\n.markdown-body h5:hover .anchor,\n.markdown-body h6:hover .anchor {\n  text-decoration: none;\n}\n\n.markdown-body h1 code,\n.markdown-body h2 code,\n.markdown-body h3 code,\n.markdown-body h4 code,\n.markdown-body h5 code,\n.markdown-body h6 code {\n  padding: 0 0.2em;\n  font-size: inherit;\n}\n\n.markdown-body summary h1,\n.markdown-body summary h2,\n.markdown-body summary h3,\n.markdown-body summary h4,\n.markdown-body summary h5,\n.markdown-body summary h6 {\n  display: inline-block;\n}\n\n.markdown-body summary h1 .anchor,\n.markdown-body summary h2 .anchor,\n.markdown-body summary h3 .anchor,\n.markdown-body summary h4 .anchor,\n.markdown-body summary h5 .anchor,\n.markdown-body summary h6 .anchor {\n  margin-left: -40px;\n}\n\n.markdown-body summary h1,\n.markdown-body summary h2 {\n  padding-bottom: 0;\n  border-bottom: 0;\n}\n\n.markdown-body ul.no-list,\n.markdown-body ol.no-list {\n  padding: 0;\n  list-style-type: none;\n}\n\n.markdown-body ol[type='a'] {\n  list-style-type: lower-alpha;\n}\n\n.markdown-body ol[type='A'] {\n  list-style-type: upper-alpha;\n}\n\n.markdown-body ol[type='i'] {\n  list-style-type: lower-roman;\n}\n\n.markdown-body ol[type='I'] {\n  list-style-type: upper-roman;\n}\n\n.markdown-body ol[type='1'] {\n  list-style-type: decimal;\n}\n\n.markdown-body div > ol:not([type]) {\n  list-style-type: decimal;\n}\n\n.markdown-body ul ul,\n.markdown-body ul ol,\n.markdown-body ol ol,\n.markdown-body ol ul {\n  margin-top: 0;\n  margin-bottom: 0;\n}\n\n.markdown-body li > p {\n  margin-top: 16px;\n}\n\n.markdown-body li + li {\n  margin-top: 0.25em;\n}\n\n.markdown-body dl {\n  padding: 0;\n}\n\n.markdown-body dl dt {\n  padding: 0;\n  margin-top: 16px;\n  font-size: 1em;\n  font-style: italic;\n  font-weight: 600;\n}\n\n.markdown-body dl dd {\n  padding: 0 16px;\n  margin-bottom: 16px;\n}\n\n.markdown-body table th {\n  font-weight: 600;\n}\n\n.markdown-body table th,\n.markdown-body table td {\n  padding: 6px 13px;\n  border: 1px solid var(--preview-color-border);\n}\n\n.markdown-body table tr {\n  background-color: var(--preview-color-bg-1);\n  border-top: 1px solid var(--preview-color-border);\n}\n\n.markdown-body table tr:nth-child(2n) {\n  background-color: var(--preview-color-fill-1);\n}\n\n.markdown-body table img {\n  background-color: transparent;\n}\n\n.markdown-body img[align='right'] {\n  padding-left: 20px;\n}\n\n.markdown-body img[align='left'] {\n  padding-right: 20px;\n}\n\n.markdown-body .emoji {\n  max-width: none;\n  vertical-align: text-top;\n  background-color: transparent;\n}\n\n.markdown-body span.frame {\n  display: block;\n  overflow: hidden;\n}\n\n.markdown-body span.frame > span {\n  display: block;\n  float: left;\n  width: auto;\n  padding: 7px;\n  margin: 13px 0 0;\n  overflow: hidden;\n  border: 1px solid var(--preview-color-border);\n}\n\n.markdown-body span.frame span img {\n  display: block;\n  float: left;\n}\n\n.markdown-body span.frame span span {\n  display: block;\n  padding: 5px 0 0;\n  clear: both;\n  color: var(--preview-color-text-1);\n}\n\n.markdown-body span.align-center {\n  display: block;\n  overflow: hidden;\n  clear: both;\n}\n\n.markdown-body span.align-center > span {\n  display: block;\n  margin: 13px auto 0;\n  overflow: hidden;\n  text-align: center;\n}\n\n.markdown-body span.align-center span img {\n  margin: 0 auto;\n  text-align: center;\n}\n\n.markdown-body span.align-right {\n  display: block;\n  overflow: hidden;\n  clear: both;\n}\n\n.markdown-body span.align-right > span {\n  display: block;\n  margin: 13px 0 0;\n  overflow: hidden;\n  text-align: right;\n}\n\n.markdown-body span.align-right span img {\n  margin: 0;\n  text-align: right;\n}\n\n.markdown-body span.float-left {\n  display: block;\n  float: left;\n  margin-right: 13px;\n  overflow: hidden;\n}\n\n.markdown-body span.float-left span {\n  margin: 13px 0 0;\n}\n\n.markdown-body span.float-right {\n  display: block;\n  float: right;\n  margin-left: 13px;\n  overflow: hidden;\n}\n\n.markdown-body span.float-right > span {\n  display: block;\n  margin: 13px auto 0;\n  overflow: hidden;\n  text-align: right;\n}\n\n.markdown-body code {\n  padding: 0.2em 0.4em;\n  margin: 0;\n  font-size: 85%;\n  white-space: break-spaces;\n  background-color: var(--preview-color-fill-1);\n  border-radius: 6px;\n}\n\n.markdown-body code br {\n  display: none;\n}\n\n.markdown-body del code {\n  text-decoration: inherit;\n}\n\n.markdown-body samp {\n  font-size: 85%;\n}\n\n.markdown-body pre code {\n  font-size: 100%;\n}\n\n.markdown-body pre > code {\n  padding: 0;\n  margin: 0;\n  word-break: normal;\n  white-space: pre;\n  background: transparent;\n  border: 0;\n}\n\n.markdown-body .highlight {\n  margin-bottom: 16px;\n}\n\n.markdown-body .highlight pre {\n  margin-bottom: 0;\n  word-break: normal;\n}\n\n.markdown-body .highlight pre,\n.markdown-body pre {\n  overflow: auto;\n  font-size: 85%;\n  line-height: 1.45;\n}\n\n.markdown-body pre code {\n  display: inline;\n  max-width: unset;\n  padding: 0;\n  margin: 0;\n  overflow: visible;\n  line-height: inherit;\n  word-wrap: normal;\n  background-color: transparent;\n  border: 0;\n}\n\n.markdown-body .csv-data td,\n.markdown-body .csv-data th {\n  padding: 5px;\n  overflow: hidden;\n  font-size: 12px;\n  line-height: 1;\n  text-align: left;\n  white-space: nowrap;\n}\n\n.markdown-body .csv-data .blob-num {\n  padding: 10px 8px 9px;\n  text-align: right;\n  background: var(--preview-color-bg-1);\n  border: 0;\n}\n\n.markdown-body .csv-data tr {\n  border-top: 0;\n}\n\n.markdown-body .csv-data th {\n  font-weight: 600;\n  background: var(--preview-color-fill-1);\n  border-top: 0;\n}\n\n.markdown-body .task-list-item {\n  list-style-type: none;\n}\n\n.markdown-body .task-list-item label {\n  font-weight: 400;\n}\n\n.markdown-body .task-list-item.enabled label {\n  cursor: pointer;\n}\n\n.markdown-body .task-list-item + .task-list-item {\n  margin-top: 4px;\n}\n\n.markdown-body .task-list-item .handle {\n  display: none;\n}\n\n.markdown-body .task-list-item-checkbox {\n  margin: 0 0.2em 0.25em -1.4em;\n  vertical-align: middle;\n}\n\n.markdown-body .contains-task-list:dir(rtl) .task-list-item-checkbox {\n  margin: 0 -1.6em 0.25em 0.2em;\n}\n\n.markdown-body .contains-task-list {\n  position: relative;\n}\n\n.markdown-body .contains-task-list:hover .task-list-item-convert-container,\n.markdown-body .contains-task-list:focus-within .task-list-item-convert-container {\n  display: block;\n  width: auto;\n  height: 24px;\n  overflow: visible;\n  clip: auto;\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/markdown/style/variable.scss",
    "content": "$doc-anchor-width: 180px;\n"
  },
  {
    "path": "packages/ui-foundation-react/src/navbar/index.ts",
    "content": "export { Navbar } from './navbar';\nexport type { NavbarProps } from './navbar';\n"
  },
  {
    "path": "packages/ui-foundation-react/src/navbar/navbar.module.scss",
    "content": "@import '../style/z-indexes';\n\n$navbar-height: 60px;\n\n.navbar {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  height: $navbar-height;\n  padding: 0 12px;\n  box-sizing: border-box;\n  border-bottom: 1px solid var(--preview-color-border);\n  font-size: var(--preview-font-size-title-1);\n  z-index: $navbar-z-index;\n\n  .title {\n    display: flex;\n    align-items: center;\n    max-width: 320px;\n    font-size: var(--preview-font-size-title-2);\n    font-weight: 600;\n    color: var(--preview-color-text-1);\n\n    .logo {\n      height: 24px;\n      margin-right: 8px;\n      flex-shrink: 0;\n    }\n\n    .text {\n      width: 100%;\n      overflow: hidden;\n      white-space: nowrap;\n      text-overflow: ellipsis;\n    }\n  }\n\n  .right {\n    display: flex;\n    align-items: center;\n\n    .darkModeSwitcher {\n      margin-right: 12px;\n      background-color: var(--preview-color-fill-4) !important;\n\n      &:global(.arco-switch-checked .arco-switch-text) {\n        color: rgb(249 204 68);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/navbar/navbar.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { HTMLAttributes, ReactNode, useContext } from 'react';\nimport cn from 'classnames';\nimport type { RouteProps } from 'react-router-dom';\nimport { Button, Switch } from '@arco-design/web-react';\nimport { IconMoonFill, IconSunFill } from '@arco-design/web-react/icon';\nimport { SlotRouter } from '@arco-cli/aspect/dist/react-router/uiRuntime';\n\nimport { WorkspaceContext } from '../workspaceContext';\nimport { BASE_DOCS_DOMAIN } from '../constants';\n\nimport Logo from './asset/arco-material-logo.svg';\nimport styles from './navbar.module.scss';\n\nexport interface NavbarProps extends Omit<HTMLAttributes<HTMLDivElement>, 'className' | 'title'> {\n  className?: string | string[];\n  title?: ReactNode;\n  // route for registering menus to the top-bar.\n  menu?: RouteProps[];\n}\n\n/**\n * Top bar with corner and contextual menu.\n */\nexport function Navbar({ menu = [], className, title }: NavbarProps) {\n  const { darkMode, setDarkMode } = useContext(WorkspaceContext);\n\n  return (\n    <div className={cn(styles.navbar, className)}>\n      <div>\n        <div className={styles.title}>\n          <Logo className={styles.logo} />\n          <span className={styles.text}>{title}</span>\n        </div>\n        <SlotRouter routes={menu} />\n      </div>\n      <div className={styles.right}>\n        <Switch\n          className={styles.darkModeSwitcher}\n          checkedText={<IconSunFill />}\n          uncheckedText={<IconMoonFill />}\n          checked={darkMode}\n          onChange={setDarkMode}\n        />\n        <Button type=\"primary\" target=\"_blank\" href={`https://${BASE_DOCS_DOMAIN}`}>\n          Get Started\n        </Button>\n      </div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/pages/contactFooter.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { HTMLAttributes } from 'react';\nimport { Button } from '@arco-design/web-react';\n\nimport styles from './style/contactFooter.module.scss';\n\nexport type ContactFooterProps = HTMLAttributes<HTMLDivElement>;\n\nexport function ContactFooter({ style, ...rest }: ContactFooterProps) {\n  return (\n    <div className={styles.contactFooter} style={style} {...rest}>\n      <Button className={styles.btn} type=\"primary\" href=\"https://arco.design/material\">\n        Material Market\n      </Button>\n      <Button className={styles.btn} type=\"primary\" href=\"https://github.com/arco-design/arco-cli\">\n        Github\n      </Button>\n    </div>\n  );\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/pages/errorPage.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { CSSProperties } from 'react';\nimport Image404 from './assets/404.svg';\n\nimport styles from './style/errorPage.module.scss';\n\ntype ErrorPageProps = {\n  /**\n   * specifies the type of error that was encountered\n   */\n  code: number;\n  /**\n   * title to be shown above the error image\n   */\n  title?: string;\n  /**\n   * style of this page\n   */\n  style?: CSSProperties;\n} & React.HTMLAttributes<HTMLDivElement>;\n\n/**\n * A component that shows an error page according to the error code\n */\nexport function ErrorPage({ code, title, style, children, ...rest }: ErrorPageProps) {\n  return (\n    <div {...rest} className={styles.errorPage} style={style}>\n      {code === 404 ? <Image404 /> : null}\n      <h1 className={styles.title}>{title}</h1>\n      {children}\n    </div>\n  );\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/pages/index.ts",
    "content": "export { ContactFooter } from './contactFooter';\nexport { ErrorPage } from './errorPage';\nexport { NotFoundPage } from './notFoundPage';\n"
  },
  {
    "path": "packages/ui-foundation-react/src/pages/notFoundPage.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React from 'react';\nimport { ErrorPage } from './errorPage';\nimport { ContactFooter } from './contactFooter';\n\nexport type NotFoundPageProps = React.HTMLAttributes<HTMLDivElement>;\n\nexport function NotFoundPage({ ...rest }: NotFoundPageProps) {\n  return (\n    <ErrorPage {...rest} code={404} title=\"Page Not Found\">\n      <ContactFooter />\n    </ErrorPage>\n  );\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/pages/style/contactFooter.module.scss",
    "content": ".contactFooter {\n  .btn {\n    margin: 0 12px;\n  }\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/pages/style/errorPage.module.scss",
    "content": ".errorPage {\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n  height: 70vh;\n  margin: auto;\n  padding: 24px;\n  text-align: center;\n\n  .title {\n    margin: 24px 0 16px;\n    font-size: var(--preview-font-size-title-1);\n    font-weight: 600;\n  }\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/preview/SlotRegister.ts",
    "content": "export class SlotRegister<T = any> {\n  constructor(readonly map = new Map<string, T>()) {}\n\n  get(id: string) {\n    return this.map.get(id);\n  }\n\n  toArray() {\n    return Array.from(this.map.entries());\n  }\n\n  values() {\n    return Array.from(this.map.values());\n  }\n\n  unregister(id: string) {\n    this.map.delete(id);\n  }\n\n  register(cb: T) {\n    const id = Math.random().toFixed(8).slice(2);\n    this.map.set(id, cb);\n    return () => this.unregister(id);\n  }\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/preview/app.module.scss",
    "content": ":global(html),\n:global(body) {\n  margin: 0;\n  padding: 0;\n  overflow: auto;\n\n  :global(*) {\n    box-sizing: border-box;\n  }\n}\n\n.emptyWarning {\n  padding: 20px 26px;\n  border-left: 9px solid #fbe842;\n  background: #fefebe;\n  line-height: 1.5;\n  color: var(--preview-color-text-1);\n\n  .title {\n    margin-top: 0;\n    margin-bottom: 6px;\n    font-size: var(--preview-font-size-title-1);\n    font-weight: 600;\n  }\n\n  .details {\n    font-size: var(--preview-font-size-body-3);\n  }\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/preview/app.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { Fragment, useEffect, useMemo } from 'react';\n// import debounce from lodash-es/debounce to enable tree-shaking\nimport debounce from 'lodash-es/debounce';\nimport type { DocsRootProps } from '@arco-cli/aspect/dist/docs/previewRuntime';\nimport { Pubsub } from '@arco-cli/aspect/dist/pubsub/previewRuntime';\n\nimport { MDXLayout } from '../markdown/mdxLayout';\nimport { Theme } from './theme';\nimport { Content as DocContent } from './doc/content';\nimport { PropertiesTable } from './doc/propertiesTable';\nimport { DocAnchor } from '../markdown/components/docAnchor';\nimport { PreviewContextProvider } from './previewContext';\nimport { VALID_MESSAGE_TYPE_FROM_PARENT_WINDOW } from '../constants';\nimport { SlotRegister } from './SlotRegister';\n\nimport '../style/colors.scss';\nimport styles from './app.module.scss';\n\nexport function App({ doc, metadata, docContextProvider }: DocsRootProps) {\n  const { doclets, apiPlaceholderElementId } = metadata || {};\n  const isEmpty = !doc && (!doclets || (Array.isArray(doclets) && doclets.length === 0));\n  const ContextProvider = typeof docContextProvider === 'function' ? docContextProvider : Fragment;\n\n  const userEventListenerSlots = useMemo<\n    Record<string, SlotRegister<(event: { type: string; data: any }) => void>>\n  >(() => {\n    const slots = {};\n\n    Object.values(VALID_MESSAGE_TYPE_FROM_PARENT_WINDOW).forEach((type) => {\n      slots[type] = new SlotRegister();\n    });\n\n    (window as any).__registerArcoPreviewEventListener = (\n      event: VALID_MESSAGE_TYPE_FROM_PARENT_WINDOW,\n      handler: () => void\n    ) => {\n      return slots[event]?.register(handler);\n    };\n\n    return slots;\n  }, []);\n\n  const { pubsub, pubsubTopic, pubsubTopicParent } = useMemo(() => {\n    const pubsub = new Pubsub();\n    const pubsubTopic = 'preview';\n    const pubsubTopicParent = 'preview-host';\n\n    try {\n      // in iframe\n      if (typeof window !== 'undefined' && window.self !== window.top) {\n        new ResizeObserver(\n          debounce(() => {\n            pubsub.reportSize(pubsubTopic, {\n              width: window.document.body.offsetWidth,\n              height: window.document.body.offsetHeight,\n            });\n          }, 300)\n        ).observe(document.body);\n\n        window.addEventListener('hashchange', () => {\n          pubsub.reportLocationHash(pubsubTopic, { hash: window.location.hash });\n        });\n      }\n    } catch (err) {}\n\n    return { pubsub, pubsubTopic, pubsubTopicParent };\n  }, []);\n\n  useEffect(() => {\n    pubsub?.sub(pubsubTopicParent, (message) => {\n      const { type, data } = message;\n      switch (type) {\n        case VALID_MESSAGE_TYPE_FROM_PARENT_WINDOW.switchDarkMode: {\n          const body = document.body;\n          data.dark ? body.setAttribute('arco-theme', 'dark') : body.removeAttribute('arco-theme');\n          break;\n        }\n        case VALID_MESSAGE_TYPE_FROM_PARENT_WINDOW.appendExtraStyle: {\n          const eleClassName = '__arco-component-extra-style';\n          // clear all append styles at first\n          document\n            .querySelectorAll(`.${eleClassName}`)\n            .forEach((node) => document.body.removeChild(node));\n          // insert new stylesheet\n          if (data.href) {\n            const styleEle = document.createElement('link');\n            styleEle.setAttribute('class', eleClassName);\n            styleEle.setAttribute('type', 'text/css');\n            styleEle.setAttribute('rel', 'stylesheet');\n            styleEle.setAttribute('href', data.href);\n            document.body?.prepend(styleEle);\n          }\n          break;\n        }\n        case VALID_MESSAGE_TYPE_FROM_PARENT_WINDOW.scrollIntoView: {\n          const { selector, options } = data;\n          if (selector) {\n            document.body.querySelector(selector)?.scrollIntoView(options);\n          }\n          break;\n        }\n        default:\n          break;\n      }\n\n      if (Object.values(VALID_MESSAGE_TYPE_FROM_PARENT_WINDOW).indexOf(type as any) > -1) {\n        userEventListenerSlots[type]?.values().forEach((callback) => {\n          callback(message);\n        });\n      }\n    });\n  }, [pubsub]);\n\n  return (\n    <PreviewContextProvider\n      pubsub={pubsub}\n      pubsubTopic={pubsubTopic}\n      pubsubTopicParent={pubsubTopicParent}\n    >\n      <Theme>\n        <MDXLayout>\n          {isEmpty ? (\n            <div className={styles.emptyWarning}>\n              <div className={styles.title}>No valid component overview found.</div>\n              <div className={styles.details}>\n                Please check your component [entries.preview] config in [arco.workspace.jsonc].\n              </div>\n            </div>\n          ) : (\n            <ContextProvider>\n              <DocContent doc={doc} />\n              <PropertiesTable doclet={doclets as any} placeholderID={apiPlaceholderElementId} />\n              <DocAnchor />\n            </ContextProvider>\n          )}\n        </MDXLayout>\n      </Theme>\n    </PreviewContextProvider>\n  );\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/preview/doc/content.module.scss",
    "content": ".errorBoundary {\n  padding: 20px 26px;\n  border-left: 9px solid #ed3315;\n  background: rgb(237 51 21 / 20%);\n  color: var(--preview-color-text-1);\n\n  .title {\n    margin-top: 0;\n    margin-bottom: 6px;\n    font-size: var(--preview-font-size-title-1);\n    font-weight: 600;\n  }\n\n  .details {\n    margin: 0;\n    padding: 1em 0;\n    font-size: var(--preview-font-size-body-3);\n    overflow: auto;\n  }\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/preview/doc/content.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { ComponentType } from 'react';\nimport { ErrorBoundary } from 'react-error-boundary';\n\nimport { CLASSNAME_MARKDOWN_CONTENT } from '../../constants';\n\nimport styles from './content.module.scss';\n\ninterface DocsContentProps {\n  doc?: ComponentType;\n}\n\nfunction ErrorFallback({ error }: { error: Error }) {\n  return (\n    <div className={styles.errorBoundary} role=\"alert\">\n      <p className={styles.title}>Failed to render. Something went wrong:</p>\n      <pre className={styles.details}>{error.message}</pre>\n    </div>\n  );\n}\n\nexport function Content({ doc }: DocsContentProps) {\n  const Content: any = typeof doc === 'function' ? doc : () => null;\n  return (\n    <ErrorBoundary FallbackComponent={ErrorFallback}>\n      <div className={CLASSNAME_MARKDOWN_CONTENT}>\n        <Content />\n      </div>\n    </ErrorBoundary>\n  );\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/preview/doc/propertiesTable.module.scss",
    "content": ".propertiesTable {\n  .table:not(:last-child) {\n    margin-bottom: 36px;\n  }\n\n  .tableTitle {\n    margin: 0 0 12px;\n  }\n\n  .highlightCodes {\n    font-size: var(--preview-font-size-body-1);\n  }\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/preview/doc/propertiesTable.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { ReactNode, useEffect, useMemo, useRef, useState } from 'react';\n// eslint-disable-next-line import/no-extraneous-dependencies\nimport { createPortal } from 'react-dom';\nimport type { Doclet } from '@arco-cli/legacy/dist/types';\n\nimport { Table } from '../../baseUI/table';\nimport { CodeSnippet } from '../../markdown/components/snippet/codeSnippet';\n\nimport styles from './propertiesTable.module.scss';\n\ntype AnchorInfo = { depth: number; text: string };\n\ninterface PropertiesTableProps {\n  doclet: Doclet[];\n  placeholderID?: string;\n}\n\nexport function PropertiesTable({ doclet, placeholderID }: PropertiesTableProps) {\n  const [, forceUpdate] = useState(0);\n  const refPortal = useRef(null);\n\n  const anchorList = useMemo<Array<AnchorInfo & { content: ReactNode }>>(() => {\n    const list = [];\n\n    if (doclet?.length) {\n      const apiTitleText = 'API';\n      list.push({\n        text: apiTitleText,\n        depth: 1,\n        content: (\n          <h1 id={apiTitleText} key={apiTitleText}>\n            {apiTitleText}\n          </h1>\n        ),\n      });\n      list.push(\n        ...doclet.map(({ name, type, properties }, index) => ({\n          text: name,\n          depth: 2,\n          content: (\n            <div key={index} className={styles.table}>\n              <h2 id={name} className={styles.tableTitle}>\n                {name}\n              </h2>\n\n              {type ? <CodeSnippet children={type} /> : null}\n\n              {properties.length ? (\n                <Table\n                  headings={['name', 'type', 'default', 'description']}\n                  rows={properties.map((p) => ({ ...p, default: p.defaultValue }))}\n                />\n              ) : null}\n            </div>\n          ),\n        }))\n      );\n    }\n\n    return list;\n  }, [doclet]);\n\n  const eleTable = anchorList.length ? (\n    <div className={styles.propertiesTable}>{anchorList.map(({ content }) => content)}</div>\n  ) : null;\n\n  useEffect(() => {\n    if (!placeholderID) return undefined;\n\n    const observer = new MutationObserver(() => {\n      const placeholder = document.querySelector(`#${placeholderID}`);\n      if (placeholder) {\n        refPortal.current = createPortal(eleTable, placeholder);\n        forceUpdate(Math.random());\n      }\n    });\n\n    observer.observe(document.body, { childList: true, subtree: true });\n\n    return () => {\n      observer.disconnect();\n    };\n  }, [placeholderID]);\n\n  return placeholderID ? refPortal.current : eleTable;\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/preview/index.tsx",
    "content": "/**\n * This is the entry for preview-runtime render\n */\n\n// eslint-disable-next-line import/no-extraneous-dependencies\nimport React from 'react';\n// eslint-disable-next-line import/no-extraneous-dependencies\nimport ReactDOM from 'react-dom';\nimport type { DocsRootProps } from '@arco-cli/aspect/dist/docs/previewRuntime';\n\nimport { App } from './app';\n\nconst MOUNT_ROOT_SELECTOR = '#root';\n\nexport default function ({\n  mountRoot = MOUNT_ROOT_SELECTOR,\n  ...rest\n}: DocsRootProps & { mountRoot: string | HTMLElement }) {\n  ReactDOM.render(\n    <App {...rest} />,\n    typeof mountRoot === 'string' ? document.querySelector(mountRoot) : mountRoot\n  );\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/preview/previewContext/index.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { createContext, PropsWithChildren, useEffect, useMemo, useRef } from 'react';\nimport type { Pubsub } from '@arco-cli/aspect/dist/pubsub/previewRuntime';\n\nconst GLOBAL_MAP_KEY = '__ARCO_PREVIEW_GLOBAL_VARIABLES';\n\ntype PreviewContextType = {\n  pubsub?: Pubsub;\n  pubsubTopic?: string;\n  pubsubTopicParent?: string;\n  registerGlobalVariable: (name: string, variable: any) => void;\n};\n\nexport const PreviewContext = createContext<PreviewContextType>({\n  registerGlobalVariable: () => {},\n});\n\nexport function PreviewContextProvider(\n  props: PropsWithChildren<Pick<PreviewContextType, 'pubsub' | 'pubsubTopic' | 'pubsubTopicParent'>>\n) {\n  const { children, pubsub, pubsubTopic, pubsubTopicParent } = props;\n  const refGlobalVariablesMap = useRef<Record<string, any>>({\n    // this is the version for preview App\n    parentMessageIsSubscribed: true,\n  });\n\n  useEffect(() => {\n    (window as any)[GLOBAL_MAP_KEY] = refGlobalVariablesMap.current;\n  }, []);\n\n  const previewContextValue = useMemo<PreviewContextType>(() => {\n    return {\n      pubsub,\n      pubsubTopic,\n      pubsubTopicParent,\n      registerGlobalVariable: (name, fn) => {\n        refGlobalVariablesMap.current[name] = fn;\n      },\n    };\n  }, []);\n\n  return <PreviewContext.Provider value={previewContextValue}>{children}</PreviewContext.Provider>;\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/preview/theme.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { PropsWithChildren } from 'react';\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\ninterface ThemeProps {}\n\nexport function Theme(props: PropsWithChildren<ThemeProps>) {\n  const { children } = props;\n  // const hash = window.location.hash || '';\n  // const [, hashQuery] = hash.split('?');\n  // const params = new URLSearchParams(hashQuery);\n  // const theme = params.get('theme') || 'light';\n\n  // TODO theme toggle\n\n  return <div>{children}</div>;\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/sideBar/componentMenu/componentMenu.module.scss",
    "content": ".componentMenu {\n  display: flex;\n  flex-direction: column;\n  height: 100%;\n\n  .overview {\n    display: flex;\n    align-items: center;\n    height: 32px;\n    margin-bottom: 8px;\n    padding: 0 6px;\n    text-decoration: none;\n    color: var(--preview-color-text-1) !important;\n\n    :global(.arco-icon) {\n      margin: 0 8px 0 6px;\n    }\n\n    &:hover {\n      background: var(--preview-color-fill-2);\n    }\n\n    &.active {\n      background: var(--preview-color-fill-2);\n      color: var(--preview-color-primary) !important;\n    }\n  }\n\n  .filter {\n    :global(input) {\n      padding-left: 8px;\n    }\n\n    :global(.arco-input-inner-wrapper) {\n      background: none;\n      border-color: var(--preview-color-border);\n    }\n\n    :global(.arco-input-inner-wrapper-focus) {\n      border-color: var(--preview-color-primary);\n    }\n  }\n\n  .divider {\n    margin: 16px 0;\n    border-color: var(--preview-color-border);\n  }\n\n  .treeWrapper {\n    flex: 1;\n    overflow: auto;\n  }\n\n  .treeNode {\n    display: flex;\n    align-items: center;\n    text-decoration: none;\n    color: inherit !important;\n\n    :global(svg) {\n      flex-shrink: 0;\n      margin-right: 4px;\n    }\n  }\n\n  .treeNodeText {\n    white-space: nowrap;\n    overflow: hidden;\n    text-overflow: ellipsis;\n  }\n\n  :global(.arco-tree-node-title) {\n    overflow: hidden;\n  }\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/sideBar/componentMenu/componentMenu.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { ReactNode, useContext, useMemo, useState } from 'react';\n// eslint-disable-next-line import/no-extraneous-dependencies\nimport { Link } from 'react-router-dom';\nimport cs from 'classnames';\nimport { Divider, Input, Tree } from '@arco-design/web-react';\nimport { IconApps, IconSearch } from '@arco-design/web-react/icon';\nimport { ComponentModel } from '@arco-cli/aspect/dist/component/uiRuntime';\nimport { WorkspaceContext } from '../../workspaceContext';\n\nimport IconFolder from '../assets/folder.svg';\nimport IconFolderOpen from '../assets/folder-open.svg';\nimport IconFile from '../assets/file.svg';\n\nimport styles from './componentMenu.module.scss';\n\nexport interface ComponentMenuProps {\n  componentId?: string;\n  onComponentChange?: (componentId: string) => void;\n}\n\nexport function ComponentMenu({ componentId, onComponentChange }: ComponentMenuProps) {\n  const { components } = useContext(WorkspaceContext);\n\n  const [filterText, setFilterText] = useState('');\n\n  const routeInfo = useMemo(() => {\n    const results: Array<{\n      key: string;\n      title: ReactNode;\n      children?: Array<{ key: string; title: ReactNode }>;\n    }> = [];\n\n    const groupByPackage: Array<{ package: string; components: ComponentModel[] }> = [];\n    for (const component of components.sort((comA, comB) => (comA.id > comB.id ? 1 : -1))) {\n      let group = groupByPackage.find((node) => node.package === component.packageName);\n      if (!group) {\n        group = {\n          package: component.packageName,\n          components: [],\n        };\n        groupByPackage.push(group);\n      }\n      group.components.push(component);\n    }\n\n    for (const { package: packageName, components } of groupByPackage) {\n      const getMenuItemProps = (component: ComponentModel) => {\n        const { id, name } = component;\n        return {\n          key: id,\n          title: name,\n        };\n      };\n      const filterRule = ({ key, title }: { key: string; title: string }) => {\n        const _searchText = filterText.toLowerCase();\n        return filterText\n          ? key.toLowerCase().indexOf(_searchText) > -1 ||\n              title.toLowerCase().indexOf(_searchText) > -1\n          : true;\n      };\n\n      if (components.length > 1) {\n        const children = components.map(getMenuItemProps).filter(filterRule);\n        children.length &&\n          results.push({\n            key: packageName,\n            title: packageName,\n            children,\n          });\n      } else if (components.length) {\n        const routeInfo = getMenuItemProps(components[0]);\n        const filterResult = filterRule(routeInfo);\n        filterResult && results.push(routeInfo);\n      }\n    }\n\n    return results;\n  }, [filterText]);\n\n  return (\n    <div className={styles.componentMenu}>\n      <Link className={cs(styles.overview, { [styles.active]: !componentId })} to=\"/\">\n        <IconApps />\n        Overview\n      </Link>\n\n      <Input\n        className={styles.filter}\n        allowClear\n        prefix={<IconSearch />}\n        value={filterText}\n        onChange={setFilterText}\n        placeholder=\"Filter components\"\n      />\n\n      <Divider className={styles.divider} />\n\n      <div className={styles.treeWrapper}>\n        <Tree\n          autoExpandParent\n          blockNode\n          actionOnClick={['select', 'expand']}\n          treeData={routeInfo}\n          selectedKeys={[componentId]}\n          renderTitle={(node) => {\n            const key = node.dataRef.key;\n            const isFolder = Array.isArray(node.dataRef.children);\n            const eleText = (\n              <span title={`${node.title}`} className={styles.treeNodeText}>\n                {node.title}\n              </span>\n            );\n            return isFolder ? (\n              <div className={styles.treeNode}>\n                {node.expanded ? <IconFolderOpen /> : <IconFolder />}\n                {eleText}\n              </div>\n            ) : (\n              <Link\n                className={styles.treeNode}\n                to={`/${key}`}\n                onClick={() => onComponentChange(key)}\n              >\n                <IconFile />\n                {eleText}\n              </Link>\n            );\n          }}\n        />\n      </div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/sideBar/componentMenu/index.ts",
    "content": "export { ComponentMenu } from './componentMenu';\nexport type { ComponentMenuProps } from './componentMenu';\n"
  },
  {
    "path": "packages/ui-foundation-react/src/sideBar/index.ts",
    "content": "export { SideBar } from './sideBar';\nexport type { SideBarProps } from './sideBar';\n"
  },
  {
    "path": "packages/ui-foundation-react/src/sideBar/sideBar.module.scss",
    "content": ".sideBar {\n  height: 100%;\n  width: 240px;\n  padding: 12px;\n  border-right: 1px solid var(--preview-color-border);\n  overflow: auto;\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/sideBar/sideBar.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React from 'react';\nimport cs from 'classnames';\nimport { ComponentMenu, ComponentMenuProps } from './componentMenu';\n\nimport styles from './sideBar.module.scss';\n\nexport interface SideBarProps {\n  className?: string | string[];\n  componentMenuProps?: ComponentMenuProps;\n}\n\nexport function SideBar({ className, componentMenuProps }: SideBarProps) {\n  return (\n    <div className={cs(className, styles.sideBar)}>\n      <ComponentMenu {...componentMenuProps} />\n    </div>\n  );\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/spin/index.ts",
    "content": "export { Spin } from '@arco-design/web-react';\nexport type { SpinProps } from '@arco-design/web-react';\n"
  },
  {
    "path": "packages/ui-foundation-react/src/style/colors.scss",
    "content": "/**\n * Font size\n */\nbody {\n  --preview-font-size-display-3: 56px;\n  --preview-font-size-display-2: 48px;\n  --preview-font-size-display-1: 36px;\n  --preview-font-size-title-3: 24px;\n  --preview-font-size-title-2: 20px;\n  --preview-font-size-title-1: 16px;\n  --preview-font-size-body-3: 14px;\n  --preview-font-size-body-2: 13px;\n  --preview-font-size-body-1: 12px;\n}\n\n/**\n * Colors\n */\nbody {\n  --preview-color-success: rgb(0 180 42);\n  --preview-color-warning: rgb(255 125 0);\n  --preview-color-danger: rgb(245 63 63);\n  --preview-color-primary: rgb(22 93 255);\n  --preview-color-bg-1: #fff;\n  --preview-color-bg-2: #fff;\n  --preview-color-bg-3: #fff;\n  --preview-color-bg-4: #fff;\n  --preview-color-border: rgb(242 243 245);\n  --preview-color-link: rgb(22 93 255);\n  --preview-color-text-1: rgb(29 33 41);\n  --preview-color-text-2: rgb(78 89 105);\n  --preview-color-text-3: rgb(134 144 156);\n  --preview-color-text-4: rgb(201 205 212);\n  --preview-color-fill-1: rgb(247 248 250);\n  --preview-color-fill-2: rgb(242 243 245);\n  --preview-color-fill-3: rgb(229 230 235);\n  --preview-color-fill-4: rgb(201 205 212);\n}\n\nbody[arco-theme='dark'] {\n  --preview-color-success: rgb(39 195 70);\n  --preview-color-warning: rgb(251 233 75);\n  --preview-color-danger: rgb(247 105 101);\n  --preview-color-primary: rgb(60 126 255);\n  --preview-color-bg-1: #17171a;\n  --preview-color-bg-2: #232324;\n  --preview-color-bg-3: #2a2a2b;\n  --preview-color-bg-4: #313132;\n  --preview-color-border: #333335;\n  --preview-color-link: rgb(60 126 255);\n  --preview-color-text-1: rgb(255 255 255 / 90%);\n  --preview-color-text-2: rgb(255 255 255 / 70%);\n  --preview-color-text-3: rgb(255 255 255 / 50%);\n  --preview-color-text-4: rgb(255 255 255 / 30%);\n  --preview-color-fill-1: rgb(255 255 255 / 4%);\n  --preview-color-fill-2: rgb(255 255 255 / 8%);\n  --preview-color-fill-3: rgb(255 255 255 / 12%);\n  --preview-color-fill-4: rgb(255 255 255 / 16%);\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/style/global.scss",
    "content": "@import '~@arco-design/web-react/dist/css/arco.css';\n@import './colors';\n\nhtml,\nbody {\n  * {\n    box-sizing: border-box;\n  }\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/style/z-indexes.scss",
    "content": "// 5 < z < 20 - internal for components (if cannot be avoided)\n\n// 20 < z < 100 - internal for pages / sections\n\n// 100 < z < 1000 - navigation / hud\n$nav-z-index: 100;\n$navbar-z-index: 102;\n\n// 5000 < z < 6000 - modals and overlays\n$modal-z-index: 5000;\n\n// 15000 < 16000 - meta \"always on top\" items\n$highlighter-z-index: 15500;\n\n// theoretical max value is around\n// 32,768 (2^16)\n// and can be up to 1,073,741,824 (2^30), depending on the browser\n// (depending on the browser)\n"
  },
  {
    "path": "packages/ui-foundation-react/src/tabs/index.ts",
    "content": "export { Tabs } from '@arco-design/web-react';\nexport type { TabsProps } from '@arco-design/web-react';\n"
  },
  {
    "path": "packages/ui-foundation-react/src/type/custom.d.ts",
    "content": "declare module '*.module.css' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\ndeclare module '*.module.scss' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\ndeclare module '*.module.sass' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.module.less' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.less' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.css' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.sass' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.scss' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.mdx' {\n  const component: any;\n  export default component;\n}\n\ndeclare module '*.svg' {\n  const component: any;\n  export default component;\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/workspaceContext/index.ts",
    "content": "export { WorkspaceContext, WorkspaceContextProvider } from './workspaceContext';\n"
  },
  {
    "path": "packages/ui-foundation-react/src/workspaceContext/workspaceContext.module.scss",
    "content": ".loader {\n  position: fixed;\n  left: 0;\n  right: 0;\n  top: 0;\n  bottom: 0;\n  z-index: 20;\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/workspaceContext/workspaceContext.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { createContext, ReactNode, useEffect, useMemo, useState } from 'react';\nimport { Spin } from '@arco-design/web-react';\nimport { ComponentModel } from '@arco-cli/aspect/dist/component/uiRuntime';\nimport { LoaderContext, useLoaderApi } from '../globalLoader';\nimport { LOCAL_STORAGE_KEY_WORKSPACE_DARK_MODE } from '../constants';\n\nimport '../style/global.scss';\nimport styles from './workspaceContext.module.scss';\n\ntype WorkspaceContextType = {\n  name: string;\n  darkMode: boolean;\n  setDarkMode: (dark: boolean) => void;\n  components: ComponentModel[];\n  overviewScrollContainerID: string;\n};\n\nexport const WorkspaceContext = createContext<WorkspaceContextType>({\n  name: '',\n  darkMode: false,\n  setDarkMode: () => {},\n  components: [],\n  overviewScrollContainerID: '',\n});\n\nexport function WorkspaceContextProvider(\n  props: {\n    children: ReactNode;\n  } & Pick<WorkspaceContextType, 'name' | 'components' | 'overviewScrollContainerID'>\n) {\n  const { name, children, overviewScrollContainerID } = props;\n  const [loaderApi, isLoading] = useLoaderApi();\n  const [darkMode, setDarkMode] = useState<boolean>(() => {\n    return +localStorage.getItem(LOCAL_STORAGE_KEY_WORKSPACE_DARK_MODE) > 0;\n  });\n\n  const workspaceContextValue = useMemo<WorkspaceContextType>(() => {\n    return {\n      name,\n      darkMode,\n      setDarkMode: (dark) => {\n        setDarkMode(dark);\n        localStorage.setItem(LOCAL_STORAGE_KEY_WORKSPACE_DARK_MODE, dark ? '1' : '0');\n      },\n      overviewScrollContainerID,\n      components: props.components,\n    };\n  }, [name, darkMode, setDarkMode, overviewScrollContainerID, JSON.stringify(props.components)]);\n\n  useEffect(() => {\n    darkMode\n      ? document.body.setAttribute('arco-theme', 'dark')\n      : document.body.removeAttribute('arco-theme');\n  }, [darkMode]);\n\n  return (\n    <WorkspaceContext.Provider value={workspaceContextValue}>\n      <LoaderContext.Provider value={loaderApi}>\n        <Spin loading={isLoading} className={styles.loader}>\n          {children}\n        </Spin>\n      </LoaderContext.Provider>\n    </WorkspaceContext.Provider>\n  );\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/workspaceOverview/index.ts",
    "content": "export { WorkspaceOverview } from './workspaceOverview';\n"
  },
  {
    "path": "packages/ui-foundation-react/src/workspaceOverview/workspaceOverview.module.scss",
    "content": ".workspaceOverview {\n  $component-card-margin: 10px;\n\n  display: flex;\n  flex-wrap: wrap;\n  min-height: 100%;\n  margin: 0 (-$component-card-margin);\n\n  .emptyPlaceholder {\n    margin-top: 20vh;\n  }\n\n  .componentCard {\n    position: relative;\n    display: flex;\n    flex-direction: column;\n    width: calc(50% - $component-card-margin * 2);\n    height: 244px;\n    margin: $component-card-margin;\n    padding: 24px;\n    text-decoration: none;\n    border: 1px solid var(--preview-color-border);\n    border-radius: 8px;\n    color: var(--preview-color-text-3);\n    font-size: var(--preview-font-size-body-1);\n    overflow: hidden;\n\n    @media (min-width: 1000px) {\n      width: calc(33.33% - $component-card-margin * 2);\n    }\n\n    @media (min-width: 1400px) {\n      width: calc(25% - $component-card-margin * 2);\n    }\n\n    @media (min-width: 1800px) {\n      width: calc(20% - $component-card-margin * 2);\n    }\n\n    &::before,\n    &::after {\n      content: ' ';\n      position: absolute;\n      bottom: -60px;\n      right: -60px;\n      width: 140px;\n      height: 140px;\n      border-radius: 100px;\n    }\n\n    &::before {\n      right: 10px;\n      background: #5addb4;\n      opacity: 0.04;\n    }\n\n    &::after {\n      background: #6aa1ff;\n      opacity: 0.05;\n    }\n\n    &:hover {\n      box-shadow: 0 0 6px var(--preview-color-fill-2);\n    }\n\n    .avatar {\n      margin-bottom: 12px;\n    }\n\n    .title {\n      display: flex;\n      align-items: center;\n      width: fit-content;\n      max-width: 100%;\n      margin-bottom: 8px;\n      font-size: var(--preview-font-size-title-1);\n      font-weight: 600;\n      color: var(--preview-color-text-1);\n\n      .titleText {\n        overflow: hidden;\n        text-overflow: ellipsis;\n        white-space: nowrap;\n      }\n\n      :global(.arco-tag) {\n        margin-left: 6px;\n      }\n    }\n\n    .packageName {\n      margin-bottom: 8px;\n      font-size: var(--preview-font-size-body-1);\n      font-weight: 500;\n      line-height: 20px;\n      color: var(--preview-color-text-2);\n    }\n\n    .description {\n      flex: 1;\n      overflow: hidden;\n      text-overflow: ellipsis;\n      margin: 0;\n      color: var(--preview-color-text-3);\n    }\n\n    .labels {\n      margin-top: 12px;\n\n      :global(.arco-icon) {\n        margin-right: 4px;\n      }\n    }\n  }\n\n  .empty {\n    display: flex;\n    align-items: center;\n  }\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/src/workspaceOverview/workspaceOverview.tsx",
    "content": "// eslint-disable-next-line import/no-extraneous-dependencies\nimport React, { useContext } from 'react';\n// eslint-disable-next-line import/no-extraneous-dependencies\nimport { Link } from 'react-router-dom';\nimport cs from 'classnames';\nimport { Avatar, Empty, Tag, Typography } from '@arco-design/web-react';\nimport { IconTag } from '@arco-design/web-react/icon';\nimport { WorkspaceContext } from '../workspaceContext';\n\nimport styles from './workspaceOverview.module.scss';\n\nconst AVAILABLE_AVATAR_COLORS = ['#FF7D00', '#FADC19', '#9FDB1D', '#14C9C9', '#165DFF', '#722ED1'];\n\nexport function WorkspaceOverview() {\n  const { components } = useContext(WorkspaceContext);\n  const isEmpty = !components?.length;\n\n  return (\n    <div className={cs(styles.workspaceOverview, { [styles.empty]: isEmpty })}>\n      {isEmpty ? (\n        <Empty className={styles.emptyPlaceholder} description=\"No components found\" />\n      ) : (\n        components.map(({ id, name, packageName, version, author, description, labels }) => {\n          const avatarText = author || 'Unknown';\n          return (\n            <Link key={id} className={styles.componentCard} to={`/${id}`}>\n              <Avatar\n                className={styles.avatar}\n                style={{\n                  background:\n                    AVAILABLE_AVATAR_COLORS[\n                      Math.floor(avatarText.length % AVAILABLE_AVATAR_COLORS.length)\n                    ],\n                }}\n              >\n                {avatarText}\n              </Avatar>\n              <div title={name} className={styles.title}>\n                <span className={styles.titleText}>{name}</span>\n                <Tag size=\"small\">v{version}</Tag>\n              </div>\n              <div className={styles.packageName}>{packageName}</div>\n              <Typography.Paragraph className={styles.description} ellipsis={{ rows: 3 }}>\n                {description}\n              </Typography.Paragraph>\n              <div className={styles.labels}>\n                <IconTag />\n                {labels.join(' / ')}\n              </div>\n            </Link>\n          );\n        })\n      )}\n    </div>\n  );\n}\n"
  },
  {
    "path": "packages/ui-foundation-react/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"dist\",\n    \"paths\": {\n      \"@arco-cli/stone\": [\"../stone/src\"],\n      \"@arco-cli/legacy/dist/*\": [\"../legacy/src/*\"],\n      \"@arco-cli/core/dist/*\": [\"../core/src/*\"],\n      \"@arco-cli/aspect/dist/*\": [\"../aspect/src/*\"],\n      \"@arco-cli/service/dist*\": [\"../service/src/*\"],\n      \"@arco-cli/ui-foundation-react\": [\"../ui-foundation-react/src\"],\n      \"@arco-cli/ui-foundation-react/dist/*\": [\"../ui-foundation-react/src/*\"]\n    }\n  }\n}\n"
  },
  {
    "path": "pnpm-workspace.yaml",
    "content": "packages:\n  - 'packages/*'\n  - 'ui'\n  - '!**/test/**'\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"allowJs\": true,\n    \"declaration\": true,\n    \"sourceMap\": true,\n    \"skipLibCheck\": true,\n    \"skipDefaultLibCheck\": true,\n    \"esModuleInterop\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"module\": \"CommonJS\",\n    \"target\": \"es6\",\n    \"moduleResolution\": \"node\",\n    \"jsx\": \"react\",\n    \"lib\": [\"DOM\", \"DOM.Iterable\", \"ES2020\"],\n    \"resolveJsonModule\": true\n  },\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "ui/.gitignore",
    "content": "es\nlib\nartifacts\n"
  },
  {
    "path": "ui/.scripts/workspaceHooks/afterComponentCreated.js",
    "content": "/* eslint-disable @typescript-eslint/no-var-requires */\nconst fs = require('fs');\nconst path = require('path');\n\nmodule.exports = function (componentInfo) {\n  const { path: pathComponentEntry, modules } = componentInfo || {};\n\n  let pathLibraryEntry = path.resolve(pathComponentEntry, '../index.ts');\n  if (!fs.existsSync(pathLibraryEntry)) {\n    pathLibraryEntry = path.resolve(pathLibraryEntry, '../index.tsx');\n  }\n\n  if (fs.existsSync(pathLibraryEntry) && fs.existsSync(pathComponentEntry)) {\n    const libraryEntryContent = fs.readFileSync(pathLibraryEntry).toString();\n    const exportExpressions = modules\n      .map(\n        ({ name, type }) =>\n          `export${type ? ' type' : ''} { ${name} } from '${path\n            .relative(path.dirname(pathLibraryEntry), pathComponentEntry)\n            .replace(/^[^.]/, (match) => `./${match}`)}';`\n      )\n      .join('\\n');\n\n    if (libraryEntryContent.indexOf(exportExpressions) === -1) {\n      fs.writeFileSync(pathLibraryEntry, `${libraryEntryContent}\\n${exportExpressions}\\n`);\n    }\n  }\n};\n"
  },
  {
    "path": "ui/arco.env.config.js",
    "content": "/* eslint-disable @typescript-eslint/no-var-requires */\nconst fs = require('fs');\nconst path = require('path');\n\nmodule.exports = function defineConfig() {\n  const webpackConfigTransformer = (config) => {\n    const mdxLoader = config.raw.module.rules\n      .find((rule) => rule.oneOf)\n      ?.oneOf?.find((rule) => rule.test.test('.mdx'))\n      ?.use?.find(({ loader }) => loader.indexOf('/mdx/loader') > -1);\n    if (mdxLoader) {\n      mdxLoader.options.preProcessFile = ({ path: filePath, content }) => {\n        const componentStyleEntry = '../style/index.ts';\n        if (fs.existsSync(path.resolve(path.dirname(filePath), componentStyleEntry))) {\n          return `${content}\\nimport '${componentStyleEntry}';`;\n        }\n        return content;\n      };\n    }\n\n    return config.merge({\n      resolve: {\n        alias: {\n          react: require.resolve('react'),\n        },\n      },\n    });\n  };\n\n  const config = {\n    jest: {\n      jestConfigPath: path.resolve(__dirname, './jest.config.js'),\n    },\n    webpack: {\n      previewConfig: [webpackConfigTransformer],\n      devServerConfig: [webpackConfigTransformer],\n    },\n    typescript: {\n      buildConfig: [\n        (config) => {\n          config.mergeTsConfig({});\n          return config;\n        },\n      ],\n    },\n    less: {\n      lessOptions: {},\n    },\n    sass: {\n      sassOptions: {},\n    },\n  };\n\n  return config;\n};\n"
  },
  {
    "path": "ui/arco.workspace.jsonc",
    "content": "{\n  \"arco.aspect/workspace\": {\n    \"name\": \"Arco Workspace UI\",\n    \"components\": {\n      \"extends\": {\n        \"rootDir\": \"src\",\n        \"entries\": {\n          \"main\": \"index.ts\",\n          \"style\": \"style/index.ts\",\n          \"preview\": \"__docs__/index.mdx\",\n          \"jsdoc\": [\n            \"interface.ts\"\n          ]\n        }\n      },\n      \"members\": [\n        {\n          \"name\": \"Overview\",\n          \"entries\": {\n            \"base\": \"Overview\"\n          }\n        }\n      ]\n    }\n  },\n  \"arco.service/generator\": {\n    \"defaultPath\": \"src\",\n    \"hooks\": {\n      \"afterComponentCreated\": \"./.scripts/workspaceHooks/afterComponentCreated.js\"\n    }\n  },\n  \"arco.service/compiler\": {\n    \"skipDeleteDistDir\": true\n  }\n}"
  },
  {
    "path": "ui/jest.config.js",
    "content": "/* eslint-disable @typescript-eslint/no-var-requires */\n// allow IDE to configure Jest config\nconst defaultConfig = require(require.resolve('@arco-cli/react/dist/jest/jest.cjs.config.js'));\n\nmodule.exports = {\n  ...defaultConfig,\n};\n"
  },
  {
    "path": "ui/package.json",
    "content": "{\n  \"name\": \"@arco-cli/workspace-materials\",\n  \"version\": \"0.7.0\",\n  \"description\": \"\",\n  \"main\": \"./lib/index.js\",\n  \"module\": \"./es/index.js\",\n  \"types\": \"./es/index.d.ts\",\n  \"scripts\": {\n    \"arco\": \"node ../packages/arco/dist/app.js\",\n    \"start\": \"pnpm arco start\",\n    \"build\": \"pnpm arco build\",\n    \"build:esm\": \"pnpm arco build --tasks=\\\"TSCompilerESM\\\"\",\n    \"sync\": \"pnpm arco sync\",\n    \"clean\": \"rm -rf es lib artifacts\",\n    \"prepublishOnly\": \"npm run build\"\n  },\n  \"peerDependencies\": {\n    \"@arco-design/web-react\": \"~2\",\n    \"react\": \">=16\"\n  },\n  \"dependencies\": {\n    \"classnames\": \"^2.3.2\",\n    \"lodash-es\": \"^4.17.21\",\n    \"penpal\": \"^6.2.2\"\n  },\n  \"devDependencies\": {\n    \"@testing-library/jest-dom\": \"^5.16.5\"\n  },\n  \"sideEffects\": [\n    \"{es,lib,src}/**/style/*\",\n    \"*.less\"\n  ],\n  \"files\": [\n    \"es\",\n    \"lib\"\n  ],\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "ui/src/Overview/Overview.tsx",
    "content": "import cs from 'classnames';\nimport debounce from 'lodash-es/debounce';\nimport React, {\n  forwardRef,\n  useCallback,\n  useEffect,\n  useImperativeHandle,\n  useRef,\n  useState,\n} from 'react';\nimport { Spin } from '@arco-design/web-react';\nimport { IconFullscreen, IconFullscreenExit, IconShareInternal } from '@arco-design/web-react/icon';\n\nimport { OverviewProps, OverviewHandle } from './interface';\nimport { useConnectIframe } from '../utils/useConnectIframe';\nimport { findNode } from '../utils/findNode';\nimport { on, off } from '../utils/dom';\n\n// @ts-ignore\nimport styles from './style/index.module.less';\nimport {\n  PREVIEW_IFRAME_GLOBAL_VARIABLES_KEY,\n  PUBSUB_TOPIC_PARENT_TO_CHILD,\n} from '../utils/constant';\n\nconst enum IFRAME_VALID_MESSAGE_TYPE {\n  updateAnchorOffset = 'updateAnchorOffset',\n  appendExtraStyle = 'appendExtraStyle',\n  switchDarkMode = 'switchDarkMode',\n  scrollIntoView = 'scrollIntoView',\n  switchActiveTab = 'switchActiveTab',\n}\n\nfunction getContainer(targetContainer?: string | HTMLElement | Window) {\n  if (typeof targetContainer === 'string') {\n    return findNode(document, targetContainer);\n  }\n  return targetContainer || window;\n}\n\nfunction canAccessIFrame(iframe: HTMLIFrameElement) {\n  let html = null;\n  try {\n    // deal with older browsers\n    const doc = iframe.contentDocument || iframe.contentWindow.document;\n    html = doc.body.innerHTML;\n  } catch (err) {}\n\n  return html !== null;\n}\n\nexport const Overview = forwardRef(function (props: OverviewProps, ref) {\n  const {\n    style,\n    className,\n    src,\n    iframe,\n    extraStyle,\n    darkMode,\n    scrollContainer,\n    scrollContainerOffset = 0,\n    timeout = 15000,\n    spinProps,\n    onReady,\n    onTimeout,\n    onIframeLoad,\n    onIframeError,\n    onIframeLocationHashChange,\n    onIframeActiveTabChange,\n  } = props;\n\n  const refIframe = useRef<HTMLIFrameElement>(null);\n  const refScrollContainer = useRef<HTMLElement | Window>(null);\n  const refLoadingTimer = useRef<any>(null);\n\n  const [iframeLoadTimes, setIframeLoadTimes] = useState(0);\n  const [iframeFullscreen, setIframeFullscreen] = useState(false);\n\n  const { height, locationHash, activeTab, connection } = useConnectIframe(refIframe);\n  const isLoading = !height;\n\n  useEffect(() => {\n    if (!isLoading) {\n      onReady?.();\n      clearTimeout(refLoadingTimer.current);\n    }\n  }, [isLoading]);\n\n  useEffect(() => {\n    if (!isLoading) {\n      onIframeLocationHashChange?.(locationHash);\n    }\n  }, [locationHash]);\n\n  useEffect(() => {\n    if (!isLoading) {\n      onIframeActiveTabChange?.(activeTab);\n    }\n  }, [activeTab]);\n\n  const operateIframe = useCallback(\n    ({ type, data }: { type: IFRAME_VALID_MESSAGE_TYPE; data: Record<string, any> }) => {\n      if (!refIframe.current) return;\n\n      const contentWindow = canAccessIFrame(refIframe.current)\n        ? refIframe.current.contentWindow\n        : null;\n\n      // compatible with preview logic before 2.1.0, directly operate iframe DOM nodes\n      if (\n        contentWindow &&\n        !(contentWindow as any)[PREVIEW_IFRAME_GLOBAL_VARIABLES_KEY]?.parentMessageIsSubscribed\n      ) {\n        switch (type) {\n          case IFRAME_VALID_MESSAGE_TYPE.updateAnchorOffset: {\n            const updateAnchorOffset = (contentWindow as any).__arcoPreviewMethods\n              ?.updateAnchorOffset;\n            if (typeof updateAnchorOffset === 'function') {\n              try {\n                updateAnchorOffset(data.offset);\n              } catch (err) {\n                console.warn(`Failed to update anchor position in component preview page, details:\n${err.toString()}`);\n              }\n            }\n            break;\n          }\n\n          case IFRAME_VALID_MESSAGE_TYPE.appendExtraStyle: {\n            const eleClassName = '__arco-component-extra-style';\n            // clear all append styles at first\n            contentWindow.document\n              .querySelectorAll(`.${eleClassName}`)\n              .forEach((node) => contentWindow.document.body.removeChild(node));\n            if (data.href) {\n              const styleEle = document.createElement('link');\n              styleEle.setAttribute('class', eleClassName);\n              styleEle.setAttribute('type', 'text/css');\n              styleEle.setAttribute('rel', 'stylesheet');\n              styleEle.setAttribute('href', data.href);\n              contentWindow.document.body?.prepend(styleEle);\n            }\n            break;\n          }\n\n          case IFRAME_VALID_MESSAGE_TYPE.switchDarkMode: {\n            const body = contentWindow.document.body;\n            data.dark\n              ? body.setAttribute('arco-theme', 'dark')\n              : body.removeAttribute('arco-theme');\n            break;\n          }\n\n          case IFRAME_VALID_MESSAGE_TYPE.scrollIntoView: {\n            try {\n              contentWindow.document.body\n                ?.querySelector(data.selector)\n                ?.scrollIntoView(data.options);\n            } catch (err) {}\n            break;\n          }\n\n          default:\n            break;\n        }\n      } else if (connection) {\n        connection.pub(PUBSUB_TOPIC_PARENT_TO_CHILD, { type, data });\n      }\n    },\n    [connection]\n  );\n\n  const scrollHandler = useCallback(\n    debounce((event) => {\n      if (connection) {\n        const scrollTop = (event.target?.scrollTop || 0) - scrollContainerOffset;\n        const offset = Math.max(0, scrollTop);\n        operateIframe({\n          type: IFRAME_VALID_MESSAGE_TYPE.updateAnchorOffset,\n          data: { offset },\n        });\n      }\n    }, 200),\n    [scrollContainerOffset, operateIframe]\n  );\n\n  useEffect(() => {\n    refScrollContainer.current = getContainer(scrollContainer);\n\n    on(refScrollContainer.current, 'scroll', scrollHandler);\n\n    return () => {\n      off(refScrollContainer.current, 'scroll', scrollHandler);\n    };\n  }, [scrollContainer, scrollHandler]);\n\n  useEffect(() => {\n    if (iframeLoadTimes > 0 && extraStyle) {\n      operateIframe({\n        type: IFRAME_VALID_MESSAGE_TYPE.appendExtraStyle,\n        data: { href: extraStyle },\n      });\n    }\n  }, [iframeLoadTimes, extraStyle, operateIframe]);\n\n  useEffect(() => {\n    if (iframeLoadTimes > 0) {\n      operateIframe({\n        type: IFRAME_VALID_MESSAGE_TYPE.switchDarkMode,\n        data: { dark: darkMode },\n      });\n    }\n  }, [iframeLoadTimes, darkMode, operateIframe]);\n\n  useImperativeHandle<any, OverviewHandle>(\n    ref,\n    () => {\n      return {\n        scrollIntoView: (selector: string, options: any) => {\n          operateIframe({\n            type: IFRAME_VALID_MESSAGE_TYPE.scrollIntoView,\n            data: { selector, options },\n          });\n        },\n        updateMDXPreviewActiveTab: (tab: string) => {\n          operateIframe({\n            type: IFRAME_VALID_MESSAGE_TYPE.switchActiveTab,\n            data: { tab },\n          });\n        },\n      };\n    },\n    [operateIframe]\n  );\n\n  return (\n    <Spin block loading={isLoading} {...spinProps}>\n      <div className={cs(styles.overview, { [styles.fullscreen]: iframeFullscreen })}>\n        <div className={styles.operationButtons}>\n          <div\n            title=\"open in new tab\"\n            className={styles.button}\n            onClick={() => window.open(src, '_blank')}\n          >\n            <IconShareInternal />\n          </div>\n          <div\n            title=\"toggle fullscreen\"\n            className={styles.button}\n            onClick={() => setIframeFullscreen(!iframeFullscreen)}\n          >\n            {iframeFullscreen ? <IconFullscreenExit /> : <IconFullscreen />}\n          </div>\n        </div>\n        <iframe\n          ref={(ref) => {\n            refIframe.current = ref;\n            if (iframe) {\n              iframe.current = ref;\n            }\n          }}\n          style={{\n            ...style,\n            opacity: isLoading ? 0.1 : 1,\n            height: isLoading ? '80vh' : height,\n          }}\n          className={cs(className, styles.iframe)}\n          title=\"material-component-overview\"\n          scrolling={iframeFullscreen ? 'auto' : 'no'}\n          src={src}\n          onLoad={(event) => {\n            onIframeLoad?.(event);\n            setIframeLoadTimes(iframeLoadTimes > 10e8 ? 1 : iframeLoadTimes + 1);\n\n            clearTimeout(refLoadingTimer.current);\n            refLoadingTimer.current = setTimeout(() => onTimeout?.(), timeout);\n          }}\n          onError={onIframeError}\n        />\n      </div>\n    </Spin>\n  );\n});\n"
  },
  {
    "path": "ui/src/Overview/__docs__/basic.tsx",
    "content": "import React from 'react';\n\nexport default function Basic() {\n  return <h1>Basic Demo</h1>;\n}\n"
  },
  {
    "path": "ui/src/Overview/__docs__/index.mdx",
    "content": "---\ntitle: Overview\ndescription: Some description about this component.\nlabels: ['Keyword-1', 'Keyword-2']\n---\n\n# 基本用法\n\nimport Basic from './basic';\n\n<div data-arco-demo=\"Basic\">\n  <Basic />\n</div>\n"
  },
  {
    "path": "ui/src/Overview/__test__/index.test.tsx",
    "content": "/* eslint-disable import/no-extraneous-dependencies */\nimport React from 'react';\nimport { render } from '@testing-library/react';\nimport { Overview } from '../index';\n\ndescribe('Overview', () => {\n  it('render current content', () => {\n    render(<Overview />);\n    expect(document.querySelector('div')).toHaveTextContent('Edit this component');\n  });\n});\n"
  },
  {
    "path": "ui/src/Overview/index.ts",
    "content": "export { Overview } from './Overview';\nexport type { OverviewProps, OverviewHandle } from './interface';\n"
  },
  {
    "path": "ui/src/Overview/interface.ts",
    "content": "import { CSSProperties, MutableRefObject } from 'react';\nimport { SpinProps } from '@arco-design/web-react';\n\n/**\n * @title Overview\n */\nexport interface OverviewProps {\n  style?: CSSProperties;\n  className?: string | string[];\n  /**\n   * @zh Iframe 页面地址\n   * @en Iframe src\n   */\n  src: string;\n  /**\n   * @zh 需要向 Iframe 额外注入的内容\n   * @en Extra style append to iframe\n   */\n  extraStyle?: string;\n  /**\n   * @zh 是否为 Arco 暗色模式\n   * @en Whether is Arco dark mode\n   */\n  darkMode?: boolean;\n  /**\n   * @zh Iframe 引用\n   * @zh Reference of iframe element\n   */\n  iframe?: MutableRefObject<HTMLIFrameElement>;\n  /**\n   * @zh 包裹 iframe 进行滚动的容器\n   * @en Scroll container of iframe\n   */\n  scrollContainer?: string | Window | HTMLElement;\n  /**\n   * @zh 滚动容器的偏移量\n   * @en Offset of scroll container\n   */\n  scrollContainerOffset?: number;\n  /**\n   * @zh 物料预览加载超时时间\n   * @en Timeout for loading preview\n   * @default 15000\n   */\n  timeout?: number;\n  /**\n   * @zh Spin 组件属性\n   * @en Pass by SpinProps\n   */\n  spinProps?: Partial<SpinProps>;\n  /**\n   * @zh 预览加载就绪回调\n   * @en Callback for preview content loaded\n   */\n  onReady?: () => void;\n  /**\n   * @zh 预览加载超时回调\n   * @en Callback for preview loaded timeout\n   */\n  onTimeout?: () => void;\n  /**\n   * @zh Iframe onLoad 事件触发回调\n   * @en Callback for iframe loaded\n   */\n  onIframeLoad?: (event) => void;\n  /**\n   * @zh Iframe onError 事件回调\n   * @en Callback for iframe onError\n   */\n  onIframeError?: (event) => void;\n  /**\n   * @zh Iframe location hash 改变的回调\n   * @en Callback for Iframe location hash change\n   */\n  onIframeLocationHashChange?: (hash: string) => void;\n  /**\n   * @zh Iframe 内部子 Tab 切换的回调\n   * @en Callback for tab switch inside iframe\n   */\n  onIframeActiveTabChange?: (activeTabKey: string) => void;\n}\n\n/**\n * @title OverviewHandle\n */\nexport type OverviewHandle = {\n  scrollIntoView: (selector: string, scrollOption?: any) => void;\n  updateMDXPreviewActiveTab: (tab: string) => void;\n};\n\n// ArcoBaseEvent from aspect/pubsub/events\nexport type PubsubMessageType = {\n  type: string;\n  data: Record<string, any>;\n};\n"
  },
  {
    "path": "ui/src/Overview/style/index.module.less",
    "content": ".overview {\n  position: relative;\n\n  .iframe {\n    background: var(--preview-color-bg-1);\n  }\n\n  &.fullscreen {\n    position: fixed;\n    left: 0;\n    right: 0;\n    top: 0;\n    bottom: 0;\n    z-index: 9999;\n\n    .iframe {\n      position: absolute;\n      left: 0;\n      top: 0;\n      width: 100% !important;\n      height: 100% !important;\n      padding: 20px;\n    }\n\n    .operationButtons {\n      top: 20px;\n      right: 20px;\n    }\n  }\n\n  .operationButtons {\n    display: flex;\n    align-items: center;\n    position: absolute;\n    top: 0;\n    right: 0;\n    color: var(--color-text-2);\n    opacity: 0;\n    transition: opacity 0.1s ease-in-out;\n    z-index: 1;\n\n    .button {\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      width: 24px;\n      height: 24px;\n      margin-left: 8px;\n      padding: 0;\n      border: 1px solid #f2f3f51a;\n      border-radius: 2px;\n      background: rgba(255, 255, 255, 0.1);\n      backdrop-filter: blur(8px);\n      box-shadow: 0 2px 4px 0 #1f23291a;\n      cursor: pointer;\n\n      &:hover {\n        background: rgba(255, 255, 255, 0.15);\n      }\n\n      &:active {\n        background: rgba(255, 255, 255, 0.2);\n      }\n\n      svg {\n        display: inline-block;\n        color: inherit;\n      }\n    }\n  }\n\n  &:hover {\n    .operationButtons {\n      opacity: 1;\n    }\n  }\n}"
  },
  {
    "path": "ui/src/index.ts",
    "content": "export { Overview } from './Overview';\nexport type { OverviewProps } from './Overview';\n"
  },
  {
    "path": "ui/src/type/custom.d.ts",
    "content": "declare module '*.module.css' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\ndeclare module '*.module.scss' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\ndeclare module '*.module.sass' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.module.less' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.less' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.css' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.sass' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.scss' {\n  const classes: { readonly [key: string]: string };\n  export default classes;\n}\n\ndeclare module '*.mdx' {\n  const component: any;\n  export default component;\n}\n\ndeclare module '*.svg' {\n  const component: any;\n  export default component;\n}\n"
  },
  {
    "path": "ui/src/utils/constant.ts",
    "content": "export const PUBSUB_TOPIC_PARENT_TO_CHILD = 'preview-host';\n\nexport const PUBSUB_TOPIC_CHILD_TO_PARENT = 'preview';\n\nexport const PREVIEW_IFRAME_GLOBAL_VARIABLES_KEY = '__ARCO_PREVIEW_GLOBAL_VARIABLES';\n"
  },
  {
    "path": "ui/src/utils/dom.ts",
    "content": "const NOOP = () => {};\n\nexport const isServerRendering = (function () {\n  try {\n    return !(typeof window !== 'undefined' && document !== undefined);\n  } catch (e) {\n    return true;\n  }\n})();\n\nexport const on = (function () {\n  if (isServerRendering) {\n    return NOOP;\n  }\n  return function (\n    element: EventTarget | null,\n    event: string,\n    // eslint-disable-next-line no-undef\n    handler: EventListenerOrEventListenerObject,\n    // eslint-disable-next-line no-undef\n    options?: boolean | AddEventListenerOptions\n  ) {\n    element && element.addEventListener(event, handler, options || false);\n  };\n})();\n\nexport const off = (function () {\n  if (isServerRendering) {\n    return NOOP;\n  }\n  return function (\n    element: EventTarget | null,\n    event: string,\n    // eslint-disable-next-line no-undef\n    handler: EventListenerOrEventListenerObject,\n    // eslint-disable-next-line no-undef\n    options?: boolean | AddEventListenerOptions\n  ) {\n    element && element.removeEventListener(event, handler, options || false);\n  };\n})();\n\nexport const contains = function (root: HTMLElement, ele) {\n  if (!root) {\n    return false;\n  }\n  if (root.contains) {\n    return root.contains(ele);\n  }\n  let node = ele;\n  while (node) {\n    if (node === root) {\n      return true;\n    }\n    node = node.parentNode;\n  }\n  return false;\n};\n\nexport const isScrollElement = (element: HTMLElement) => {\n  const clientHeight =\n    element === document.documentElement ? element.clientHeight : element.offsetHeight;\n  const clientWidth =\n    element === document.documentElement ? element.clientWidth : element.offsetWidth;\n\n  return element.scrollHeight > clientHeight || element.scrollWidth > clientWidth;\n};\n\nexport const getScrollElements = (\n  container: HTMLElement,\n  top: HTMLElement = document.documentElement\n): HTMLElement[] => {\n  const scrollElements: HTMLElement[] = [];\n  let element: HTMLElement | null = container;\n  while (element && element !== top) {\n    if (isScrollElement(element)) {\n      scrollElements.push(element);\n    }\n    element = element.parentElement;\n  }\n  return scrollElements;\n};\n"
  },
  {
    "path": "ui/src/utils/findNode.ts",
    "content": "export function findNode(dom: HTMLElement | Document, selector: string): HTMLElement {\n  // handle id start with number\n  // e.g. id #123\n  const s =\n    typeof selector === 'string' && selector[0] === '#'\n      ? `[id='${selector.replace('#', '')}']`\n      : selector;\n  try {\n    return dom.querySelector(s);\n  } catch (e) {\n    console.error(e);\n    return null;\n  }\n}\n"
  },
  {
    "path": "ui/src/utils/useConnectIframe.ts",
    "content": "import { useState, MutableRefObject, useEffect } from 'react';\nimport { connectToChild } from 'penpal';\nimport { PUBSUB_TOPIC_CHILD_TO_PARENT } from './constant';\nimport type { PubsubMessageType } from '../Overview/interface';\n\nexport function useConnectIframe(refIframe: MutableRefObject<HTMLIFrameElement>) {\n  const [height, setHeight] = useState(0);\n  const [locationHash, setLocationHash] = useState('');\n  const [activeTab, setActiveTab] = useState<string>(null);\n  const [connection, setConnection] = useState(null);\n\n  useEffect(() => {\n    if (!refIframe.current) return;\n\n    connectToChild<{\n      pub: (topic: string, event: PubsubMessageType) => Promise<any>;\n    }>({\n      iframe: refIframe.current,\n      methods: {\n        pub: (topic: string, message: PubsubMessageType) => {\n          if (topic === PUBSUB_TOPIC_CHILD_TO_PARENT) {\n            switch (message.type) {\n              case 'preview-size':\n                setHeight(message.data.height);\n                break;\n              case 'preview-location-hash':\n                setLocationHash(message.data.hash);\n                break;\n              case 'preview-active-tab':\n                setActiveTab(message.data.activeTab || '');\n                break;\n              default:\n                break;\n            }\n          }\n        },\n      },\n    })\n      .promise.then((connection) => setConnection(connection))\n      .catch((err) => {\n        console.error(\n          `[ComponentPreview] Failed to connect child iframe which is used to preview component. Details:\\n${err.toString()}`\n        );\n      });\n  }, [refIframe.current]);\n\n  return {\n    height,\n    locationHash,\n    activeTab,\n    connection,\n  };\n}\n"
  },
  {
    "path": "ui/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"allowSyntheticDefaultImports\": true,\n    \"downlevelIteration\": true,\n    \"esModuleInterop\": true,\n    \"experimentalDecorators\": true,\n    \"jsx\": \"react\",\n    \"lib\": [\n      \"es5\",\n      \"dom\"\n    ],\n    \"moduleResolution\": \"node\",\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"skipLibCheck\": true,\n    \"target\": \"es2015\",\n    \"types\": [\n      \"node\",\n      \"jest\"\n    ]\n  },\n  \"include\": [\n    \"src/**/*.ts\",\n    \"src/**/*.tsx\"\n  ],\n  \"exclude\": [\n    \"node_modules\"\n  ]\n}"
  }
]