├── .changeset
└── config.json
├── .editorconfig
├── .github
└── workflows
│ ├── main.yml
│ ├── release-pull-request.yml
│ └── release.yml
├── .gitignore
├── .npmrc
├── .nvmrc
├── .pnpmfile.cjs
├── .vscode
├── extensions.json
└── settings.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── CONTRIBUTING.zh-CN.md
├── LICENSE
├── README.md
├── README.zh-CN.md
├── biome.json
├── document
├── en
│ ├── api
│ │ ├── app.md
│ │ ├── ejs.md
│ │ ├── fs.md
│ │ ├── git.md
│ │ ├── handlebars.md
│ │ ├── index.md
│ │ ├── input.md
│ │ ├── json.md
│ │ └── npm.md
│ ├── concept.md
│ └── start.md
└── zh
│ ├── api
│ ├── app.md
│ ├── ejs.md
│ ├── fs.md
│ ├── git.md
│ ├── handlebars.md
│ ├── index.md
│ ├── input.md
│ ├── json.md
│ └── npm.md
│ ├── concept.md
│ └── start.md
├── modern.config.js
├── monorepo.code-workspace
├── package.json
├── packages
├── api
│ ├── app
│ │ ├── .npmignore
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── modern.config.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── index.ts
│ │ │ ├── locale
│ │ │ │ ├── en.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── zh.ts
│ │ │ └── utils
│ │ │ │ ├── checkUseNvm.ts
│ │ │ │ └── transform.ts
│ │ └── tsconfig.json
│ ├── ejs
│ │ ├── .npmignore
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── modern.config.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── index.ts
│ │ │ └── utils
│ │ │ │ ├── index.ts
│ │ │ │ └── renderString.ts
│ │ ├── tests
│ │ │ ├── tsconfig.json
│ │ │ └── utils.test.ts
│ │ └── tsconfig.json
│ ├── fs
│ │ ├── .npmignore
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── modern.config.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ └── index.ts
│ │ └── tsconfig.json
│ ├── git
│ │ ├── .npmignore
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── modern.config.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── index.ts
│ │ │ └── utils
│ │ │ │ └── index.ts
│ │ ├── tests
│ │ │ ├── index.test.ts
│ │ │ └── tsconfig.json
│ │ └── tsconfig.json
│ ├── handlebars
│ │ ├── .npmignore
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── modern.config.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── index.ts
│ │ │ └── utils
│ │ │ │ ├── index.ts
│ │ │ │ └── renderString.ts
│ │ ├── tests
│ │ │ ├── tsconfig.json
│ │ │ └── utils.test.ts
│ │ └── tsconfig.json
│ ├── json
│ │ ├── .npmignore
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── modern.config.ts
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── index.ts
│ │ │ └── utils
│ │ │ │ └── index.ts
│ │ ├── tests
│ │ │ ├── index.test.ts
│ │ │ └── tsconfig.json
│ │ └── tsconfig.json
│ └── npm
│ │ ├── .npmignore
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── modern.config.ts
│ │ ├── package.json
│ │ ├── src
│ │ ├── index.ts
│ │ └── utils
│ │ │ ├── index.ts
│ │ │ └── install.ts
│ │ ├── tests
│ │ ├── tsconfig.json
│ │ └── utils.test.ts
│ │ └── tsconfig.json
├── cli
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── bin
│ │ └── run.js
│ ├── modern.config.ts
│ ├── package.json
│ ├── src
│ │ ├── actions
│ │ │ └── genAction.ts
│ │ ├── index.ts
│ │ └── utils
│ │ │ └── index.ts
│ └── tsconfig.json
├── core
│ ├── .npmignore
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── modern.config.ts
│ ├── package.json
│ ├── src
│ │ ├── codesmith
│ │ │ ├── constants.ts
│ │ │ └── index.ts
│ │ ├── constants.ts
│ │ ├── generator
│ │ │ ├── constants.ts
│ │ │ └── index.ts
│ │ ├── index.ts
│ │ ├── logger
│ │ │ ├── constants.ts
│ │ │ └── index.ts
│ │ ├── materials
│ │ │ ├── FsMaterial.ts
│ │ │ ├── FsResource.ts
│ │ │ ├── constants.ts
│ │ │ └── index.ts
│ │ └── utils
│ │ │ ├── downloadPackage.ts
│ │ │ ├── fsExists.ts
│ │ │ ├── getGeneratorDir.ts
│ │ │ ├── getNpmPackageInfo.ts
│ │ │ ├── getNpmRegistry.ts
│ │ │ ├── getNpmTarballUrl.ts
│ │ │ ├── getNpmVersion.ts
│ │ │ ├── getPackageInfo.ts
│ │ │ ├── index.ts
│ │ │ ├── nodeRequire.ts
│ │ │ ├── packageManager.ts
│ │ │ └── timeoutPromise.ts
│ ├── tests
│ │ ├── tsconfig.json
│ │ └── utils
│ │ │ ├── downloadPackage.test.ts
│ │ │ ├── fsExists.test.ts
│ │ │ ├── getGeneratorDir.test.ts
│ │ │ ├── getNpmVersion.test.ts
│ │ │ ├── getNpmtarballUrl.test.ts
│ │ │ └── getPackageInfo.test.ts
│ └── tsconfig.json
├── formily
│ ├── .npmignore
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── modern.config.ts
│ ├── package.json
│ ├── src
│ │ ├── index.ts
│ │ ├── inquirer.ts
│ │ ├── prompt.ts
│ │ └── transform.ts
│ ├── tests
│ │ ├── prompt.test.ts
│ │ ├── transform.test.ts
│ │ └── tsconfig.json
│ └── tsconfig.json
├── global
│ ├── .npmignore
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── modern.config.ts
│ ├── package.json
│ ├── src
│ │ └── index.ts
│ └── tsconfig.json
├── inquirer
│ ├── .npmignore
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── modern.config.ts
│ ├── package.json
│ ├── src
│ │ ├── index.ts
│ │ ├── list.ts
│ │ ├── types
│ │ │ └── index.d.ts
│ │ └── utils
│ │ │ ├── index.ts
│ │ │ └── pointer.ts
│ └── tsconfig.json
└── utils
│ ├── .npmignore
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── modern.config.ts
│ ├── package.json
│ ├── src
│ ├── chalk.ts
│ ├── execa.ts
│ ├── fs-extra.ts
│ ├── glob.ts
│ ├── index.ts
│ ├── lodash.ts
│ ├── npm.ts
│ ├── ora.ts
│ └── semver.ts
│ └── tsconfig.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
├── scripts
├── .eslintrc.js
├── package.json
├── src
│ └── get-release-version.ts
└── tsconfig.json
└── tsconfig.json
/.changeset/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://unpkg.com/@changesets/config@1.6.0/schema.json",
3 | "changelog": "@changesets/cli/changelog",
4 | "commit": false,
5 | "fixed": [["@modern-js/*"]],
6 | "access": "restricted",
7 | "baseBranch": "main",
8 | "updateInternalDependencies": "patch",
9 | "ignore": [],
10 | "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
11 | "onlyUpdatePeerDependentsWhenOutOfRange": true
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: http://EditorConfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | charset = utf-8
7 | end_of_line = lf
8 | indent_style = space
9 | insert_final_newline = true
10 |
11 | [*.{js,jsx,ts,tsx,mjs,mjsx,cjs,cjsx,sh,rb}]
12 | indent_size = 2
13 | max_line_length = 80
14 | trim_trailing_whitespace = true
15 |
16 | [*.py]
17 | indent_size = 4
18 | max_line_length = 80
19 | trim_trailing_whitespace = true
20 |
21 | [*.{css,scss,less,html,hbs,ejs,json,code-workspace,yml,yaml,gql}]
22 | indent_size = 2
23 | trim_trailing_whitespace = true
24 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow to help you get started with Actions
2 |
3 | name: CI
4 |
5 | # Controls when the workflow will run
6 | on:
7 | # Triggers the workflow on push or pull request events but only for the main branch
8 | push:
9 | branches: [main]
10 | pull_request:
11 | branches: [main]
12 |
13 | # Allows you to run this workflow manually from the Actions tab
14 | workflow_dispatch:
15 |
16 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
17 | jobs:
18 | # This workflow contains a single job called "build"
19 | test:
20 | # The type of runner that the job will run on
21 | runs-on: ubuntu-latest
22 |
23 | # Steps represent a sequence of tasks that will be executed as part of the job
24 | steps:
25 | - name: Checkout
26 | uses: actions/checkout@v4
27 | with:
28 | fetch-depth: 1
29 |
30 | - name: git init
31 | run: git config --global user.email "modern@bytedance.com" && git config --global user.name "modern"
32 |
33 | # Runs a single command using the runners shell
34 | - name: Install Pnpm
35 | run: npm install -g --force corepack && corepack enable
36 |
37 | - name: install
38 | run: pnpm i --ignore-scripts
39 |
40 | - name: build
41 | run: pnpm run prepare
42 |
43 | - name: lint
44 | run: pnpm run lint
45 |
46 | - name: test
47 | run: pnpm -r test
48 |
--------------------------------------------------------------------------------
/.github/workflows/release-pull-request.yml:
--------------------------------------------------------------------------------
1 | name: Release Pull Request
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | version:
7 | type: choice
8 | description: 'Release Type(canary, alpha, beta, latest)'
9 | required: true
10 | default: 'latest'
11 | options:
12 | - canary
13 | - alpha
14 | - beta
15 | - latest
16 |
17 | jobs:
18 | release:
19 | name: Create Release Pull Request
20 | runs-on: ubuntu-latest
21 | steps:
22 | - name: Checkout Repo
23 | uses: actions/checkout@master
24 | with:
25 | # This makes Actions fetch only one branch to release
26 | fetch-depth: 100
27 |
28 | - name: Install Pnpm
29 | run: npm install -g --force corepack && corepack enable
30 |
31 | - name: Setup Node.js 18
32 | uses: actions/setup-node@v3
33 | with:
34 | node-version: '18'
35 | cache: 'pnpm'
36 |
37 | - name: Install Dependencies
38 | run: pnpm install --ignore-scripts
39 |
40 | - name: Create Release Pull Request
41 | uses: web-infra-dev/actions@v2
42 | with:
43 | # this expects you to have a script called release which does a build for your packages and calls changeset publish
44 | version: ${{ github.event.inputs.version }}
45 | versionNumber: 'auto'
46 | type: 'pull request'
47 | tools: 'modern'
48 | env:
49 | GITHUB_TOKEN: ${{ secrets.REPO_SCOPED_TOKEN }}
50 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
51 | REPOSITORY: ${{ github.repository }}
52 | REF: ${{ github.ref }}
53 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | version:
7 | type: choice
8 | description: 'Release Version(canary, alpha, beta, latest)'
9 | required: true
10 | default: 'canary'
11 | options:
12 | - canary
13 | - alpha
14 | - beta
15 | - latest
16 | branch:
17 | description: 'Release Branch(confirm release branch)'
18 | required: true
19 | default: 'main'
20 |
21 | permissions:
22 | id-token: write
23 |
24 | jobs:
25 | release:
26 | name: Release
27 | runs-on: ubuntu-latest
28 | steps:
29 | - name: Checkout Repo
30 | uses: actions/checkout@v3
31 | with:
32 | # This makes Actions fetch only one branch to release
33 | fetch-depth: 1
34 |
35 | - name: Install Pnpm
36 | run: npm install -g --force corepack && corepack enable
37 |
38 | - name: Setup Node.js 18
39 | uses: actions/setup-node@v3
40 | with:
41 | node-version: '18'
42 | cache: 'pnpm'
43 |
44 | - name: Install Dependencies
45 | run: pnpm install --ignore-scripts
46 |
47 | - name: Prepare
48 | run: pnpm run prepare
49 |
50 | - name: Release
51 | uses: web-infra-dev/actions@v2
52 | with:
53 | # this expects you to have a script called release which does a build for your packages and calls changeset publish
54 | version: ${{ github.event.inputs.version }}
55 | branch: ${{ github.event.inputs.branch }}
56 | type: 'release'
57 | tools: 'modern'
58 | env:
59 | GITHUB_TOKEN: ${{ secrets.REPO_SCOPED_TOKEN }}
60 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
61 | REPOSITORY: ${{ github.repository }}
62 | REF: ${{ github.ref }}
63 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | .pnp
4 | .pnp.js
5 | .env.*.local
6 | .history
7 | .rts*
8 | *.log*
9 | *.pid
10 | *.pid.*
11 | *.report
12 | *.lcov
13 | lib-cov
14 |
15 | node_modules/
16 | .npm
17 | .lock-wscript
18 | .yarn-integrity
19 | .node_repl_history
20 | .nyc_output
21 | *.tsbuildinfo
22 | .eslintcache
23 | .sonarlint
24 |
25 | dist/
26 | coverage/
27 | release/
28 | output/
29 | output_resource/
30 |
31 | .vscode/**/*
32 | !.vscode/settings.json
33 | !.vscode/extensions.json
34 | .idea/
35 |
36 | **/*/typings/auto-generated
37 | **/*/adapters/**/index.ts
38 | **/*/adapters/**/index.js
39 |
40 | .changeset/pre.json
41 | .pnpm-store/
42 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | registry = 'https://registry.npmjs.org/'
2 |
3 | link-workspace-packages=false
4 | strict-peer-dependencies=false
5 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | lts/gallium
2 |
--------------------------------------------------------------------------------
/.pnpmfile.cjs:
--------------------------------------------------------------------------------
1 | function readPackage(pkg, _context) {
2 | // Override the manifest of foo@1.x after downloading it from the registry
3 | // fix @samverschueren/stream-to-observable bug
4 | if (pkg.name === '@samverschueren/stream-to-observable') {
5 | pkg.dependencies = {
6 | ...pkg.dependencies,
7 | 'any-observable': '^0.5.1',
8 | };
9 | }
10 |
11 | return pkg;
12 | }
13 |
14 | module.exports = {
15 | hooks: {
16 | readPackage,
17 | },
18 | };
19 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "styled-components.vscode-styled-components",
4 | "cpylua.language-postcss",
5 | "EditorConfig.editorconfig",
6 | "drKnoxy.eslint-disable-snippets",
7 | "mkaufman.htmlhint",
8 | "streetsidesoftware.code-spell-checker",
9 | "codezombiech.gitignore",
10 | "aaron-bond.better-comments",
11 | "jasonnutter.search-node-modules",
12 | "jock.svg",
13 | "mikestead.dotenv",
14 | "vscode-icons-team.vscode-icons",
15 | "biomejs.biome"
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.associations": {
3 | ".code-workspace": "jsonc",
4 | ".babelrc": "json",
5 | ".eslintrc": "jsonc",
6 | ".eslintrc*.json": "jsonc",
7 | ".stylelintrc": "jsonc",
8 | "stylelintrc": "jsonc",
9 | ".htmlhintrc": "jsonc",
10 | "htmlhintrc": "jsonc",
11 | "Procfile*": "shellscript",
12 | "README": "markdown",
13 | "*.ttml": "xml",
14 | "*.ttss": "css"
15 | },
16 | "search.useIgnoreFiles": true,
17 | "search.exclude": {
18 | "**/dist": true,
19 | "**/*.log": true,
20 | "**/*.pid": true,
21 | "**/.git": true,
22 | "**/compiled": true,
23 | "**/coverage": true,
24 | "**/node_modules": true,
25 | "**/bower_components": true
26 | },
27 | //
28 | "editor.rulers": [80, 120],
29 | "files.eol": "\n",
30 | "files.trimTrailingWhitespace": true,
31 | "files.insertFinalNewline": true,
32 | //
33 | "cSpell.diagnosticLevel": "Hint",
34 | "javascript.validate.enable": false,
35 | "typescript.validate.enable": true,
36 | "css.validate": false,
37 | "scss.validate": false,
38 | "less.validate": false,
39 | "editor.defaultFormatter": "biomejs.biome",
40 | "editor.formatOnSave": true,
41 | "editor.codeActionsOnSave": {
42 | "quickfix.biome": "explicit"
43 | },
44 | "javascript.format.enable": false,
45 | "typescript.format.enable": false,
46 | //
47 | "json.format.enable": false,
48 | "emmet.triggerExpansionOnTab": true,
49 | "typescript.tsdk": "node_modules/typescript/lib",
50 | "files.exclude": {
51 | "**/.git": true,
52 | "**/.svn": true,
53 | "**/.hg": true,
54 | "**/CVS": true,
55 | "**/.DS_Store": true,
56 | "**/Thumbs.db": true,
57 | "**/node_modules": false
58 | },
59 | "[typescript]": {
60 | "editor.defaultFormatter": "biomejs.biome"
61 | },
62 | "[typescriptreact]": {
63 | "editor.defaultFormatter": "biomejs.biome"
64 | },
65 | "[json]": {
66 | "editor.defaultFormatter": "biomejs.biome"
67 | },
68 | "[jsonc]": {
69 | "editor.defaultFormatter": "esbenp.prettier-vscode"
70 | },
71 | "[javascriptreact]": {
72 | "editor.defaultFormatter": "biomejs.biome"
73 | },
74 | "[javascript]": {
75 | "editor.defaultFormatter": "biomejs.biome"
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Modern.js
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CodeSmith
6 |
7 |
8 | A cool code generation tool.
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | English | [简体中文](./README.zh-CN.md)
18 |
19 | ## Introduce
20 |
21 | CodeSmith is a code generation tool that uses the concept of micro-generators to complete the entire code generation process.
22 |
23 | Traditional scaffolding usually provides project-level generators based on templates, which are used once and then discarded. After generating the project, they do not help with subsequent business iterations.
24 |
25 | Micro-generators focus on the entire lifecycle of the project. They can generate file modules of various granularities and types in the project (such as entry, component, model, etc.), and can also generate abstract business logic (which may not create new files, but automatically refactor existing files). Micro-generators are not one-time tools used only when creating projects, but a toolbox that accompanies the project's subsequent iterative process.
26 |
27 | [`@modern-js/create`](https://www.npmjs.com/package/@modern-js/create) is based on CodeSmith and dynamically generates different initial files and codes or modifies and restructures existing files and codes based on different micro-generators loaded on demand during the Q&A process.
28 |
29 | The new command provided by Modern.js is also based on CodeSmith and is used to create project elements and enable functions during the project development process.
30 |
31 | ## Document
32 |
33 | - [Quick Start](./document/en/start.md)
34 | - [Concepts](./document/en/concept.md)
35 | - [API](./document/en/api/index.md)
36 |
37 | ## Contributing
38 |
39 | > New contributors welcome!
40 |
41 | Please read the [Contributing Guide](https://github.com/web-infra-dev/codesmith/blob/main/CONTRIBUTING.md).
42 |
43 | ### Code of Conduct
44 |
45 | This repo has adopted the Bytedance Open Source Code of Conduct. Please check [Code of Conduct](./CODE_OF_CONDUCT.md) for more details.
46 |
47 | ## License
48 |
49 | Modern.js is [MIT licensed](https://github.com/web-infra-dev/codesmith/blob/main/LICENSE).
50 |
--------------------------------------------------------------------------------
/README.zh-CN.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CodeSmith
6 |
7 |
8 | A cool code generation tool.
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | [English](./README.md) | 简体中文
18 |
19 | ## 介绍
20 |
21 | CodeSmith 是一个代码生成工具,使用微生成器的理念来完成整个代码生成过程。
22 |
23 | 传统脚手架通常提供整个项目级别的生成器,基于模板,一用即抛,生成完项目之后,对后续的业务迭代没有帮助。
24 |
25 | 微生成器关注的是项目的整个生命周期,既可以生成项目中各种粒度各种类型的文件模块(比如 entry、component、model 等),也可以生成抽象的业务逻辑(可能不创建新文件,而是在现有文件上做自动重构)。微生成器不是只在最初创建项目的时候使用的一次性工具,而是伴随项目后续迭代过程的工具箱。
26 |
27 | [`@modern-js/create`](https://www.npmjs.com/package/@modern-js/create) 是基于 CodeSmith 实现的,会在问答过程中,按需加载不同的微生成器,动态生成不同的初始文件和代码或修改重组已有的文件和代码。
28 |
29 | Modern.js 提供的 `new` 命令也是基于 CodeSmith 实现的,用于项目开发过程中新建项目元素、开启功能等。
30 |
31 | ## 文档
32 |
33 | - [快速上手](./document/zh/start.md)
34 | - [核心概念](./document/zh/concept.md)
35 | - [API](./document/zh/api/index.md)
36 |
37 | ## 参与贡献
38 |
39 | > 欢迎参与 CodeSmith 贡献!
40 |
41 | 请阅读 [贡献指南](https://github.com/web-infra-dev/codesmith/blob/main/CONTRIBUTING.zh-CN.md) 来共同参与 CodeSmith 的建设。
42 |
43 | ### 行为准则
44 |
45 | 本仓库采纳了字节跳动的开源项目行为准则。请点击 [行为准则](./CODE_OF_CONDUCT.md) 查看更多的信息。
46 |
47 | ## License
48 |
49 | CodeSmith 项目基于 [MIT 协议](https://github.com/web-infra-dev/codesmith/blob/main/LICENSE),请自由地享受和参与开源。
50 |
--------------------------------------------------------------------------------
/biome.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://biomejs.dev/schemas/1.8.3/schema.json",
3 | "vcs": {
4 | "enabled": true,
5 | "defaultBranch": "main",
6 | "clientKind": "git",
7 | "useIgnoreFile": true
8 | },
9 | "formatter": {
10 | "enabled": true,
11 | "indentStyle": "space",
12 | "ignore": ["package.json"]
13 | },
14 | "javascript": {
15 | "formatter": {
16 | "quoteStyle": "single",
17 | "arrowParentheses": "asNeeded",
18 | "jsxQuoteStyle": "double",
19 | "lineWidth": 80
20 | }
21 | },
22 | "linter": {
23 | "enabled": true,
24 | "rules": {
25 | "recommended": true,
26 | "style": {
27 | "useNodejsImportProtocol": "off",
28 | "noNonNullAssertion": "off",
29 | "useDefaultParameterLast": "off"
30 | },
31 | "suspicious": {
32 | "noExplicitAny": "off"
33 | },
34 | "complexity": {
35 | "noForEach": "off"
36 | }
37 | }
38 | },
39 | "organizeImports": {
40 | "enabled": true
41 | },
42 | "files": {
43 | "ignoreUnknown": true,
44 | "ignore": [".vscode/**/*", "node_modules/**/*", "dist/**/*"]
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/document/en/api/ejs.md:
--------------------------------------------------------------------------------
1 | # EJS API
2 |
3 | English | [简体中文](../../zh/api/ejs.md)
4 |
5 | The EJS API is provided by the `@modern-js/codesmith-api-ejs` package, which provides methods for rendering single files and folders using [EJS](https://ejs.co/).
6 |
7 | ## Usage
8 |
9 | ```ts
10 | import { EjsAPI } from '@modern-js/codesmith-api-ejs';
11 |
12 | export default async (context: GeneratorContext, generator: GeneratorCore) => {
13 | const ejsAPI = new EjsAPI(generator);
14 | await ejsAPI.renderTemplate(
15 | context.current!.material.get('templates/a.js.ejs'),
16 | 'b.js',
17 | { name: 'test ejs' },
18 | );
19 | };
20 | ```
21 |
22 | - Create an instance of EjsAPI with the generator as the parameter.
23 | - Call the API methods provided on the instance.
24 |
25 | ## API
26 |
27 | ### renderTemplate
28 |
29 | Render a single EJS template file. It is defined as follows:
30 |
31 | ```ts
32 | renderTemplate: (
33 | templateResource: FsResource,
34 | target: string,
35 | parameters?: Record,
36 | ) => Promise;
37 | ```
38 |
39 | - `templateResource`: The template file, defined by `context.current!.material.get()`.
40 | - `target`: The target file path.
41 | - `parameters`: The values of template variables. When EJS variables exist in the template, define the corresponding variable values.
42 |
43 | ### renderTemplateDir
44 |
45 | Batch render EJS template folders. It is defined as follows:
46 |
47 | ```ts
48 | type TargetFunction = (globMatch: string) => string;
49 | type RenderTemplateDirOptions = {
50 | nodir?: boolean;
51 | dot?: boolean;
52 | ignore?: string | readonly string[];
53 | parameters?: Record;
54 | };
55 | renderTemplateDir: (
56 | material: FsMaterial,
57 | findGlob: string,
58 | target: TargetFunction,
59 | options?: RenderTemplateDirOptions,
60 | ) => Promise;
61 | ```
62 |
63 | - `material`: The file resources of the current micro-generator, with a value of `context.current!.material`.
64 | - `findGlob`: The matching rule for template files, which supports the [glob](https://www.npmjs.com/package/glob) format. For example, `templates/**/*` matches all files in the templates directory.
65 | - `target`: The target file name, which renames files that meet the criteria. The function takes the file name as its parameter.
66 | - `options.parameters`: The values of template variables. When EJS variables exist in the template, define the corresponding variable values.
67 | - `options.nodir`/`options.dot`/`options.ignore`: glob matching parameters.
68 |
69 | Example:
70 |
71 | ```ts
72 | const ejsAPI = new EjsAPI(generator);
73 | await ejsAPI.renderTemplateDir(
74 | context.current!.material,
75 | 'templates/**/*',
76 | (resourceKey: string) =>
77 | resourceKey.replace('templates/', '').replace('.ejs', ''),
78 | { parameters: { name: 'name' } },
79 | );
80 | ```
81 |
--------------------------------------------------------------------------------
/document/en/api/fs.md:
--------------------------------------------------------------------------------
1 | # FS API
2 |
3 | English | [简体中文](../../zh/api/fs.md)
4 |
5 | The FS API is provided by the `@modern-js/codesmith-api-fs` package, which provides methods for rendering single files and folders.
6 |
7 | ## Usage
8 |
9 | ```ts
10 | import { FsAPI } from '@modern-js/codesmith-api-fs';
11 |
12 | export default async (context: GeneratorContext, generator: GeneratorCore) => {
13 | const fsAPI = new FsAPI(generator);
14 | await fsAPI.renderFile(
15 | context.current!.material.get('templates/a.txt'),
16 | 'b.txt',
17 | );
18 | };
19 | ```
20 |
21 | - Create an instance of FsAPI with the generator as the parameter.
22 | - Call the API methods provided on the instance.
23 |
24 | ## API
25 |
26 | ### renderFile
27 |
28 | Render a single file. It is defined as follows:
29 |
30 | ```ts
31 | renderFile: (resource: FsResource, target: string) => Promise;
32 | ```
33 |
34 | - `resource`: Define by `context.current!.material.get()`.
35 | - `target`: The target file path.
36 |
37 | ### renderDir
38 |
39 | Batch render folders. It is defined as follows:
40 |
41 | ```ts
42 | type TargetFunction = (globMatch: string) => string;
43 | type RenderDirOptions = {
44 | nodir?: boolean;
45 | dot?: boolean;
46 | ignore?: string | readonly string[];
47 | };
48 | renderDir: (
49 | material: FsMaterial,
50 | findGlob: string,
51 | target: TargetFunction,
52 | options?: RenderDirOptions,
53 | ) => Promise;
54 | ```
55 |
56 | - `material`: The file resources of the current micro-generator, with a value of `context.current!.material`.
57 | - `findGlob`: The matching rule for template files, which supports the [glob](https://www.npmjs.com/package/glob) format. For example, `templates/**/*` matches all files in the templates directory.
58 | - `target`: The target file name, which renames files that meet the criteria. The function takes the file name as its parameter.
59 | - `options.nodir`/`options.dot`/`options.ignore`: glob matching parameters.
60 |
61 | Example:
62 |
63 | ```ts
64 | const fsAPI = new FsAPI(generator);
65 | await fsAPI.renderDir(
66 | context.current!.material,
67 | 'templates/**/*',
68 | (resourceKey: string) =>
69 | resourceKey.replace('templates/', ''),
70 | );
71 | ```
72 |
--------------------------------------------------------------------------------
/document/en/api/git.md:
--------------------------------------------------------------------------------
1 | # Git API
2 |
3 | English | [简体中文](../../zh/api/git.md)
4 |
5 | The Git API is provided by the `@modern-js/codesmith-api-git` package, which provides methods for initializing Git repositories, committing Git commits, etc.
6 |
7 | ## Usage
8 |
9 | ```ts
10 | import { GitAPI } from '@modern-js/codesmith-api-git';
11 |
12 | export default async (context: GeneratorContext, generator: GeneratorCore) => {
13 | const gitApi = new GitAPI(generatorCore, generatorContext);
14 | await gitApi.initGitRepo();
15 | };
16 | ```
17 |
18 | - Create an instance of GitAPI with the same parameters as the micro-generator.
19 | - Call the API methods provided on the instance.
20 |
21 | ## API
22 |
23 | ### isInGitRepo
24 |
25 | Determine if the current project is a git repository. It is defined as follows:
26 |
27 | ```ts
28 | isInGitRepo: (cwd?: string) => Promise;
29 | ```
30 |
31 | - `cwd`: The project directory, with a default value of `generator.outputPath`.
32 |
33 | ### initGitRepo
34 |
35 | Initialize the current project as a git repository. It is defined as follows:
36 |
37 | ```ts
38 | initGitRepo(cwd?: string, force?: boolean): Promise;
39 | ```
40 |
41 | - `cwd`: The project directory, with a default value of `generator.outputPath`.
42 | - `force`: Whether to force initialization if the current directory is already a git repository.
43 |
44 | ### addAndCommit
45 |
46 | Commit current changes. It is defined as follows:
47 |
48 | ```ts
49 | addAndCommit(commitMessage: string, cwd?: string): Promise;
50 | ```
51 |
52 | - `commitMessage`: The commit message.
53 | - `cwd`: The project directory, with a default value of `generator.outputPath`.
54 |
--------------------------------------------------------------------------------
/document/en/api/handlebars.md:
--------------------------------------------------------------------------------
1 | # Handlebars API
2 |
3 | English | [简体中文](../../zh/api/handelbars.md)
4 |
5 | The Handlebars API is provided by the `@modern-js/codesmith-api-handlebars` package, which provides methods for rendering single files and folders using [Handlebars](https://handlebarsjs.com/).
6 |
7 | ## Usages
8 |
9 | ```ts
10 | import { HandlebarsAPI } from '@modern-js/codesmith-api-handlebars';
11 |
12 | export default async (context: GeneratorContext, generator: GeneratorCore) => {
13 | const handlebarsAPI = new HandlebarsAPI(generator);
14 | await handlebarsAPI.renderTemplate(
15 | context.current!.material.get('templates/a.js.handlebars'),
16 | 'b.js',
17 | { name: 'test handebars' },
18 | );
19 | };
20 | ```
21 |
22 | - Create an instance of HandlebarsAPI with the generator as the parameter.
23 | - Call the API methods provided on the instance.
24 |
25 | ## API
26 |
27 | ### registerHelp
28 |
29 | Register Handlebars helper code. It is defined as follows:
30 |
31 | ```ts
32 | registerHelp: (
33 | helpers: Record,
34 | ) => Promise;
35 | ```
36 |
37 | - `helpers`: Block helper code object. The use of block helper code can be found [here](https://handlebarsjs.com/guide/#block-helpers).
38 |
39 | ### registerPartials
40 |
41 | Register Handlebars code snippets. It is defined as follows:
42 |
43 | ```ts
44 | registerPartials: (
45 | partials: Record,
46 | ) => Promise;
47 | ```
48 |
49 | - `partials`: Code snippet object. The use of code snippets can be found [here](https://handlebarsjs.com/guide/#code-snippets).
50 |
51 | ### renderTemplate
52 |
53 | Render a single Handlebars template file. It is defined as follows:
54 |
55 | ```ts
56 | renderTemplate: (
57 | templateResource: FsResource,
58 | target: string,
59 | parameters?: Record,
60 | ) => Promise;
61 | ```
62 |
63 | - `templateResource`: The template file, obtained through `context.current!.material.get()`.
64 | - `target`: The target file path.
65 | - `parameters`: The values of template variables. When Handlebars variables exist in the template, define the corresponding variable values.
66 |
67 | ### renderTemplateDir
68 |
69 | Batch render Handlebars template folders. It is defined as follows:
70 |
71 | ```ts
72 | type TargetFunction = (globMatch: string) => string;
73 | type RenderTemplateDirOptions = {
74 | nodir?: boolean;
75 | dot?: boolean;
76 | ignore?: string | readonly string[];
77 | parameters?: Record;
78 | };
79 | renderTemplateDir: (
80 | material: FsMaterial,
81 | findGlob: string,
82 | target: TargetFunction,
83 | options?: RenderTemplateDirOptions,
84 | ) => Promise;
85 | ```
86 |
87 | - `material`: The file resources of the current micro-generator, with a value of `context.current!.material`.
88 | - `findGlob`: The matching rule for template files, which supports the [glob](https://www.npmjs.com/package/glob) format. For example, `templates/**/*` matches all files in the templates directory.
89 | - `target`: The target file name, which renames files that meet the criteria. The function takes the file name as its parameter.
90 | - `options.parameters`: The values of template variables. When Handlebars variables exist in the template, define the corresponding variable values.
91 | - `options.nodir`/`options.dot`/`options.ignore`: glob matching parameters.
92 |
93 | Example:
94 |
95 | ```ts
96 | const handlebarsAPI = new HandlebarsAPI(generator);
97 | await handlebarsAPI.renderTemplateDir(
98 | context.current!.material,
99 | 'templates/**/*',
100 | (resourceKey: string) =>
101 | resourceKey.replace('templates/', '').replace('.handlebars', ''),
102 | { parameters: { name: 'name' } },
103 | );
104 | ```
105 |
--------------------------------------------------------------------------------
/document/en/api/index.md:
--------------------------------------------------------------------------------
1 | # API
2 |
3 | English | [简体中文](../../zh/api/index.md)
4 |
5 | CodeSmith API is provided by different NPM packages, and you can install different dependencies according to your needs to use the API.
6 |
7 | - [App API](./app.md)
8 |
9 | - [Handlebars API](./handlebars.md)
10 |
11 | - [EJS API](./ejs.md)
12 |
13 | - [JSON API](./json.md)
14 |
15 | - [FS API](./fs.md)
16 |
17 | - [Git API](./git.md)
18 |
19 | - [NPM API](./npm.md)
20 |
--------------------------------------------------------------------------------
/document/en/api/input.md:
--------------------------------------------------------------------------------
1 | # Input
2 |
3 | English | [简体中文](../../zh/api/input.md)
4 |
5 | Each customized template provides a way to interact with users through Input, which is defined using JSON Schema:
6 |
7 | For example:
8 |
9 | ```js
10 | const schema = {
11 | type: 'object',
12 | properties: {
13 | language: {
14 | type: 'string',
15 | title: 'Please select the programming language:',
16 | enum: [
17 | { label: 'TS', value: 'ts' },
18 | { label: 'ES6+', value: 'js' },
19 | ],
20 | },
21 | },
22 | };
23 | ```
24 |
25 | JSON Schema format is based on the open source [Formily](https://formilyjs.org/) Schema format. The following are the supported fields:
26 |
27 | ## type
28 |
29 | Defines the type of the current schema. Currently supported types are `string`, `number`, and `object`. `string` type is used for string inputs and dropdown options. `object` type is used for nesting schemas and needs to be used with the `properties` attribute.
30 |
31 | ## title
32 |
33 | Defines the display name of the current schema.
34 |
35 | ## default
36 |
37 | Defines the default value of the current schema.
38 |
39 | ## enum
40 |
41 | Defines the options when the current schema is a dropdown selection.
42 |
43 | The sub-items support `string` or `{ label: string; value: string}` types. When the value and display value are the same in the dropdown options, `string` can be used directly to define the options.
44 |
45 | When representing multiple selection options, set the `default` field to `[]`.
46 |
47 | ## x-validator
48 |
49 | Defines the validation rules for the current schema. When the schema is an input type, validation will be automatically performed after input completion.
50 |
51 | The validation rules supported here are provided by [Formily](https://formilyjs.org/zh-CN/guide/advanced/validate), for example, the maximum value is 5:
52 |
53 | ```js
54 | const schema = {
55 | type: 'object',
56 | properties: {
57 | max_5: {
58 | type: 'number',
59 | title: 'Maximum value (>5 will cause an error)',
60 | 'x-validator': {
61 | maximum: 5,
62 | },
63 | },
64 | },
65 | };
66 | ```
67 |
68 | It also supports using validation functions directly:
69 |
70 | ```js
71 | const schema = {
72 | type: 'object',
73 | properties: {
74 | path: {
75 | type: 'string',
76 | title: 'Can only contain numbers and letters',
77 | 'x-validator': value => {
78 | if (!/^[0-9a-zA-Z]*$/g.test(value)) {
79 | return 'Incorrect format';
80 | }
81 | return '';
82 | },
83 | },
84 | },
85 | };
86 | ```
87 |
88 | ## x-reactions
89 |
90 | Use linkage between schemas. This is exactly the same as [Formily linkage rules](https://formilyjs.org/zh-CN/guide/advanced/linkages).
91 |
92 | For example:
93 |
94 | ```js
95 | const schema = {
96 | type: 'object',
97 | properties: {
98 | name: {
99 | type: 'string',
100 | title: 'Name',
101 | },
102 | path: {
103 | type: 'string',
104 | title: 'Path',
105 | 'x-reactions': [
106 | {
107 | dependencies: ['name'],
108 | fulfill: {
109 | state: {
110 | value: '{{$deps[0]}}',
111 | },
112 | },
113 | },
114 | ],
115 | },
116 | },
117 | };
118 | ```
119 |
120 | ## properties
121 |
122 | Organize the structure of the current schema and define sub-forms. `properties` is an object, where the `key` is the schema keyword and the `value` is a schema object as described above.
123 |
--------------------------------------------------------------------------------
/document/en/api/json.md:
--------------------------------------------------------------------------------
1 | # JSON API
2 |
3 | English | [简体中文](../../zh/api/json.md)
4 |
5 | The JSON API is provided by the `@modern-js/codesmith-api-json` package, which provides methods for obtaining JSON file content, updating JSON files, etc.
6 |
7 | ## Usage
8 |
9 | ```ts
10 | import { JsonAPI } from '@modern-js/codesmith-api-json';
11 |
12 | export default async (context: GeneratorContext, generator: GeneratorCore) => {
13 | const jsonAPI = new JsonAPI(generator);
14 | await jsonAPI.update(context.materials.default.get('package.json'), {
15 | query: {},
16 | update: {
17 | $set: {
18 | 'dependencies.@modern-js/plugin-bff': `^2.0.0`,
19 | },
20 | },
21 | });
22 | };
23 | ```
24 |
25 | - Create an instance of JsonAPI with the generator as the parameter.
26 | - Call the API methods provided on the instance.
27 |
28 | ## API
29 |
30 | ### get
31 |
32 | Get the content of a JSON file. It is defined as follows:
33 |
34 | ```ts
35 | get: (resource: FsResource) => Promise>;
36 | ```
37 |
38 | - `resource`: Defined by `context.materials.default.get()`.
39 |
40 | ### extend
41 |
42 | Merge an object into a JSON file. It is defined as follows:
43 |
44 | ```ts
45 | extend(resource: FsResource, obj: Record): Promise;
46 | ```
47 |
48 | - `resource`: Defined by `context.materials.default.get()`.
49 | - `obj`: The object to be merged.
50 |
51 | ### update
52 |
53 | Update the fields of an object into a JSON file. It is defined as follows:
54 |
55 | ```ts
56 | update(resource: FsResource, operation: {
57 | query: Record;
58 | update: Record;
59 | }): Promise;
60 | ```
61 |
62 | - `resource`: Defined `context.materials.default.get()`.
63 | - `operation`: The update operation, which can be found in detail in [declaration-update](https://www.npmjs.com/package/declaration-update).
64 |
--------------------------------------------------------------------------------
/document/en/api/npm.md:
--------------------------------------------------------------------------------
1 | # NPM API
2 |
3 | English | [简体中文](../../zh/api/npm.md)
4 |
5 | The NPM API is provided by the `@modern-js/codesmith-api-npm` package, which provides methods for installing dependencies using different package managers.
6 |
7 | ## Usage
8 |
9 | ```ts
10 | import { NpmAPI } from '@modern-js/codesmith-api-npm';
11 |
12 | export default async (context: GeneratorContext, generator: GeneratorCore) => {
13 | const npmApi = new NpmAPI(generator);
14 | await npmApi.pnpmInstall({});
15 | };
16 | ```
17 |
18 | - Create an instance of NpmAPI with the same parameters as the micro-generator.
19 | - Call the API methods provided on the instance.
20 |
21 | ## API
22 |
23 | ### npmInstall
24 |
25 | Install dependencies using npm. It is defined as follows:
26 |
27 | ```ts
28 | npmInstall: ({
29 | cwd,
30 | registryUrl,
31 | ignoreScripts,
32 | }: {
33 | cwd?: string;
34 | registryUrl?: string;
35 | ignoreScripts?: boolean;
36 | useNvm?: boolean;
37 | }) => Promise>;
38 | ```
39 |
40 | - `cwd`: The directory where the install command is executed, with a default value of `generator.outputPath`.
41 | - `registryUrl`: The registry parameter for installing dependencies.
42 | - `ignoreScripts`: Whether `--ignore-scripts` parameter is needed during dependency installation.
43 | - `useNvm`: Whether to use nvm to switch node versions.
44 |
45 | ### yarnInstall
46 |
47 | Install dependencies using yarn. It is defined as follows:
48 |
49 | ```ts
50 | yarnInstall: ({
51 | cwd,
52 | registryUrl,
53 | ignoreScripts,
54 | }: {
55 | cwd?: string;
56 | registryUrl?: string;
57 | ignoreScripts?: boolean;
58 | useNvm?: boolean;
59 | }) => Promise>;
60 | ```
61 |
62 | The parameters are the same as those of `npmInstall`.
63 |
64 | ### pnpmInstall
65 |
66 | Install dependencies using pnpm. It is defined as follows:
67 |
68 | ```ts
69 | pnpmInstall: ({
70 | cwd,
71 | registryUrl,
72 | ignoreScripts,
73 | }: {
74 | cwd?: string;
75 | registryUrl?: string;
76 | ignoreScripts?: boolean;
77 | useNvm?: boolean;
78 | }) => Promise>;
79 | ```
80 |
81 | The parameters are the same as those of `npmInstall`.
82 |
--------------------------------------------------------------------------------
/document/zh/api/ejs.md:
--------------------------------------------------------------------------------
1 | # EJS API
2 |
3 | [English](../../en/api/ejs.md) | 简体中文
4 |
5 | EJS API 是由 `@modern-js/codesmith-api-ejs` 包提供,该包提供了使用 [EJS](https://ejs.co/) 渲染单个文件及文件夹方法。
6 |
7 | ## 使用姿势
8 |
9 | ```ts
10 | import { EjsAPI } from '@modern-js/codesmith-api-ejs';
11 |
12 | export default async (context: GeneratorContext, generator: GeneratorCore) => {
13 | const ejsAPI = new EjsAPI(generator);
14 | await ejsAPI.renderTemplate(
15 | context.current!.material.get('templates/a.js.ejs'),
16 | 'b.js',
17 | { name: 'test ejs' },
18 | );
19 | };
20 | ```
21 |
22 | - 创建 EjsAPI 实例,参数为 generator。
23 | - 调用实例上提供的 API 方法。
24 |
25 | ## API
26 |
27 | ### renderTemplate
28 |
29 | 渲染单个 EJS 模板文件。其类型定义为:
30 |
31 | ```ts
32 | renderTemplate: (
33 | templateResource: FsResource,
34 | target: string,
35 | parameters?: Record,
36 | ) => Promise;
37 | ```
38 |
39 | - `templateResource`:模板文件,通过 `context.current!.material.get()` 获取。
40 | - `target`: 目标文件路径。
41 | - `parameters`:模板变量值,当模板中存在 EJS 变量时,定义对应变量值。
42 |
43 | ### renderTemplateDir
44 |
45 | 批量渲染 EJS 模板文件夹。其类型定义为:
46 |
47 | ```ts
48 | type TargetFunction = (globMatch: string) => string;
49 | type RenderTemplateDirOptions = {
50 | nodir?: boolean;
51 | dot?: boolean;
52 | ignore?: string | readonly string[];
53 | parameters?: Record;
54 | };
55 | renderTemplateDir: (
56 | material: FsMaterial,
57 | findGlob: string,
58 | target: TargetFunction,
59 | options?: RenderTemplateDirOptions,
60 | ) => Promise;
61 | ```
62 |
63 | - `material`:当前微生成器文件资源,其值为 `context.current!.material`。
64 | - `findGlob`:模板文件匹配规则,支持 [glob](https://www.npmjs.com/package/glob) 格式,例如:`templates/**/*` 为 templates 目录所有文件。
65 | - `target`:目标文件名称,对满足条件的文件进行重命名,函数参数为文件名称。
66 | - `options.parameters`:模板变量值,当模板中存在 EJS 变量时,定义对应变量值。
67 | - `options.nodir`/`options.dot`/`options.ignore`:glob 匹配参数。
68 |
69 | 示例:
70 |
71 | ```ts
72 | const ejsAPI = new EjsAPI(generator);
73 | await ejsAPI.renderTemplateDir(
74 | context.current!.material,
75 | 'templates/**/*',
76 | (resourceKey: string) =>
77 | resourceKey.replace('templates/', '').replace('.ejs', ''),
78 | { parameters: { name: 'name' } },
79 | );
80 | ```
81 |
--------------------------------------------------------------------------------
/document/zh/api/fs.md:
--------------------------------------------------------------------------------
1 | # FS API
2 |
3 | [English](../../en/api/fs.md) | 简体中文
4 |
5 | FS API 是由 `@modern-js/codesmith-api-fs` 包提供,该包提供了渲染单个文件及文件夹方法。
6 |
7 | ## 使用姿势
8 |
9 | ```ts
10 | import { FsAPI } from '@modern-js/codesmith-api-fs';
11 |
12 | export default async (context: GeneratorContext, generator: GeneratorCore) => {
13 | const fsAPI = new FsAPI(generator);
14 | await fsAPI.renderFile(
15 | context.current!.material.get('templates/a.txt'),
16 | 'b.txt',
17 | );
18 | };
19 | ```
20 |
21 | - 创建 FsAPI 实例,参数为 generator。
22 | - 调用实例上提供的 API 方法。
23 |
24 | ## API
25 |
26 | ### renderFile
27 |
28 | 渲染单个文件。其类型定义为:
29 |
30 | ```ts
31 | renderFile: (resource: FsResource, target: string) => Promise;
32 | ```
33 |
34 | - `resource`: `context.current!.material.get()` 获取。
35 | - `target`: 目标文件路径。
36 |
37 | ### renderDir
38 |
39 | 批量渲染文件夹。其类型定义为:
40 |
41 | ```ts
42 | type TargetFunction = (globMatch: string) => string;
43 | type RenderDirOptions = {
44 | nodir?: boolean;
45 | dot?: boolean;
46 | ignore?: string | readonly string[];
47 | };
48 | renderDir: (
49 | material: FsMaterial,
50 | findGlob: string,
51 | target: TargetFunction,
52 | options?: RenderDirOptions,
53 | ) => Promise;
54 | ```
55 |
56 | - `material`:当前微生成器文件资源,其值为 `context.current!.material`。
57 | - `findGlob`:模板文件匹配规则,支持 [glob](https://www.npmjs.com/package/glob) 格式,例如:`templates/**/*` 为 templates 目录所有文件。
58 | - `target`:目标文件名称,对满足条件的文件进行重命名,函数参数为文件名称。
59 | - `options.nodir`/`options.dot`/`options.ignore`:glob 匹配参数。
60 |
61 | 示例:
62 |
63 | ```ts
64 | const fsAPI = new FsAPI(generator);
65 | await fsAPI.renderDir(
66 | context.current!.material,
67 | 'templates/**/*',
68 | (resourceKey: string) =>
69 | resourceKey.replace('templates/', ''),
70 | );
71 | ```
72 |
--------------------------------------------------------------------------------
/document/zh/api/git.md:
--------------------------------------------------------------------------------
1 | # Git API
2 |
3 | [English](../../en/api/git.md) | 简体中文
4 |
5 | Git API 由 `@modern-js/codesmith-api-git` 包提供,该包提供了初始化 Git 仓库,提交 Git commit 等方法。
6 |
7 | ## 使用姿势
8 |
9 | ```ts
10 | import { GitAPI } from '@modern-js/codesmith-api-git';
11 |
12 | export default async (context: GeneratorContext, generator: GeneratorCore) => {
13 | const gitApi = new GitAPI(generatorCore, generatorContext);
14 | await gitApi.initGitRepo();
15 | };
16 | ```
17 |
18 | - 创建 GitAPI 实例,参数和微生成器参数一致。
19 | - 调用实例上提供的 API 方法。
20 |
21 | ## API
22 |
23 | ### isInGitRepo
24 |
25 | 判断当前项目是否为 Git 仓库。其类型定义为:
26 |
27 | ```ts
28 | isInGitRepo: (cwd?: string) => Promise;
29 | ```
30 |
31 | - `cwd`:项目目录,默认为 `generator.outputPath`。
32 |
33 | ### initGitRepo
34 |
35 | 初始化当前项目为 Git 仓库。其类型定义为:
36 |
37 | ```ts
38 | initGitRepo(cwd?: string, force?: boolean): Promise;
39 | ```
40 |
41 | - `cwd`:项目目录,默认为 `generator.outputPath`。
42 | - `force`:如果当前目录已经为一个 Git 仓库,是否强制初始化。
43 |
44 | ### addAndCommit
45 |
46 | 提交当前变更。其类型定义为:
47 |
48 | ```ts
49 | addAndCommit(commitMessage: string, cwd?: string): Promise;
50 | ```
51 |
52 | - `commitMessage`:commit 信息。
53 | - `cwd`:项目目录,默认为 `generator.outputPath`。
54 |
--------------------------------------------------------------------------------
/document/zh/api/handlebars.md:
--------------------------------------------------------------------------------
1 | # Handlebars API
2 |
3 | [English](../../en/api/handlebars.md) | 简体中文
4 |
5 | Handlebars API 是由 `@modern-js/codesmith-api-handlebars` 包提供,该包提供了使用 [Handlebars](https://handlebarsjs.com/) 渲染单个文件及文件夹方法。
6 |
7 | ## 使用姿势
8 |
9 | ```ts
10 | import { HandlebarsAPI } from '@modern-js/codesmith-api-handlebars';
11 |
12 | export default async (context: GeneratorContext, generator: GeneratorCore) => {
13 | const handlebarsAPI = new HandlebarsAPI(generator);
14 | await handlebarsAPI.renderTemplate(
15 | context.current!.material.get('templates/a.js.handlebars'),
16 | 'b.js',
17 | { name: 'test handebars' },
18 | );
19 | };
20 | ```
21 |
22 | - 创建 HandlebarsAPI 实例,参数为 generator。
23 | - 调用实例上提供的 API 方法。
24 |
25 | ## API
26 |
27 | ### registerHelp
28 |
29 | 注册 Handlebars 助手代码。其类型定义为:
30 |
31 | ```ts
32 | registerHelp: (
33 | helpers: Record,
34 | ) => Promise;
35 | ```
36 |
37 | - `helpers`:块助手代码对象,块助手代码的使用可参考[这里](https://handlebarsjs.com/zh/guide/#%E5%9D%97%E5%8A%A9%E6%89%8B%E4%BB%A3%E7%A0%81)。
38 |
39 | ### registerPartials
40 |
41 | 注册 Handlebars 代码片段。其类型定义为:
42 |
43 | ```ts
44 | registerPartials: (
45 | partials: Record,
46 | ) => Promise;
47 | ```
48 |
49 | - `partials`:代码片段对象,代码片段的使用可参考[这里](https://handlebarsjs.com/zh/guide/#%E4%BB%A3%E7%A0%81%E7%89%87%E6%AE%B5)。
50 |
51 | ### renderTemplate
52 |
53 | 渲染单个 Handlebars 模板文件。其类型定义为:
54 |
55 | ```ts
56 | renderTemplate: (
57 | templateResource: FsResource,
58 | target: string,
59 | parameters?: Record,
60 | ) => Promise;
61 | ```
62 |
63 | - `templateResource`:模板文件,通过 `context.current!.material.get()` 获取。
64 | - `target`: 目标文件路径。
65 | - `parameters`:模板变量值,当模板中存在 Handlebars 变量时,定义对应变量值。
66 |
67 | ### renderTemplateDir
68 |
69 | 批量渲染 Handlebars 模板文件夹。其类型定义为:
70 |
71 | ```ts
72 | type TargetFunction = (globMatch: string) => string;
73 | type RenderTemplateDirOptions = {
74 | nodir?: boolean;
75 | dot?: boolean;
76 | ignore?: string | readonly string[];
77 | parameters?: Record;
78 | };
79 | renderTemplateDir: (
80 | material: FsMaterial,
81 | findGlob: string,
82 | target: TargetFunction,
83 | options?: RenderTemplateDirOptions,
84 | ) => Promise;
85 | ```
86 |
87 | - `material`:当前微生成器文件资源,其值为 `context.current!.material`。
88 | - `findGlob`:模板文件匹配规则,支持 [glob](https://www.npmjs.com/package/glob) 格式,例如:`templates/**/*` 为 templates 目录所有文件。
89 | - `target`:目标文件名称,对满足条件的文件进行重命名,函数参数为文件名称。
90 | - `options.parameters`:模板变量值,当模板中存在 Handebars 变量时,定义对应变量值。
91 | - `options.nodir`/`options.dot`/`options.ignore`:glob 匹配参数。
92 |
93 | 示例:
94 |
95 | ```ts
96 | const handlebarsAPI = new HandlebarsAPI(generator);
97 | await handlebarsAPI.renderTemplateDir(
98 | context.current!.material,
99 | 'templates/**/*',
100 | (resourceKey: string) =>
101 | resourceKey.replace('templates/', '').replace('.handlebars', ''),
102 | { parameters: { name: 'name' } },
103 | );
104 | ```
105 |
--------------------------------------------------------------------------------
/document/zh/api/index.md:
--------------------------------------------------------------------------------
1 | # API
2 |
3 | [English](../../en/api/index.md) | 简体中文
4 |
5 | CodeSmith API 是由不同的 NPM 包提供的,可根据需求安装不同的依赖去使用对应的 API。
6 |
7 | - [App API](./app.md)
8 |
9 | - [Handlebars API](./handlebars.md)
10 |
11 | - [EJS API](./ejs.md)
12 |
13 | - [JSON API](./json.md)
14 |
15 | - [FS API](./fs.md)
16 |
17 | - [Git API](./git.md)
18 |
19 | - [NPM API](./npm.md)
20 |
--------------------------------------------------------------------------------
/document/zh/api/input.md:
--------------------------------------------------------------------------------
1 | # Input
2 |
3 | [English](../../en/api/input.md) | 简体中文
4 |
5 | 每个定制化模板都提供了 Input 的方式完成与用户的问题交互,使用 JSON Schema 的方式进行定义:
6 |
7 | 例如:
8 |
9 | ```js
10 | const schema = {
11 | type: 'object',
12 | properties: {
13 | language: {
14 | type: 'string',
15 | title: '开发语言',
16 | enum: [
17 | { label: 'TS', value: 'ts' },
18 | { label: 'ES6+', value: 'js' },
19 | ],
20 | },
21 | },
22 | };
23 | ```
24 |
25 | JSON Schema 的格式参考了开源的 [Formily](https://formilyjs.org/) Schema 的格式,下面将对支持的字段进行介绍:
26 |
27 | ## type
28 |
29 | 定义当前 Schema 类型,当前支持的类型为 `string`、`number` 和 `object`。字符串输入和下拉选项都需要使用 `string` 类型。 `object` 类型用于实现 Schema 之间嵌套,需要配和 `properties` 属性使用。
30 |
31 | ## title
32 |
33 | 定义当前 Schema 展示名称。
34 |
35 | ## default
36 |
37 | 定义当前 Schema 的默认值。
38 |
39 | ## enum
40 |
41 | 当前 Schema 为下列选项时,定义选项内容。
42 |
43 | 子项支持 `string` 或者 `{ label: string; value: string}` 类型,当下拉选项中值和展示值相同时,可直接使用 `string` 定义。
44 |
45 | 当需要表示多选选项时,设置 `default` 字段为 `[]` 即可。
46 |
47 | ## x-validator
48 |
49 | 当前 Schema 的校验规则。当 Schema 为输入类型时,在输入完成后会自动完成校验。
50 |
51 | 这里校验规则支持[ Formily 提供的校验规则](https://formilyjs.org/zh-CN/guide/advanced/validate),例如最大值为 5:
52 |
53 | ```js
54 | const schema = {
55 | type: 'object',
56 | properties: {
57 | max_5: {
58 | type: 'number',
59 | title: '最大值(>5报错)',
60 | 'x-validator': {
61 | maximum: 5,
62 | },
63 | },
64 | },
65 | };
66 | ```
67 |
68 | 也支持直接使用验证函数:
69 |
70 | ```js
71 | const schema = {
72 | type: 'object',
73 | properties: {
74 | path: {
75 | type: 'string',
76 | title: '只能包含数字和字母',
77 | 'x-validator': value => {
78 | if (!/^[0-9a-zA-Z]*$/g.test(value)) {
79 | return '格式不正确';
80 | }
81 | return '';
82 | },
83 | },
84 | },
85 | };
86 | ```
87 |
88 | ## x-reactions
89 |
90 | 使用 Schema 之间的联动,这里和[ Formily 联动规则](https://formilyjs.org/zh-CN/guide/advanced/linkages)完全相同。
91 |
92 | 例如:
93 |
94 | ```js
95 | const schema = {
96 | type: 'object',
97 | properties: {
98 | name: {
99 | type: 'string',
100 | title: '名称',
101 | },
102 | path: {
103 | type: 'string',
104 | title: '路径',
105 | 'x-reactions': [
106 | {
107 | dependencies: ['name'],
108 | fulfill: {
109 | state: {
110 | value: '{{$deps[0]}}',
111 | },
112 | },
113 | },
114 | ],
115 | },
116 | },
117 | };
118 | ```
119 |
120 | ## properties
121 |
122 | 组织当前 Schema 的结构,定义子表单。`properties` 为对象,`key` 为 Schema 关键字,`value` 为上述描述的 Schema 对象。
123 |
--------------------------------------------------------------------------------
/document/zh/api/json.md:
--------------------------------------------------------------------------------
1 | # JSON API
2 |
3 | [English](../../en/api/json.md) | 简体中文
4 |
5 | JSON API 是由 `@modern-js/codesmith-api-json` 包提供,该包提供了获取 JSON 文件内容,更新 JSON 文件等方法。
6 |
7 | ## 使用姿势
8 |
9 | ```ts
10 | import { JsonAPI } from '@modern-js/codesmith-api-json';
11 |
12 | export default async (context: GeneratorContext, generator: GeneratorCore) => {
13 | const jsonAPI = new JsonAPI(generator);
14 | await jsonAPI.update(context.materials.default.get('package.json'), {
15 | query: {},
16 | update: {
17 | $set: {
18 | 'dependencies.@modern-js/plugin-bff': `^2.0.0`,
19 | },
20 | },
21 | });
22 | };
23 | ```
24 |
25 | - 创建 JsonAPI 实例,参数为 generator。
26 | - 调用实例上提供的 API 方法。
27 |
28 | ## API
29 |
30 | ### get
31 |
32 | 获取 JSON 文件内容。其类型定义为:
33 |
34 | ```ts
35 | get: (resource: FsResource) => Promise>;
36 | ```
37 |
38 | - `resource`: `context.materials.default.get()` 获取。
39 |
40 | ### extend
41 |
42 | 合并对象至 JSON 文件。其类型定义为:
43 |
44 | ```ts
45 | extend(resource: FsResource, obj: Record): Promise;
46 | ```
47 |
48 | - `resource`: `context.materials.default.get()` 获取。
49 | - `obj`:合并对象
50 |
51 | ### update
52 |
53 | 更新对象字段至 JSON 文件。其类型定义为:
54 |
55 | ```ts
56 | update(resource: FsResource, operation: {
57 | query: Record;
58 | update: Record;
59 | }): Promise;
60 | ```
61 |
62 | - `resource`: `context.materials.default.get()` 获取。
63 | - `operation`:更新操作,详细使用姿势可查看 [declaration-update](https://www.npmjs.com/package/declaration-update)。
64 |
--------------------------------------------------------------------------------
/document/zh/api/npm.md:
--------------------------------------------------------------------------------
1 | # NPM API
2 |
3 | [English](../../en/api/npm.md) | 简体中文
4 |
5 | NPM API 是由 `@modern-js/codesmith-api-npm` 包提供,该包提供了不同的包管理工具安装依赖的方法。
6 |
7 | ## 使用姿势
8 |
9 | ```ts
10 | import { NpmAPI } from '@modern-js/codesmith-api-npm';
11 |
12 | export default async (context: GeneratorContext, generator: GeneratorCore) => {
13 | const npmApi = new NpmAPI(generator);
14 | await npmApi.pnpmInstall({});
15 | };
16 | ```
17 |
18 | - 创建 NpmAPI 实例,参数和微生成器参数一致。
19 | - 调用实例上提供的 API 方法。
20 |
21 | ## API
22 |
23 | ### npmInstall
24 |
25 | 使用 npm 安装依赖。其类型定义为:
26 |
27 | ```ts
28 | npmInstall: ({
29 | cwd,
30 | registryUrl,
31 | ignoreScripts,
32 | }: {
33 | cwd?: string;
34 | registryUrl?: string;
35 | ignoreScripts?: boolean;
36 | useNvm?: boolean;
37 | }) => Promise>;
38 | ```
39 |
40 | - `cwd`: install 命令的执行目录,默认为 `generator.outputPath`。
41 | - `registryUrl`:安装依赖的 registry 参数。
42 | - `ignoreScripts`:安装依赖时是否需要 `--ignore-scripts` 参数。
43 | - `useNvm`:是否使用 nvm 切换 node 版本。
44 |
45 | ### yarnInstall
46 |
47 | 使用 yarn 安装依赖。其类型定义为:
48 |
49 | ```ts
50 | yarnInstall: ({
51 | cwd,
52 | registryUrl,
53 | ignoreScripts,
54 | }: {
55 | cwd?: string;
56 | registryUrl?: string;
57 | ignoreScripts?: boolean;
58 | useNvm?: boolean;
59 | }) => Promise>;
60 | ```
61 |
62 | 参数和 `npmInstall` 参数一致。
63 |
64 | ### pnpmInstall
65 |
66 | 使用 pnpm 安装依赖。其类型定义为:
67 |
68 | ```ts
69 | pnpmInstall: ({
70 | cwd,
71 | registryUrl,
72 | ignoreScripts,
73 | }: {
74 | cwd?: string;
75 | registryUrl?: string;
76 | ignoreScripts?: boolean;
77 | useNvm?: boolean;
78 | }) => Promise>;
79 | ```
80 |
81 | 参数和 `npmInstall` 参数一致。
82 |
--------------------------------------------------------------------------------
/document/zh/start.md:
--------------------------------------------------------------------------------
1 | # 快速上手
2 |
3 | [English](../en/start.md) | 简体中文
4 |
5 | ## 创建项目
6 |
7 | ```bash
8 | mkdir generator-demo && cd generator demo
9 | npx @modern-js/codesmith-cli@latest @modern-js/generator-generator
10 | ? 请填写项目名称 generator-demo
11 | ? 请选择包管理工具 pnpm
12 | ? 请选择开发语言 TS
13 | ```
14 |
15 | ## 目录结构
16 |
17 | 创建完成后的项目目录结构
18 |
19 | ```bash
20 | .
21 | ├── .changeset
22 | │ └── config.json
23 | ├── .eslintrc.js
24 | ├── .gitignore
25 | ├── .husky
26 | │ └── pre-commit
27 | ├── .npmrc
28 | ├── .nvmrc
29 | ├── .prettierrc
30 | ├── .vscode
31 | │ ├── extensions.json
32 | │ └── settings.json
33 | ├── README.md
34 | ├── modern.config.ts
35 | ├── package.json
36 | ├── src
37 | │ ├── .eslintrc.js
38 | │ ├── index.ts
39 | │ └── modern-app-env.d.ts
40 | ├── templates
41 | └── tsconfig.json
42 | ```
43 |
44 | 项目是基于 [Modern.js 模块项目](https://modernjs.dev/module-tools) 创建的,核心是下面几个文件:
45 |
46 | ```bash
47 | .
48 | ├── src
49 | │ └── index.ts
50 | ├── templates
51 | │ └── .gitkeep
52 | ```
53 |
54 | ### src/index.ts
55 |
56 | 该文件用于完成微生成器的内容开发。
57 |
58 | ```ts
59 | import { GeneratorContext, GeneratorCore } from '@modern-js/codesmith';
60 | import { AppAPI } from '@modern-js/codesmith-api-app';
61 |
62 | const handleTemplateFile = async (appApi: AppAPI) => {
63 | await appApi.forgeTemplate('templates/**/*');
64 | };
65 |
66 | export default async (context: GeneratorContext, generator: GeneratorCore) => {
67 | const appApi = new AppAPI(context, generator);
68 |
69 | const { locale } = context.config;
70 | appApi.i18n.changeLanguage({ locale });
71 |
72 | if (!(await appApi.checkEnvironment())) {
73 | // eslint-disable-next-line no-process-exit
74 | process.exit(1);
75 | }
76 |
77 | generator.logger.debug(`start run @modern-js/generator-demo`);
78 | generator.logger.debug(`context=${JSON.stringify(context)}`);
79 | generator.logger.debug(`context.data=${JSON.stringify(context.data)}`);
80 |
81 | await handleTemplateFile(appApi);
82 |
83 | await appApi.runInstall();
84 |
85 | appApi.showSuccessInfo();
86 |
87 | generator.logger.debug(`forge @modern-js/generator-demo succeed `);
88 | };
89 | ```
90 |
91 | 该文件默认导出一个函数,函数参数为 `context` 和 `generator`。`context` 上提供了微生成器运行的一些上下文信息,`generator` 上提供了一些生成器运行的工具和方法。
92 |
93 | ### templates
94 |
95 | `templates` 目录存在当前微生成器的模板文件,支持 Handlebars 和 EJS 格式,微生成器提供了对应操作不同类型文件的 API。
96 |
97 | 如果模板文件为 `js`、`ts` 或者 `json` 文件,推荐直接使用 `.handlebars` 或者 `.ejs` 后缀,可避免项目 eslint 报错和在 Monorepo 中项目识别问题。
98 |
99 | 模板中 `.gitignore` 文件和 `.npmrc` 文件在发布 npm 包时会自动删除,需要使用 `.handlebars` 或者 `.ejs` 后缀将其保留。
100 |
101 | ## 使用
102 |
103 | ### 命令行运行
104 |
105 | CodeSmith 提供了 CLI 工具用于直接运行微生成器,支持两种格式:
106 |
107 | - 绝对路径
108 |
109 | 适用于本地开发调试,开发完成后,在微生成器执行 npm run build 构建项目,然后使用下面命令即可进行测试。
110 |
111 | ```bash
112 | npx @modern-js/codesmith-cli@latest
113 | ```
114 |
115 | - npm 包
116 |
117 | 适用于微生成器发布于 bnpm 上,共享微生成器场景。
118 |
119 | ```bash
120 | npx @modern-js/codesmith-cli@latest
121 | ```
122 |
123 | ### 使用 JS 执行
124 |
125 | 除了使用 CLI 的方式执行微生成器,CodeSmith 还支持在代码中执行微生成器。
126 |
127 | - 安装 CodeSmith 依赖
128 |
129 | ```bash
130 | pnpm add @modern-js/codesmith
131 | ```
132 |
133 | - 创建 CodeSmith 实例
134 |
135 | ```ts
136 | import { CodeSmith } from '@modern-js/codesmith';
137 |
138 | const smith = new CodeSmith({
139 | debug: false,
140 | });
141 | ```
142 |
143 | > debug 为 true 时将开发 Debug 模式,会打印对应的 debug 日志。
144 |
145 | - 调用 forge 方法运行微生成器
146 |
147 | ```ts
148 | const smith = new CodeSmith({
149 | debug: false,
150 | });
151 |
152 | await smith.forge({
153 | tasks: [
154 | {
155 | generator: ,
156 | config: {},
157 | },
158 | ],
159 | pwd: '.',
160 | });
161 | ```
162 |
--------------------------------------------------------------------------------
/modern.config.js:
--------------------------------------------------------------------------------
1 | import monorepoTools from '@modern-js/monorepo-tools';
2 |
3 | module.exports = {
4 | plugins: [monorepoTools()],
5 | };
6 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "codesmith-monorepo",
4 | "description": "The meta-framework suite designed from scratch for frontend-focused modern web development.",
5 | "homepage": "https://modernjs.dev",
6 | "bugs": "https://github.com/web-infra-dev/codesmith/issues",
7 | "repository": "web-infra-dev/codesmith",
8 | "license": "MIT",
9 | "keywords": [
10 | "react",
11 | "framework",
12 | "modern",
13 | "modern.js"
14 | ],
15 | "scripts": {
16 | "new": "modern new",
17 | "setup": "npm run reset && pnpm install --ignore-scripts",
18 | "reset": "pnpm -r exec rm -rf ./node_modules",
19 | "test": "pnpm run --filter './packages/**' test --detectOpenHandles",
20 | "prepare": "pnpm run --filter './packages/**' prepare",
21 | "lint": "biome check",
22 | "change": "modern change",
23 | "bump": "modern bump",
24 | "pre": "modern pre",
25 | "release": "modern release --ignore-scripts",
26 | "gen-release-note": "modern gen-release-note",
27 | "get-release-version": "cd scripts && pnpm run get-release-version"
28 | },
29 | "engines": {
30 | "node": ">=14.17.6",
31 | "pnpm": ">=8.0.0"
32 | },
33 | "packageManager": "pnpm@9.12.2",
34 | "husky": {
35 | "hooks": {
36 | "pre-commit": "lint-staged",
37 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
38 | }
39 | },
40 | "commitlint": {
41 | "extends": [
42 | "@commitlint/config-conventional"
43 | ]
44 | },
45 | "lint-staged": {
46 | "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}": [
47 | "biome check --files-ignore-unknown=true"
48 | ]
49 | },
50 | "workspaces": {
51 | "packages": [
52 | "apps/*",
53 | "examples/*",
54 | "services/*",
55 | "features/*",
56 | "packages/*",
57 | "packages/api/*",
58 | "packages/easy-form/*"
59 | ]
60 | },
61 | "devDependencies": {
62 | "@biomejs/biome": "1.8.3",
63 | "@modern-js/monorepo-tools": "2.58.0",
64 | "@modern-js/tsconfig": "2.58.0"
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/packages/api/app/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | .pnp
4 | .pnp.js
5 | .env.*.local
6 | .history
7 | .rts*
8 | *.log*
9 | *.pid
10 | *.pid.*
11 | *.report
12 | *.lcov
13 | lib-cov
14 |
15 | node_modules/
16 | .npm
17 | .lock-wscript
18 | .yarn-integrity
19 | .node_repl_history
20 | .nyc_output
21 | *.tsbuildinfo
22 | .eslintcache
23 | .sonarlint
24 |
25 | coverage/
26 | release/
27 | output/
28 | output_resource/
29 |
30 | .vscode/**/*
31 | !.vscode/settings.json
32 | !.vscode/extensions.json
33 | .idea/
34 |
35 | **/*/api/typings/auto-generated
36 | **/*/adapters/**/index.ts
37 | **/*/adapters/**/index.js
38 |
39 | src/
40 |
41 | modern.config.*
42 | tsconfig.json
43 | CHANGELOG.md
44 |
--------------------------------------------------------------------------------
/packages/api/app/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Modern.js
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/api/app/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Modern.js
6 |
7 |
8 | A Progressive React Framework for modern web development.
9 |
10 |
11 | ## Getting Started
12 |
13 | Please follow [Quick Start](https://modernjs.dev/en/guides/get-started/quick-start) to get started with Modern.js.
14 |
15 | ## Documentation
16 |
17 | - [English Documentation](https://modernjs.dev/en/)
18 | - [中文文档](https://modernjs.dev)
19 |
20 | ## Contributing
21 |
22 | Please read the [Contributing Guide](https://github.com/web-infra-dev/modern.js/blob/main/CONTRIBUTING.md).
23 |
24 | ## License
25 |
26 | Modern.js is [MIT licensed](https://github.com/web-infra-dev/modern.js/blob/main/LICENSE).
27 |
--------------------------------------------------------------------------------
/packages/api/app/modern.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig, moduleTools } from '@modern-js/module-tools';
2 |
3 | import { testingPlugin } from '@modern-js/plugin-testing';
4 |
5 | export default defineConfig({
6 | buildPreset: 'modern-js-universal',
7 | plugins: [moduleTools(), testingPlugin()],
8 | });
9 |
--------------------------------------------------------------------------------
/packages/api/app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@modern-js/codesmith-api-app",
3 | "description": "codesmith app api",
4 | "homepage": "https://modernjs.dev",
5 | "bugs": "https://github.com/web-infra-dev/codesmith/issues",
6 | "repository": "web-infra-dev/codesmith",
7 | "license": "MIT",
8 | "keywords": [
9 | "react",
10 | "framework",
11 | "modern",
12 | "modern.js"
13 | ],
14 | "version": "2.6.8",
15 | "jsnext:source": "./src/index.ts",
16 | "types": "./dist/types/index.d.ts",
17 | "main": "./dist/cjs/index.js",
18 | "module": "./dist/esm-node/index.js",
19 | "publishConfig": {
20 | "registry": "https://registry.npmjs.org/",
21 | "access": "public"
22 | },
23 | "scripts": {
24 | "prepare": "pnpm build",
25 | "prepublishOnly": "pnpm build --platform",
26 | "new": "modern new",
27 | "build": "modern build",
28 | "test": "modern test --passWithNoTests"
29 | },
30 | "dependencies": {
31 | "@swc/helpers": "0.5.1",
32 | "@modern-js/codesmith-api-ejs": "workspace:*",
33 | "@modern-js/codesmith-api-fs": "workspace:*",
34 | "@modern-js/codesmith-api-git": "workspace:*",
35 | "@modern-js/codesmith-api-handlebars": "workspace:*",
36 | "@modern-js/codesmith-api-npm": "workspace:*",
37 | "@modern-js/codesmith-formily": "workspace:*",
38 | "@modern-js/codesmith-utils": "workspace:*",
39 | "@modern-js/plugin-i18n": "2.60.3",
40 | "comment-json": "^4.2.3",
41 | "extra": "^0.2.1",
42 | "inquirer": "8.1.3"
43 | },
44 | "peerDependencies": {
45 | "@modern-js/codesmith": "workspace:^2.6.8"
46 | },
47 | "devDependencies": {
48 | "@modern-js/codesmith": "workspace:*",
49 | "@modern-js/module-tools": "2.60.3",
50 | "@modern-js/plugin-testing": "2.60.3",
51 | "@types/inquirer": "^7.3.3",
52 | "@types/jest": "^26.0.24",
53 | "@types/node": "^14.18.42",
54 | "typescript": "^4.9.5"
55 | },
56 | "sideEffects": false
57 | }
58 |
--------------------------------------------------------------------------------
/packages/api/app/src/locale/en.ts:
--------------------------------------------------------------------------------
1 | export const EN_LOCALE = {
2 | environment: {
3 | node_version:
4 | 'The version of Node.js is too low. Please upgrade to the LTS version: https://nodejs.org/',
5 | nvm_install: 'please install nvm first',
6 | yarn_pnpm_npm: 'please install yarn or pnpm or npm first',
7 | },
8 | install: {
9 | failed:
10 | 'dependencies install failed, please execute `{command}` to install the dependencies ',
11 | failed_no_command: 'dependencies install failed',
12 | success: 'dependencies are automatically installed',
13 | },
14 | git: {
15 | failed:
16 | 'git repository create failed, please check installing git and setting git username and email',
17 | success: 'git repository has been automatically created',
18 | },
19 | templated: {
20 | failed: 'forging template failed',
21 | },
22 | generator: {
23 | failed: 'load sub generator failed',
24 | },
25 | success: {
26 | info: 'Success!',
27 | },
28 | };
29 |
--------------------------------------------------------------------------------
/packages/api/app/src/locale/index.ts:
--------------------------------------------------------------------------------
1 | import { I18n } from '@modern-js/plugin-i18n';
2 | import { EN_LOCALE } from './en';
3 | import { ZH_LOCALE } from './zh';
4 |
5 | const i18n = new I18n();
6 |
7 | const localeKeys = i18n.init('zh', { zh: ZH_LOCALE, en: EN_LOCALE });
8 |
9 | export { i18n, localeKeys, I18n };
10 |
--------------------------------------------------------------------------------
/packages/api/app/src/locale/zh.ts:
--------------------------------------------------------------------------------
1 | export const ZH_LOCALE = {
2 | environment: {
3 | node_version: 'Node.js 版本太低,请升级至 LTS 版本: https://nodejs.org/',
4 | nvm_install: '检测到环境中未安装 nvm,请先安装 nvm',
5 | yarn_pnpm_npm: '检测到环境中未安装包管理工具,请先安装 yarn 或 pnpm 或 npm',
6 | },
7 | install: {
8 | failed: '依赖自动安装失败,请手动执行 `{command}` 命令进行安装',
9 | failed_no_command: '依赖自动安装失败,请手动执行 install 命令进行安装',
10 | success: '依赖自动安装成功',
11 | },
12 | git: {
13 | failed:
14 | 'git 仓库初始化失败, 请确认是否安装 git 且初始化 git username 和 email',
15 | success: 'git 仓库初始化成功',
16 | },
17 | templated: {
18 | failed: '模板生成失败',
19 | },
20 | generator: {
21 | failed: '加载子生成器失败',
22 | },
23 | success: {
24 | info: '成功!',
25 | },
26 | };
27 |
--------------------------------------------------------------------------------
/packages/api/app/src/utils/checkUseNvm.ts:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import { type ILogger, fsExists } from '@modern-js/codesmith';
3 | import { execaWithStreamLog } from '@modern-js/codesmith-api-npm';
4 | import { execa } from '@modern-js/codesmith-utils/execa';
5 | import { fs } from '@modern-js/codesmith-utils/fs-extra';
6 | import { canUseFnm, canUseNvm } from '@modern-js/codesmith-utils/npm';
7 | import { semver } from '@modern-js/codesmith-utils/semver';
8 |
9 | const NODE_MAJOR_VERSION_MAP: Record = {
10 | 'lts/*': 18,
11 | 'lts/argon': 4,
12 | 'lts/boron': 6,
13 | 'lts/carbon': 8,
14 | 'lts/dubnium': 10,
15 | 'lts/erbium': 12,
16 | 'lts/fermium': 14,
17 | 'lts/gallium': 16,
18 | 'lts/hydrogen': 18,
19 | 'lts/jod': 22,
20 | };
21 |
22 | export async function getNoteVersion() {
23 | const result = await execa('node', ['--version']);
24 | return result.stdout.slice(1);
25 | }
26 | export async function checkUseNvm(cwd: string, logger: ILogger) {
27 | // check windows
28 | if (process.platform.startsWith('win')) {
29 | return false;
30 | }
31 | // exist .nvmrc file
32 | if (!(await fsExists(path.join(cwd, '.nvmrc')))) {
33 | return false;
34 | }
35 | // check current node version and expect node version
36 | const nvmrcContent = (
37 | await fs.readFile(path.join(cwd, '.nvmrc'), 'utf-8')
38 | ).replace('\n', '');
39 | const expectNodeVersion =
40 | NODE_MAJOR_VERSION_MAP[nvmrcContent] || nvmrcContent;
41 | const currentNodeVersion = await getNoteVersion();
42 | if (expectNodeVersion === semver.major(currentNodeVersion)) {
43 | return false;
44 | }
45 | // check nvm or fnm exist
46 | if (!((await canUseNvm()) || (await canUseFnm()))) {
47 | logger.warn(
48 | `🟡 [Check nvm Error]: Current node version is not expect, you should install ${expectNodeVersion}`,
49 | );
50 | return false;
51 | }
52 | // run nvm install
53 | try {
54 | await execaWithStreamLog('source ~/.nvm/nvm.sh && nvm install', [], {
55 | shell: true,
56 | cwd,
57 | });
58 | return true;
59 | } catch (e) {
60 | return false;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/packages/api/app/src/utils/transform.ts:
--------------------------------------------------------------------------------
1 | import { isString } from '@modern-js/codesmith-utils/lodash';
2 | import type { Question } from 'inquirer';
3 |
4 | export function transformInquirerSchema(
5 | questions: Question[],
6 | configValue: Record = {},
7 | validateMap: Record<
8 | string,
9 | (
10 | input: unknown,
11 | data?: Record,
12 | ) => { success: boolean; error?: string }
13 | > = {},
14 | initValue: Record = {},
15 | ) {
16 | for (const question of questions) {
17 | question.default = initValue[question.name!] || question.default;
18 | const originValidate = question.validate;
19 | question.validate = async (input, answers) => {
20 | if (originValidate) {
21 | const result = await originValidate(input, answers);
22 | if (isString(result)) {
23 | return result;
24 | }
25 | }
26 | if (validateMap[question.name!]) {
27 | const result = validateMap[question.name!](input, configValue);
28 | if (result.error) {
29 | return result.error;
30 | }
31 | }
32 | return true;
33 | };
34 | if (configValue[question.name!]) {
35 | question.when = false;
36 | }
37 | }
38 | return questions;
39 | }
40 |
--------------------------------------------------------------------------------
/packages/api/app/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@modern-js/tsconfig/base",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "jsx": "preserve",
6 | "baseUrl": "./",
7 | "isolatedModules": true,
8 | "paths": {
9 | "@/*": ["./src/*"]
10 | }
11 | },
12 | "include": ["src"]
13 | }
14 |
--------------------------------------------------------------------------------
/packages/api/ejs/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | .pnp
4 | .pnp.js
5 | .env.*.local
6 | .history
7 | .rts*
8 | *.log*
9 | *.pid
10 | *.pid.*
11 | *.report
12 | *.lcov
13 | lib-cov
14 |
15 | node_modules/
16 | .npm
17 | .lock-wscript
18 | .yarn-integrity
19 | .node_repl_history
20 | .nyc_output
21 | *.tsbuildinfo
22 | .eslintcache
23 | .sonarlint
24 |
25 | coverage/
26 | release/
27 | output/
28 | output_resource/
29 |
30 | .vscode/**/*
31 | !.vscode/settings.json
32 | !.vscode/extensions.json
33 | .idea/
34 |
35 | **/*/api/typings/auto-generated
36 | **/*/adapters/**/index.ts
37 | **/*/adapters/**/index.js
38 |
39 | src/
40 |
41 | modern.config.*
42 | tsconfig.json
43 | CHANGELOG.md
44 |
--------------------------------------------------------------------------------
/packages/api/ejs/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Modern.js
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/api/ejs/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Modern.js
6 |
7 |
8 | A Progressive React Framework for modern web development.
9 |
10 |
11 | ## Getting Started
12 |
13 | Please follow [Quick Start](https://modernjs.dev/en/guides/get-started/quick-start) to get started with Modern.js.
14 |
15 | ## Documentation
16 |
17 | - [English Documentation](https://modernjs.dev/en/)
18 | - [中文文档](https://modernjs.dev)
19 |
20 | ## Contributing
21 |
22 | Please read the [Contributing Guide](https://github.com/web-infra-dev/modern.js/blob/main/CONTRIBUTING.md).
23 |
24 | ## License
25 |
26 | Modern.js is [MIT licensed](https://github.com/web-infra-dev/modern.js/blob/main/LICENSE).
27 |
--------------------------------------------------------------------------------
/packages/api/ejs/modern.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig, moduleTools } from '@modern-js/module-tools';
2 |
3 | import { testingPlugin } from '@modern-js/plugin-testing';
4 |
5 | export default defineConfig({
6 | buildPreset: 'modern-js-universal',
7 | plugins: [moduleTools(), testingPlugin()],
8 | });
9 |
--------------------------------------------------------------------------------
/packages/api/ejs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@modern-js/codesmith-api-ejs",
3 | "description": "codesmith ejs api",
4 | "homepage": "https://modernjs.dev",
5 | "bugs": "https://github.com/web-infra-dev/codesmith/issues",
6 | "repository": "web-infra-dev/codesmith",
7 | "license": "MIT",
8 | "keywords": [
9 | "react",
10 | "framework",
11 | "modern",
12 | "modern.js"
13 | ],
14 | "version": "2.6.8",
15 | "jsnext:source": "./src/index.ts",
16 | "types": "./dist/types/index.d.ts",
17 | "main": "./dist/cjs/index.js",
18 | "module": "./dist/esm-node/index.js",
19 | "publishConfig": {
20 | "registry": "https://registry.npmjs.org/",
21 | "access": "public"
22 | },
23 | "scripts": {
24 | "prepare": "pnpm build",
25 | "prepublishOnly": "pnpm build -- --platform",
26 | "new": "modern new",
27 | "build": "modern build",
28 | "test": "modern test"
29 | },
30 | "dependencies": {
31 | "@swc/helpers": "0.5.1",
32 | "ejs": "^3.1.9"
33 | },
34 | "peerDependencies": {
35 | "@modern-js/codesmith": "workspace:^2.6.8"
36 | },
37 | "devDependencies": {
38 | "@modern-js/codesmith": "workspace:*",
39 | "@modern-js/module-tools": "2.60.3",
40 | "@modern-js/plugin-testing": "2.60.3",
41 | "@types/ejs": "^3.1.2",
42 | "@types/jest": "^26.0.24",
43 | "@types/node": "^14.18.42",
44 | "typescript": "^4.9.5"
45 | },
46 | "sideEffects": false
47 | }
48 |
--------------------------------------------------------------------------------
/packages/api/ejs/src/index.ts:
--------------------------------------------------------------------------------
1 | import {
2 | FS_RESOURCE,
3 | type FsMaterial,
4 | type FsResource,
5 | type GeneratorCore,
6 | } from '@modern-js/codesmith';
7 | import { renderString } from './utils';
8 |
9 | type TargetFunction = (globMatch: string) => string;
10 |
11 | type RenderTemplateDirOptions = {
12 | nodir?: boolean;
13 | dot?: boolean;
14 | ignore?: string | readonly string[];
15 | parameters?: Record;
16 | };
17 |
18 | export { renderString };
19 |
20 | export class EjsAPI {
21 | protected readonly generatorCore: GeneratorCore;
22 |
23 | constructor(generatorCore: GeneratorCore) {
24 | this.generatorCore = generatorCore;
25 | }
26 |
27 | public async renderTemplate(
28 | templateResource: FsResource,
29 | target: string,
30 | parameters: Record = {},
31 | ) {
32 | if (templateResource._type !== FS_RESOURCE) {
33 | throw new Error('resource not match');
34 | }
35 | const resourceValue = await templateResource.value();
36 | if (typeof resourceValue.content !== 'string') {
37 | throw new Error(
38 | `resource.value is not string, resourceValue=${
39 | resourceValue as unknown as string
40 | }`,
41 | );
42 | }
43 | await this.generatorCore.output.fs(
44 | target,
45 | renderString(resourceValue.content, parameters),
46 | { encoding: 'utf-8' },
47 | );
48 | }
49 |
50 | public async renderTemplateDir(
51 | material: FsMaterial,
52 | findGlob: string,
53 | target: TargetFunction,
54 | options?: RenderTemplateDirOptions,
55 | ) {
56 | const resourceMap = await material.find(findGlob, {
57 | nodir: true,
58 | ...options,
59 | });
60 | await Promise.all(
61 | // resourceKey is relate path. example: in `garr-master/package.json`, package.json is resourceKey
62 | Object.keys(resourceMap).map(async resourceKey => {
63 | this.generatorCore.logger.debug(
64 | `💡 [EJS Render Template Dir]: resourceKey=${resourceKey}`,
65 | );
66 | await this.renderTemplate(
67 | material.get(resourceKey),
68 | target(resourceKey),
69 | options?.parameters,
70 | );
71 | }),
72 | );
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/packages/api/ejs/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | export { renderString } from './renderString';
2 |
--------------------------------------------------------------------------------
/packages/api/ejs/src/utils/renderString.ts:
--------------------------------------------------------------------------------
1 | import ejs from 'ejs';
2 |
3 | export function renderString(
4 | template: string,
5 | fullData: Record,
6 | ): string {
7 | return ejs.render(template, fullData) || '';
8 | }
9 |
--------------------------------------------------------------------------------
/packages/api/ejs/tests/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@modern-js/tsconfig/base",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "jsx": "preserve",
6 | "baseUrl": "./",
7 | "isolatedModules": true,
8 | "paths": {
9 | "@/*": ["../src/*"]
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/packages/api/ejs/tests/utils.test.ts:
--------------------------------------------------------------------------------
1 | import { renderString } from '@/utils';
2 |
3 | describe('Utils cases', () => {
4 | test('renderString test', () => {
5 | const result = renderString('renderString <%= name %>', { name: 'test' });
6 | expect(result).toBe('renderString test');
7 | });
8 | test('renderString array', () => {
9 | const people = ['geddy', 'neil', 'alex'];
10 | const result = renderString('<%= people.join(", "); %>', { people });
11 | expect(result).toBe('geddy, neil, alex');
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/packages/api/ejs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@modern-js/tsconfig/base",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "jsx": "preserve",
6 | "baseUrl": "./",
7 | "isolatedModules": true,
8 | "paths": {
9 | "@/*": ["./src/*"]
10 | }
11 | },
12 | "include": ["src"]
13 | }
14 |
--------------------------------------------------------------------------------
/packages/api/fs/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | .pnp
4 | .pnp.js
5 | .env.*.local
6 | .history
7 | .rts*
8 | *.log*
9 | *.pid
10 | *.pid.*
11 | *.report
12 | *.lcov
13 | lib-cov
14 |
15 | node_modules/
16 | .npm
17 | .lock-wscript
18 | .yarn-integrity
19 | .node_repl_history
20 | .nyc_output
21 | *.tsbuildinfo
22 | .eslintcache
23 | .sonarlint
24 |
25 | coverage/
26 | release/
27 | output/
28 | output_resource/
29 |
30 | .vscode/**/*
31 | !.vscode/settings.json
32 | !.vscode/extensions.json
33 | .idea/
34 |
35 | **/*/api/typings/auto-generated
36 | **/*/adapters/**/index.ts
37 | **/*/adapters/**/index.js
38 |
39 | src/
40 |
41 | modern.config.*
42 | tsconfig.json
43 | CHANGELOG.md
44 |
--------------------------------------------------------------------------------
/packages/api/fs/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Modern.js
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/api/fs/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Modern.js
6 |
7 |
8 | A Progressive React Framework for modern web development.
9 |
10 |
11 | ## Getting Started
12 |
13 | Please follow [Quick Start](https://modernjs.dev/en/guides/get-started/quick-start) to get started with Modern.js.
14 |
15 | ## Documentation
16 |
17 | - [English Documentation](https://modernjs.dev/en/)
18 | - [中文文档](https://modernjs.dev)
19 |
20 | ## Contributing
21 |
22 | Please read the [Contributing Guide](https://github.com/web-infra-dev/modern.js/blob/main/CONTRIBUTING.md).
23 |
24 | ## License
25 |
26 | Modern.js is [MIT licensed](https://github.com/web-infra-dev/modern.js/blob/main/LICENSE).
27 |
--------------------------------------------------------------------------------
/packages/api/fs/modern.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig, moduleTools } from '@modern-js/module-tools';
2 |
3 | import { testingPlugin } from '@modern-js/plugin-testing';
4 |
5 | export default defineConfig({
6 | buildPreset: 'modern-js-universal',
7 | plugins: [moduleTools(), testingPlugin()],
8 | });
9 |
--------------------------------------------------------------------------------
/packages/api/fs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@modern-js/codesmith-api-fs",
3 | "description": "codesmith fs api",
4 | "homepage": "https://modernjs.dev",
5 | "bugs": "https://github.com/web-infra-dev/codesmith/issues",
6 | "repository": "web-infra-dev/codesmith",
7 | "license": "MIT",
8 | "keywords": [
9 | "react",
10 | "framework",
11 | "modern",
12 | "modern.js"
13 | ],
14 | "version": "2.6.8",
15 | "jsnext:source": "./src/index.ts",
16 | "types": "./dist/types/index.d.ts",
17 | "main": "./dist/cjs/index.js",
18 | "module": "./dist/esm-node/index.js",
19 | "publishConfig": {
20 | "registry": "https://registry.npmjs.org/",
21 | "access": "public"
22 | },
23 | "scripts": {
24 | "prepare": "pnpm build",
25 | "prepublishOnly": "pnpm build -- --platform",
26 | "new": "modern new",
27 | "build": "modern build",
28 | "test": "modern test --passWithNoTests"
29 | },
30 | "dependencies": {
31 | "@swc/helpers": "0.5.1",
32 | "@modern-js/codesmith-utils": "workspace:*"
33 | },
34 | "peerDependencies": {
35 | "@modern-js/codesmith": "workspace:^2.6.8"
36 | },
37 | "devDependencies": {
38 | "@modern-js/codesmith": "workspace:*",
39 | "@modern-js/module-tools": "2.60.3",
40 | "@modern-js/plugin-testing": "2.60.3",
41 | "@types/jest": "^26.0.24",
42 | "@types/node": "^14.18.42",
43 | "typescript": "^4.9.5"
44 | },
45 | "sideEffects": false
46 | }
47 |
--------------------------------------------------------------------------------
/packages/api/fs/src/index.ts:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import {
3 | FS_RESOURCE,
4 | type FsMaterial,
5 | type FsResource,
6 | type GeneratorCore,
7 | } from '@modern-js/codesmith';
8 | import { fs } from '@modern-js/codesmith-utils/fs-extra';
9 |
10 | type RenderDirOptions = {
11 | nodir?: boolean;
12 | dot?: boolean;
13 | ignore?: string | readonly string[];
14 | };
15 |
16 | type TargetFunction = (globMatch: string) => string;
17 |
18 | export class FsAPI {
19 | protected readonly generatorCore: GeneratorCore;
20 |
21 | constructor(generatorCore: GeneratorCore) {
22 | this.generatorCore = generatorCore;
23 | }
24 |
25 | public async renderFile(resource: FsResource, target: string) {
26 | if (resource._type !== FS_RESOURCE) {
27 | throw new Error('resource not match');
28 | }
29 | const filePath = path.resolve(
30 | this.generatorCore.outputPath,
31 | target.toString(),
32 | );
33 | await fs.mkdirp(path.dirname(filePath));
34 | await fs.copyFile(resource.filePath, filePath);
35 | }
36 |
37 | public async renderDir(
38 | material: FsMaterial,
39 | findGlob: string,
40 | target: TargetFunction,
41 | options?: RenderDirOptions,
42 | ) {
43 | const resourceMap = await material.find(findGlob, {
44 | nodir: true,
45 | ...options,
46 | });
47 | await Promise.all(
48 | Object.keys(resourceMap).map(async resourceKey => {
49 | this.generatorCore.logger.debug(
50 | `💡 [FS Render Dir]: resourceKey=${resourceKey}`,
51 | );
52 | await this.renderFile(material.get(resourceKey), target(resourceKey));
53 | }),
54 | );
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/packages/api/fs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@modern-js/tsconfig/base",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "jsx": "preserve",
6 | "baseUrl": "./",
7 | "isolatedModules": true,
8 | "paths": {
9 | "@/*": ["./src/*"]
10 | }
11 | },
12 | "include": ["src"]
13 | }
14 |
--------------------------------------------------------------------------------
/packages/api/git/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | .pnp
4 | .pnp.js
5 | .env.*.local
6 | .history
7 | .rts*
8 | *.log*
9 | *.pid
10 | *.pid.*
11 | *.report
12 | *.lcov
13 | lib-cov
14 |
15 | node_modules/
16 | .npm
17 | .lock-wscript
18 | .yarn-integrity
19 | .node_repl_history
20 | .nyc_output
21 | *.tsbuildinfo
22 | .eslintcache
23 | .sonarlint
24 |
25 | coverage/
26 | release/
27 | output/
28 | output_resource/
29 |
30 | .vscode/**/*
31 | !.vscode/settings.json
32 | !.vscode/extensions.json
33 | .idea/
34 |
35 | **/*/api/typings/auto-generated
36 | **/*/adapters/**/index.ts
37 | **/*/adapters/**/index.js
38 |
39 | src/
40 |
41 | modern.config.*
42 | tsconfig.json
43 | CHANGELOG.md
44 |
--------------------------------------------------------------------------------
/packages/api/git/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Modern.js
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/api/git/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Modern.js
6 |
7 |
8 | A Progressive React Framework for modern web development.
9 |
10 |
11 | ## Getting Started
12 |
13 | Please follow [Quick Start](https://modernjs.dev/en/guides/get-started/quick-start) to get started with Modern.js.
14 |
15 | ## Documentation
16 |
17 | - [English Documentation](https://modernjs.dev/en/)
18 | - [中文文档](https://modernjs.dev)
19 |
20 | ## Contributing
21 |
22 | Please read the [Contributing Guide](https://github.com/web-infra-dev/modern.js/blob/main/CONTRIBUTING.md).
23 |
24 | ## License
25 |
26 | Modern.js is [MIT licensed](https://github.com/web-infra-dev/modern.js/blob/main/LICENSE).
27 |
--------------------------------------------------------------------------------
/packages/api/git/modern.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig, moduleTools } from '@modern-js/module-tools';
2 |
3 | import { testingPlugin } from '@modern-js/plugin-testing';
4 |
5 | export default defineConfig({
6 | buildPreset: 'modern-js-universal',
7 | plugins: [moduleTools(), testingPlugin()],
8 | });
9 |
--------------------------------------------------------------------------------
/packages/api/git/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@modern-js/codesmith-api-git",
3 | "description": "codesmith git api",
4 | "homepage": "https://modernjs.dev",
5 | "bugs": "https://github.com/web-infra-dev/codesmith/issues",
6 | "repository": "web-infra-dev/codesmith",
7 | "license": "MIT",
8 | "keywords": [
9 | "react",
10 | "framework",
11 | "modern",
12 | "modern.js"
13 | ],
14 | "version": "2.6.8",
15 | "jsnext:source": "./src/index.ts",
16 | "types": "./dist/types/index.d.ts",
17 | "main": "./dist/cjs/index.js",
18 | "module": "./dist/esm-node/index.js",
19 | "publishConfig": {
20 | "registry": "https://registry.npmjs.org/",
21 | "access": "public"
22 | },
23 | "scripts": {
24 | "prepare": "pnpm build",
25 | "prepublishOnly": "pnpm build -- --platform",
26 | "new": "modern new",
27 | "build": "modern build",
28 | "test": "modern test"
29 | },
30 | "dependencies": {
31 | "@swc/helpers": "0.5.1",
32 | "@modern-js/codesmith-utils": "workspace:*"
33 | },
34 | "peerDependencies": {
35 | "@modern-js/codesmith": "workspace:^2.6.8"
36 | },
37 | "devDependencies": {
38 | "@modern-js/codesmith": "workspace:*",
39 | "@modern-js/module-tools": "2.60.3",
40 | "@modern-js/plugin-testing": "2.60.3",
41 | "@types/jest": "^26.0.24",
42 | "@types/node": "^14.18.42",
43 | "typescript": "^4.9.5"
44 | },
45 | "sideEffects": false
46 | }
47 |
--------------------------------------------------------------------------------
/packages/api/git/src/index.ts:
--------------------------------------------------------------------------------
1 | import type { GeneratorContext, GeneratorCore } from '@modern-js/codesmith';
2 | import {
3 | canUseGit,
4 | gitAdd,
5 | gitCommit,
6 | initGitRepo,
7 | isInGitRepo,
8 | } from './utils';
9 |
10 | export class GitAPI {
11 | protected readonly generatorCore: GeneratorCore;
12 |
13 | protected readonly generatorContext?: GeneratorContext;
14 |
15 | constructor(
16 | generatorCore: GeneratorCore,
17 | generatorContext?: GeneratorContext,
18 | ) {
19 | this.generatorCore = generatorCore;
20 | this.generatorContext = generatorContext;
21 | }
22 |
23 | public async isInGitRepo(cwd: string = this.generatorCore.outputPath) {
24 | const canUse = await canUseGit();
25 | if (canUse) {
26 | return isInGitRepo(cwd);
27 | }
28 | throw new Error('git is not found');
29 | }
30 |
31 | public async initGitRepo(cwd = this.generatorCore.outputPath, force = false) {
32 | const canUse = await canUseGit();
33 | if (!canUse) {
34 | throw new Error('git is not found');
35 | }
36 | const alreadyInit = await this.isInGitRepo(cwd);
37 | if (alreadyInit && !force) {
38 | this.generatorCore.logger.debug('❗️ [Git Init]: Already init, Skip');
39 | return;
40 | }
41 | try {
42 | const {
43 | config: { defaultBranch = 'master' },
44 | } = this.generatorContext || { config: { defaultBranch: 'master' } };
45 | await initGitRepo(cwd, defaultBranch);
46 | } catch (e) {
47 | this.generatorCore.logger.debug('❗️ [Git Init Error]:', e);
48 | throw e;
49 | }
50 | }
51 |
52 | public async addAndCommit(
53 | commitMessage: string,
54 | cwd = this.generatorCore.outputPath,
55 | ) {
56 | const canUse = await canUseGit();
57 | if (!canUse) {
58 | throw new Error('git is not found');
59 | }
60 | try {
61 | await gitAdd(cwd);
62 | await gitCommit(cwd, commitMessage);
63 | } catch (e) {
64 | this.generatorCore.logger.debug('❗️ [Git Add and Commit Error]:', e);
65 | throw e;
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/packages/api/git/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | import { execa } from '@modern-js/codesmith-utils/execa';
2 |
3 | export async function canUseGit() {
4 | try {
5 | await execa('git', ['--version'], { env: process.env });
6 | return true;
7 | } catch (e) {
8 | return false;
9 | }
10 | }
11 |
12 | export async function isInGitRepo(cwd: string) {
13 | try {
14 | await execa('git', ['rev-parse', '--is-inside-work-tree'], {
15 | env: process.env,
16 | cwd,
17 | });
18 | return true;
19 | } catch (e) {
20 | return false;
21 | }
22 | }
23 |
24 | export async function initGitRepo(cwd: string, defaultBranch: string) {
25 | await execa('git', ['init'], {
26 | env: process.env,
27 | cwd,
28 | });
29 | const { stdout } = await execa('git', ['symbolic-ref', '--short', 'HEAD'], {
30 | env: process.env,
31 | cwd,
32 | });
33 |
34 | if (stdout !== defaultBranch) {
35 | await execa('git', ['checkout', '-b', defaultBranch], {
36 | env: process.env,
37 | cwd,
38 | });
39 | }
40 | }
41 |
42 | export async function gitAdd(cwd: string) {
43 | await execa('git', ['add', '-A'], {
44 | env: process.env,
45 | cwd,
46 | });
47 | }
48 |
49 | export async function gitCommit(cwd: string, commitMessage: string) {
50 | await execa('git', ['commit', '-m', commitMessage, '--no-verify'], {
51 | env: process.env,
52 | cwd,
53 | });
54 | }
55 |
--------------------------------------------------------------------------------
/packages/api/git/tests/index.test.ts:
--------------------------------------------------------------------------------
1 | import os from 'os';
2 | import path from 'path';
3 | import {
4 | canUseGit,
5 | gitAdd,
6 | gitCommit,
7 | initGitRepo,
8 | isInGitRepo,
9 | } from '@/utils';
10 | import { execa } from '@modern-js/codesmith-utils/execa';
11 | import { fs } from '@modern-js/codesmith-utils/fs-extra';
12 |
13 | const cwd = path.join(os.tmpdir(), 'codesmith_test', Math.random().toString());
14 |
15 | describe('Utils cases', () => {
16 | beforeAll(async () => {
17 | await fs.mkdirp(cwd);
18 | });
19 | afterAll(async () => {
20 | await fs.remove(cwd);
21 | });
22 | test('canUseGit test', async () => {
23 | const canUse = await canUseGit();
24 | expect(canUse).toBe(true);
25 | });
26 | test('isInGitRepo test', async () => {
27 | const alreadyInit = await isInGitRepo(cwd);
28 | expect(alreadyInit).toBe(false);
29 | });
30 | test('initGitRepo test', async () => {
31 | await initGitRepo(cwd, 'main');
32 | const alreadyInit = await isInGitRepo(cwd);
33 | expect(alreadyInit).toBe(true);
34 | });
35 | test('gitAdd and gitCommit test', async () => {
36 | const packageJson = {
37 | name: 'test-git',
38 | version: '0.1.0',
39 | private: true,
40 | };
41 | await fs.writeFile(
42 | path.join(cwd, 'package.json'),
43 | JSON.stringify(packageJson),
44 | { encoding: 'utf-8' },
45 | );
46 | await gitAdd(cwd);
47 | await gitCommit(cwd, 'feat: init');
48 | const result = await execa('git', ['log'], { cwd, env: process.env });
49 | expect(result.stdout.includes('feat: init')).toBeTruthy();
50 | });
51 | });
52 |
--------------------------------------------------------------------------------
/packages/api/git/tests/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@modern-js/tsconfig/base",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "jsx": "preserve",
6 | "baseUrl": "./",
7 | "isolatedModules": true,
8 | "paths": {
9 | "@/*": ["../src/*"]
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/packages/api/git/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@modern-js/tsconfig/base",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "jsx": "preserve",
6 | "baseUrl": "./",
7 | "isolatedModules": true,
8 | "paths": {
9 | "@/*": ["./src/*"]
10 | }
11 | },
12 | "include": ["src"]
13 | }
14 |
--------------------------------------------------------------------------------
/packages/api/handlebars/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | .pnp
4 | .pnp.js
5 | .env.*.local
6 | .history
7 | .rts*
8 | *.log*
9 | *.pid
10 | *.pid.*
11 | *.report
12 | *.lcov
13 | lib-cov
14 |
15 | node_modules/
16 | .npm
17 | .lock-wscript
18 | .yarn-integrity
19 | .node_repl_history
20 | .nyc_output
21 | *.tsbuildinfo
22 | .eslintcache
23 | .sonarlint
24 |
25 | coverage/
26 | release/
27 | output/
28 | output_resource/
29 |
30 | .vscode/**/*
31 | !.vscode/settings.json
32 | !.vscode/extensions.json
33 | .idea/
34 |
35 | **/*/api/typings/auto-generated
36 | **/*/adapters/**/index.ts
37 | **/*/adapters/**/index.js
38 |
39 | src/
40 |
41 | modern.config.*
42 | tsconfig.json
43 | CHANGELOG.md
44 |
--------------------------------------------------------------------------------
/packages/api/handlebars/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Modern.js
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/api/handlebars/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Modern.js
6 |
7 |
8 | A Progressive React Framework for modern web development.
9 |
10 |
11 | ## Getting Started
12 |
13 | Please follow [Quick Start](https://modernjs.dev/en/guides/get-started/quick-start) to get started with Modern.js.
14 |
15 | ## Documentation
16 |
17 | - [English Documentation](https://modernjs.dev/en/)
18 | - [中文文档](https://modernjs.dev)
19 |
20 | ## Contributing
21 |
22 | Please read the [Contributing Guide](https://github.com/web-infra-dev/modern.js/blob/main/CONTRIBUTING.md).
23 |
24 | ## License
25 |
26 | Modern.js is [MIT licensed](https://github.com/web-infra-dev/modern.js/blob/main/LICENSE).
27 |
--------------------------------------------------------------------------------
/packages/api/handlebars/modern.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig, moduleTools } from '@modern-js/module-tools';
2 |
3 | import { testingPlugin } from '@modern-js/plugin-testing';
4 |
5 | export default defineConfig({
6 | buildPreset: 'modern-js-universal',
7 | plugins: [moduleTools(), testingPlugin()],
8 | });
9 |
--------------------------------------------------------------------------------
/packages/api/handlebars/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@modern-js/codesmith-api-handlebars",
3 | "description": "codesmith handlebars api",
4 | "homepage": "https://modernjs.dev",
5 | "bugs": "https://github.com/web-infra-dev/codesmith/issues",
6 | "repository": "web-infra-dev/codesmith",
7 | "license": "MIT",
8 | "keywords": [
9 | "react",
10 | "framework",
11 | "modern",
12 | "modern.js"
13 | ],
14 | "version": "2.6.8",
15 | "jsnext:source": "./src/index.ts",
16 | "types": "./dist/types/index.d.ts",
17 | "main": "./dist/cjs/index.js",
18 | "module": "./dist/esm-node/index.js",
19 | "publishConfig": {
20 | "registry": "https://registry.npmjs.org/",
21 | "access": "public"
22 | },
23 | "scripts": {
24 | "prepare": "pnpm build",
25 | "prepublishOnly": "pnpm build -- --platform",
26 | "new": "modern new",
27 | "build": "modern build",
28 | "test": "modern test"
29 | },
30 | "dependencies": {
31 | "@swc/helpers": "0.5.1",
32 | "handlebars": "^4.7.7"
33 | },
34 | "peerDependencies": {
35 | "@modern-js/codesmith": "workspace:^2.6.8"
36 | },
37 | "devDependencies": {
38 | "@modern-js/codesmith": "workspace:*",
39 | "@modern-js/module-tools": "2.60.3",
40 | "@modern-js/plugin-testing": "2.60.3",
41 | "@types/jest": "^26.0.24",
42 | "@types/node": "^14.18.42",
43 | "typescript": "^4.9.5"
44 | },
45 | "sideEffects": false
46 | }
47 |
--------------------------------------------------------------------------------
/packages/api/handlebars/src/index.ts:
--------------------------------------------------------------------------------
1 | import {
2 | FS_RESOURCE,
3 | type FsMaterial,
4 | type FsResource,
5 | type GeneratorCore,
6 | } from '@modern-js/codesmith';
7 | import type handlebars from 'handlebars';
8 | import { renderString } from './utils';
9 |
10 | type TargetFunction = (globMatch: string) => string;
11 |
12 | type RenderTemplateDirOptions = {
13 | nodir?: boolean;
14 | dot?: boolean;
15 | ignore?: string | readonly string[];
16 | parameters?: Record;
17 | };
18 |
19 | export { renderString };
20 |
21 | export class HandlebarsAPI {
22 | protected readonly generatorCore: GeneratorCore;
23 |
24 | protected readonly registers: {
25 | helpers: Record;
26 | partials: Record;
27 | };
28 |
29 | constructor(
30 | generatorCore: GeneratorCore,
31 | registers?: {
32 | helpers: Record;
33 | partials: Record;
34 | },
35 | ) {
36 | this.generatorCore = generatorCore;
37 | this.registers = registers || { helpers: {}, partials: {} };
38 | }
39 |
40 | public async registerHelp(
41 | helpers: Record,
42 | ) {
43 | this.registers.helpers = {
44 | ...this.registers.helpers,
45 | ...helpers,
46 | };
47 | }
48 |
49 | public async registerPartials(partials: Record) {
50 | this.registers.partials = {
51 | ...this.registers.partials,
52 | ...partials,
53 | };
54 | }
55 |
56 | public async renderTemplate(
57 | templateResource: FsResource,
58 | target: string,
59 | parameters: Record = {},
60 | ) {
61 | if (templateResource._type !== FS_RESOURCE) {
62 | throw new Error('resource not match');
63 | }
64 | const resourceValue = await templateResource.value();
65 | if (typeof resourceValue.content !== 'string') {
66 | throw new Error(
67 | `resource.value is not string, resourceValue=${
68 | resourceValue as unknown as string
69 | }`,
70 | );
71 | }
72 | await this.generatorCore.output.fs(
73 | target,
74 | renderString(resourceValue.content, parameters, this.registers),
75 | { encoding: 'utf-8' },
76 | );
77 | }
78 |
79 | public async renderTemplateDir(
80 | material: FsMaterial,
81 | findGlob: string,
82 | target: TargetFunction,
83 | options?: RenderTemplateDirOptions,
84 | ) {
85 | const resourceMap = await material.find(findGlob, {
86 | nodir: true,
87 | ...options,
88 | });
89 | await Promise.all(
90 | // resourceKey is relate path. example: in `garr-master/package.json`, package.json is resourceKey
91 | Object.keys(resourceMap).map(async resourceKey => {
92 | this.generatorCore.logger.debug(
93 | `💡 [Handlebars Render Template Dir]: resourceKey=${resourceKey}`,
94 | );
95 | await this.renderTemplate(
96 | material.get(resourceKey),
97 | target(resourceKey),
98 | options?.parameters,
99 | );
100 | }),
101 | );
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/packages/api/handlebars/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | export { renderString } from './renderString';
2 |
--------------------------------------------------------------------------------
/packages/api/handlebars/src/utils/renderString.ts:
--------------------------------------------------------------------------------
1 | import handlebars from 'handlebars';
2 |
3 | export function renderString(
4 | template: string,
5 | fullData: Record,
6 | registers?: {
7 | helpers: Record;
8 | partials: Record;
9 | },
10 | ): string {
11 | const helpers: Record = {
12 | ...registers?.helpers,
13 | };
14 | const partials: Record = {
15 | ...registers?.partials,
16 | };
17 | Object.keys(helpers).forEach(h => handlebars.registerHelper(h, helpers[h]));
18 | Object.keys(partials).forEach(p =>
19 | handlebars.registerPartial(p, partials[p]),
20 | );
21 | return handlebars.compile(template)(fullData) || '';
22 | }
23 |
--------------------------------------------------------------------------------
/packages/api/handlebars/tests/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@modern-js/tsconfig/base",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "jsx": "preserve",
6 | "baseUrl": "./",
7 | "isolatedModules": true,
8 | "paths": {
9 | "@/*": ["../src/*"]
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/packages/api/handlebars/tests/utils.test.ts:
--------------------------------------------------------------------------------
1 | import { renderString } from '@/utils';
2 |
3 | describe('Utils cases', () => {
4 | test('renderString test', () => {
5 | const result = renderString('renderString {{ name }}', { name: 'test' });
6 | expect(result).toBe('renderString test');
7 | });
8 | });
9 |
--------------------------------------------------------------------------------
/packages/api/handlebars/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@modern-js/tsconfig/base",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "jsx": "preserve",
6 | "baseUrl": "./",
7 | "isolatedModules": true,
8 | "paths": {
9 | "@/*": ["./src/*"]
10 | }
11 | },
12 | "include": ["src"]
13 | }
14 |
--------------------------------------------------------------------------------
/packages/api/json/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | .pnp
4 | .pnp.js
5 | .env.*.local
6 | .history
7 | .rts*
8 | *.log*
9 | *.pid
10 | *.pid.*
11 | *.report
12 | *.lcov
13 | lib-cov
14 |
15 | node_modules/
16 | .npm
17 | .lock-wscript
18 | .yarn-integrity
19 | .node_repl_history
20 | .nyc_output
21 | *.tsbuildinfo
22 | .eslintcache
23 | .sonarlint
24 |
25 | coverage/
26 | release/
27 | output/
28 | output_resource/
29 |
30 | .vscode/**/*
31 | !.vscode/settings.json
32 | !.vscode/extensions.json
33 | .idea/
34 |
35 | **/*/api/typings/auto-generated
36 | **/*/adapters/**/index.ts
37 | **/*/adapters/**/index.js
38 |
39 | src/
40 |
41 | modern.config.*
42 | tsconfig.json
43 | CHANGELOG.md
44 |
--------------------------------------------------------------------------------
/packages/api/json/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Modern.js
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/api/json/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Modern.js
6 |
7 |
8 | A Progressive React Framework for modern web development.
9 |
10 |
11 | ## Getting Started
12 |
13 | Please follow [Quick Start](https://modernjs.dev/en/guides/get-started/quick-start) to get started with Modern.js.
14 |
15 | ## Documentation
16 |
17 | - [English Documentation](https://modernjs.dev/en/)
18 | - [中文文档](https://modernjs.dev)
19 |
20 | ## Contributing
21 |
22 | Please read the [Contributing Guide](https://github.com/web-infra-dev/modern.js/blob/main/CONTRIBUTING.md).
23 |
24 | ## License
25 |
26 | Modern.js is [MIT licensed](https://github.com/web-infra-dev/modern.js/blob/main/LICENSE).
27 |
--------------------------------------------------------------------------------
/packages/api/json/modern.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig, moduleTools } from '@modern-js/module-tools';
2 |
3 | import { testingPlugin } from '@modern-js/plugin-testing';
4 |
5 | export default defineConfig({
6 | buildPreset: 'modern-js-universal',
7 | plugins: [moduleTools(), testingPlugin()],
8 | });
9 |
--------------------------------------------------------------------------------
/packages/api/json/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@modern-js/codesmith-api-json",
3 | "description": "codesmith json api",
4 | "homepage": "https://modernjs.dev",
5 | "bugs": "https://github.com/web-infra-dev/codesmith/issues",
6 | "repository": "web-infra-dev/codesmith",
7 | "license": "MIT",
8 | "keywords": [
9 | "react",
10 | "framework",
11 | "modern",
12 | "modern.js"
13 | ],
14 | "version": "2.6.8",
15 | "jsnext:source": "./src/index.ts",
16 | "types": "./dist/types/index.d.ts",
17 | "main": "./dist/cjs/index.js",
18 | "module": "./dist/esm-node/index.js",
19 | "publishConfig": {
20 | "registry": "https://registry.npmjs.org/",
21 | "access": "public"
22 | },
23 | "scripts": {
24 | "prepare": "pnpm build",
25 | "prepublishOnly": "pnpm build -- --platform",
26 | "new": "modern new",
27 | "build": "modern build",
28 | "test": "modern test --passWithNoTests"
29 | },
30 | "dependencies": {
31 | "@swc/helpers": "0.5.1",
32 | "@modern-js/codesmith": "workspace:*",
33 | "comment-json": "^4.2.3",
34 | "declaration-update": "^0.0.2"
35 | },
36 | "devDependencies": {
37 | "@modern-js/module-tools": "2.60.3",
38 | "@modern-js/plugin-testing": "2.60.3",
39 | "@types/jest": "^26.0.24",
40 | "@types/node": "^14.18.42",
41 | "typescript": "^4.9.5"
42 | },
43 | "sideEffects": false
44 | }
45 |
--------------------------------------------------------------------------------
/packages/api/json/src/index.ts:
--------------------------------------------------------------------------------
1 | import type { FsResource, GeneratorCore } from '@modern-js/codesmith';
2 | import commentJSON from 'comment-json';
3 | import * as declarationUpdate from 'declaration-update';
4 | import { editJson } from './utils';
5 |
6 | export class JsonAPI {
7 | protected readonly generatorCore: GeneratorCore;
8 |
9 | constructor(generatorCore: GeneratorCore) {
10 | this.generatorCore = generatorCore;
11 | }
12 |
13 | public async get(resource: FsResource) {
14 | const originJsonValue = await resource.value();
15 | try {
16 | const origin = commentJSON.parse(originJsonValue.content as string);
17 | return origin;
18 | } catch (e) {
19 | this.generatorCore.logger.debug('❗️ [JSON Get Parse Error]:', e);
20 | throw new Error('resource content is not a legal json');
21 | }
22 | }
23 |
24 | public async extend(
25 | resource: FsResource,
26 | obj: Record,
27 | endWithNewLine = false,
28 | ) {
29 | await editJson(this.generatorCore, resource, async () => {
30 | const originJsonValue = await resource.value();
31 | try {
32 | const origin = commentJSON.parse(originJsonValue.content as string);
33 | const newObj = commentJSON.assign(origin, obj);
34 | const jsonIntent = 2;
35 | return (
36 | commentJSON.stringify(newObj, undefined, jsonIntent) +
37 | (endWithNewLine ? '\n' : '')
38 | );
39 | } catch (e) {
40 | this.generatorCore.logger.debug('❗️ [JSON Extend Parse Error]:', e);
41 | throw new Error('resource content is not a legal json');
42 | }
43 | });
44 | }
45 |
46 | public async update(
47 | resource: FsResource,
48 | operation: { query: Record; update: Record },
49 | endWithNewLine = false,
50 | ) {
51 | await editJson(this.generatorCore, resource, text => {
52 | try {
53 | const jsonContent = commentJSON.parse(text) as Record;
54 | declarationUpdate.query(jsonContent, operation.query, operation.update);
55 | const jsonIntent = 2;
56 | return Promise.resolve(
57 | commentJSON.stringify(jsonContent, undefined, jsonIntent) +
58 | (endWithNewLine ? '\n' : ''),
59 | );
60 | } catch (e) {
61 | this.generatorCore.logger.debug('❗️ [JSON Update Parse Error]:', e);
62 | throw new Error('resource content is not a legal json');
63 | }
64 | });
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/packages/api/json/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | import type { FsResource, GeneratorCore } from '@modern-js/codesmith';
2 |
3 | export async function editJson(
4 | generatorCore: GeneratorCore,
5 | resource: FsResource,
6 | getNewJsonValue: (text: string) => Promise,
7 | ): Promise {
8 | const originJsonValue = await resource.value();
9 | const newJsonString = await getNewJsonValue(
10 | originJsonValue.content as string,
11 | );
12 | if (!newJsonString) {
13 | throw new Error('get new json string is undefined');
14 | }
15 | await generatorCore.output.fs(resource.filePath, newJsonString, {
16 | encoding: 'utf-8',
17 | });
18 | return newJsonString;
19 | }
20 |
--------------------------------------------------------------------------------
/packages/api/json/tests/index.test.ts:
--------------------------------------------------------------------------------
1 | import commentJSON from 'comment-json';
2 | import * as declarationUpdate from 'declaration-update';
3 |
4 | describe('update json', () => {
5 | it('simple string', () => {
6 | const jsonContent = commentJSON.parse('{}');
7 | declarationUpdate.query(
8 | jsonContent,
9 | {},
10 | {
11 | $set: { a: '1' },
12 | },
13 | );
14 | expect(jsonContent).toEqual({ a: '1' });
15 | });
16 | it('complex string', () => {
17 | const jsonContent = commentJSON.parse('{}');
18 | declarationUpdate.query(
19 | jsonContent,
20 | {},
21 | {
22 | $set: {
23 | a: {
24 | b: '2',
25 | },
26 | },
27 | },
28 | );
29 | expect(jsonContent).toEqual({
30 | a: {
31 | b: '2',
32 | },
33 | });
34 | });
35 | it('simple array', () => {
36 | const jsonContent = commentJSON.parse('{}');
37 | declarationUpdate.query(
38 | jsonContent,
39 | {},
40 | {
41 | $set: ['1', '2', '3'],
42 | },
43 | );
44 | expect(jsonContent).toEqual({
45 | '0': '1',
46 | '1': '2',
47 | '2': '3',
48 | });
49 | });
50 | it('complex array', () => {
51 | const jsonContent = commentJSON.parse('{}');
52 | declarationUpdate.query(
53 | jsonContent,
54 | {},
55 | {
56 | $set: [
57 | {
58 | a: '1',
59 | },
60 | {
61 | b: '2',
62 | },
63 | {
64 | c: '3',
65 | },
66 | ],
67 | },
68 | );
69 | expect(jsonContent).toEqual({
70 | '0': {
71 | a: '1',
72 | },
73 | '1': {
74 | b: '2',
75 | },
76 | '2': {
77 | c: '3',
78 | },
79 | });
80 | });
81 | it('string and array', () => {
82 | const jsonContent = commentJSON.parse('{}');
83 | declarationUpdate.query(
84 | jsonContent,
85 | {},
86 | {
87 | $set: {
88 | a: ['1', '2', '3'],
89 | b: {
90 | b1: 'b1',
91 | },
92 | },
93 | },
94 | );
95 | expect(jsonContent).toEqual({
96 | a: ['1', '2', '3'],
97 | b: {
98 | b1: 'b1',
99 | },
100 | });
101 | });
102 | });
103 |
--------------------------------------------------------------------------------
/packages/api/json/tests/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@modern-js/tsconfig/base",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "jsx": "preserve",
6 | "baseUrl": "./",
7 | "isolatedModules": true,
8 | "paths": {
9 | "@/*": ["../src/*"]
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/packages/api/json/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@modern-js/tsconfig/base",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "jsx": "preserve",
6 | "baseUrl": "./",
7 | "isolatedModules": true,
8 | "paths": {
9 | "@/*": ["./src/*"]
10 | }
11 | },
12 | "include": ["src"]
13 | }
14 |
--------------------------------------------------------------------------------
/packages/api/npm/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | .pnp
4 | .pnp.js
5 | .env.*.local
6 | .history
7 | .rts*
8 | *.log*
9 | *.pid
10 | *.pid.*
11 | *.report
12 | *.lcov
13 | lib-cov
14 |
15 | node_modules/
16 | .npm
17 | .lock-wscript
18 | .yarn-integrity
19 | .node_repl_history
20 | .nyc_output
21 | *.tsbuildinfo
22 | .eslintcache
23 | .sonarlint
24 |
25 | coverage/
26 | release/
27 | output/
28 | output_resource/
29 |
30 | .vscode/**/*
31 | !.vscode/settings.json
32 | !.vscode/extensions.json
33 | .idea/
34 |
35 | **/*/api/typings/auto-generated
36 | **/*/adapters/**/index.ts
37 | **/*/adapters/**/index.js
38 |
39 | src/
40 |
41 | modern.config.*
42 | tsconfig.json
43 | CHANGELOG.md
44 |
--------------------------------------------------------------------------------
/packages/api/npm/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Modern.js
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/api/npm/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Modern.js
6 |
7 |
8 | A Progressive React Framework for modern web development.
9 |
10 |
11 | ## Getting Started
12 |
13 | Please follow [Quick Start](https://modernjs.dev/en/guides/get-started/quick-start) to get started with Modern.js.
14 |
15 | ## Documentation
16 |
17 | - [English Documentation](https://modernjs.dev/en/)
18 | - [中文文档](https://modernjs.dev)
19 |
20 | ## Contributing
21 |
22 | Please read the [Contributing Guide](https://github.com/web-infra-dev/modern.js/blob/main/CONTRIBUTING.md).
23 |
24 | ## License
25 |
26 | Modern.js is [MIT licensed](https://github.com/web-infra-dev/modern.js/blob/main/LICENSE).
27 |
--------------------------------------------------------------------------------
/packages/api/npm/modern.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig, moduleTools } from '@modern-js/module-tools';
2 |
3 | import { testingPlugin } from '@modern-js/plugin-testing';
4 |
5 | export default defineConfig({
6 | buildPreset: 'modern-js-universal',
7 | plugins: [moduleTools(), testingPlugin()],
8 | });
9 |
--------------------------------------------------------------------------------
/packages/api/npm/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@modern-js/codesmith-api-npm",
3 | "description": "codesmith npm api",
4 | "homepage": "https://modernjs.dev",
5 | "bugs": "https://github.com/web-infra-dev/codesmith/issues",
6 | "repository": "web-infra-dev/codesmith",
7 | "license": "MIT",
8 | "keywords": [
9 | "react",
10 | "framework",
11 | "modern",
12 | "modern.js"
13 | ],
14 | "version": "2.6.8",
15 | "jsnext:source": "./src/index.ts",
16 | "types": "./dist/types/index.d.ts",
17 | "main": "./dist/cjs/index.js",
18 | "module": "./dist/esm-node/index.js",
19 | "publishConfig": {
20 | "registry": "https://registry.npmjs.org/",
21 | "access": "public"
22 | },
23 | "scripts": {
24 | "prepare": "pnpm build",
25 | "prepublishOnly": "pnpm build -- --platform",
26 | "new": "modern new",
27 | "build": "modern build",
28 | "test": "modern test"
29 | },
30 | "dependencies": {
31 | "@swc/helpers": "0.5.1",
32 | "@modern-js/codesmith-utils": "workspace:*"
33 | },
34 | "peerDependencies": {
35 | "@modern-js/codesmith": "workspace:^2.6.8"
36 | },
37 | "devDependencies": {
38 | "@modern-js/codesmith": "workspace:*",
39 | "@modern-js/module-tools": "2.60.3",
40 | "@modern-js/plugin-testing": "2.60.3",
41 | "@types/jest": "^26.0.24",
42 | "@types/node": "^14.18.42",
43 | "typescript": "^4.9.5"
44 | },
45 | "sideEffects": false
46 | }
47 |
--------------------------------------------------------------------------------
/packages/api/npm/src/index.ts:
--------------------------------------------------------------------------------
1 | import type { GeneratorCore } from '@modern-js/codesmith';
2 | import type { ExecaReturnValue } from '@modern-js/codesmith-utils/execa';
3 | import { npmInstall, pnpmInstall, yarnInstall } from './utils';
4 |
5 | export * from './utils';
6 | export class NpmAPI {
7 | protected readonly generatorCore: GeneratorCore;
8 |
9 | constructor(generatorCore: GeneratorCore) {
10 | this.generatorCore = generatorCore;
11 | }
12 |
13 | public npmInstall({
14 | cwd,
15 | registryUrl,
16 | ignoreScripts,
17 | }: {
18 | cwd?: string;
19 | registryUrl?: string;
20 | ignoreScripts?: boolean;
21 | useNvm?: boolean;
22 | }): Promise {
23 | return npmInstall({
24 | cwd: cwd || this.generatorCore.outputPath,
25 | registryUrl,
26 | ignoreScripts,
27 | });
28 | }
29 |
30 | public yarnInstall({
31 | cwd,
32 | registryUrl,
33 | ignoreScripts,
34 | }: {
35 | cwd?: string;
36 | registryUrl?: string;
37 | ignoreScripts?: boolean;
38 | useNvm?: boolean;
39 | }): Promise {
40 | return yarnInstall({
41 | cwd: cwd || this.generatorCore.outputPath,
42 | registryUrl,
43 | ignoreScripts,
44 | });
45 | }
46 |
47 | public pnpmInstall({
48 | cwd,
49 | registryUrl,
50 | ignoreScripts,
51 | }: {
52 | cwd?: string;
53 | registryUrl?: string;
54 | ignoreScripts?: boolean;
55 | useNvm?: boolean;
56 | }): Promise {
57 | return pnpmInstall({
58 | cwd: cwd || this.generatorCore.outputPath,
59 | registryUrl,
60 | ignoreScripts,
61 | });
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/packages/api/npm/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | export {
2 | canUseNvm,
3 | canUseFnm,
4 | canUseNpm,
5 | canUseYarn,
6 | canUsePnpm,
7 | } from '@modern-js/codesmith-utils/npm';
8 | export {
9 | npmInstall,
10 | yarnInstall,
11 | pnpmInstall,
12 | execaWithStreamLog,
13 | runInstallWithNvm,
14 | } from './install';
15 |
--------------------------------------------------------------------------------
/packages/api/npm/src/utils/install.ts:
--------------------------------------------------------------------------------
1 | import { type ExecaReturnValue, execa } from '@modern-js/codesmith-utils/execa';
2 | import {
3 | canUseNpm,
4 | canUsePnpm,
5 | canUseYarn,
6 | } from '@modern-js/codesmith-utils/npm';
7 |
8 | export function execaWithStreamLog(
9 | command: string,
10 | args: string[],
11 | options: Record,
12 | ) {
13 | const promise = execa(command, args, {
14 | ...options,
15 | stdin: 'inherit',
16 | stdout: 'inherit',
17 | stderr: 'inherit',
18 | });
19 | return promise;
20 | }
21 |
22 | export async function runInstallWithNvm(
23 | command: string,
24 | options: Record,
25 | ): Promise {
26 | return await execa(`~/.nvm/nvm-exec ${command}`, {
27 | ...options,
28 | shell: true,
29 | stdin: 'inherit',
30 | stdout: 'inherit',
31 | stderr: 'inherit',
32 | });
33 | }
34 |
35 | export async function npmInstall({
36 | cwd,
37 | registryUrl,
38 | ignoreScripts,
39 | useNvm,
40 | }: {
41 | cwd: string;
42 | registryUrl?: string;
43 | ignoreScripts?: boolean;
44 | useNvm?: boolean;
45 | }): Promise {
46 | const canUse = await canUseNpm();
47 | if (canUse) {
48 | const params = ['install'];
49 | if (registryUrl) {
50 | params.push(`--registry=${registryUrl}`);
51 | }
52 | if (ignoreScripts) {
53 | params.push('--ignore-scripts');
54 | }
55 | if (useNvm) {
56 | return runInstallWithNvm(`npm ${params.join(' ')}`, {
57 | cwd,
58 | env: process.env,
59 | });
60 | }
61 | return execaWithStreamLog('npm', params, {
62 | cwd,
63 | env: process.env,
64 | });
65 | }
66 | throw new Error('please install npm first');
67 | }
68 |
69 | export async function yarnInstall({
70 | cwd,
71 | registryUrl,
72 | ignoreScripts,
73 | useNvm,
74 | }: {
75 | cwd: string;
76 | registryUrl?: string;
77 | ignoreScripts?: boolean;
78 | useNvm?: boolean;
79 | }): Promise {
80 | const canUse = await canUseYarn();
81 | if (canUse) {
82 | const params = ['install'];
83 | if (registryUrl) {
84 | params.push(`--registry=${registryUrl}`);
85 | }
86 | if (ignoreScripts) {
87 | params.push('--ignore-scripts');
88 | }
89 | if (useNvm) {
90 | return runInstallWithNvm(`yarn ${params.join(' ')}`, {
91 | cwd,
92 | env: process.env,
93 | });
94 | }
95 | return execaWithStreamLog('yarn', params, { cwd, env: process.env });
96 | }
97 | throw new Error('please install yarn first');
98 | }
99 |
100 | export async function pnpmInstall({
101 | cwd,
102 | registryUrl,
103 | ignoreScripts,
104 | useNvm,
105 | }: {
106 | cwd: string;
107 | registryUrl?: string;
108 | ignoreScripts?: boolean;
109 | useNvm?: boolean;
110 | }): Promise {
111 | const canUse = await canUsePnpm();
112 | if (canUse) {
113 | const params = ['install'];
114 | if (registryUrl) {
115 | params.push(`--registry=${registryUrl}`);
116 | }
117 | if (ignoreScripts) {
118 | params.push('--ignore-scripts');
119 | }
120 | if (useNvm) {
121 | return runInstallWithNvm(`yarn ${params.join(' ')}`, {
122 | cwd,
123 | env: process.env,
124 | });
125 | }
126 | return execaWithStreamLog('pnpm', params, { cwd, env: process.env });
127 | }
128 | throw new Error('please install pnpm first');
129 | }
130 |
--------------------------------------------------------------------------------
/packages/api/npm/tests/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@modern-js/tsconfig/base",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "jsx": "preserve",
6 | "baseUrl": "./",
7 | "isolatedModules": true,
8 | "paths": {
9 | "@/*": ["../src/*"]
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/packages/api/npm/tests/utils.test.ts:
--------------------------------------------------------------------------------
1 | import os from 'os';
2 | import path from 'path';
3 | import {
4 | execaWithStreamLog,
5 | npmInstall,
6 | pnpmInstall,
7 | yarnInstall,
8 | } from '@/utils/install';
9 | import { fs } from '@modern-js/codesmith-utils/fs-extra';
10 | import {
11 | canUseFnm,
12 | canUseNpm,
13 | canUseNvm,
14 | canUseYarn,
15 | } from '@modern-js/codesmith-utils/npm';
16 |
17 | describe('Env utils cases', () => {
18 | test('can use nvm', async () => {
19 | const result = await canUseNvm();
20 | expect(typeof result === 'boolean').toBeTruthy();
21 | });
22 | test('can use fnm', async () => {
23 | const result = await canUseFnm();
24 | expect(typeof result === 'boolean').toBeTruthy();
25 | });
26 | test('can use npm', async () => {
27 | const result = await canUseNpm();
28 | expect(typeof result === 'boolean').toBeTruthy();
29 | });
30 | test('can use yarn', async () => {
31 | const result = await canUseYarn();
32 | expect(typeof result === 'boolean').toBeTruthy();
33 | });
34 | test('can use yarn', async () => {
35 | const result = await canUseYarn();
36 | expect(typeof result === 'boolean').toBeTruthy();
37 | });
38 | });
39 |
40 | const cwd = path.join(os.tmpdir(), 'codesmith_test', Math.random().toString());
41 |
42 | describe('Install cases', () => {
43 | beforeEach(async () => {
44 | await fs.mkdirp(cwd);
45 | const packageJson = {
46 | name: 'test-npm',
47 | version: '0.1.0',
48 | private: true,
49 | dependencies: {
50 | lodash: '^4',
51 | },
52 | };
53 | await fs.writeFile(
54 | path.join(cwd, 'package.json'),
55 | JSON.stringify(packageJson),
56 | { encoding: 'utf-8' },
57 | );
58 | });
59 | afterEach(async () => {
60 | await fs.remove(cwd);
61 | });
62 | test('npm install', async () => {
63 | const result = await npmInstall({ cwd });
64 | expect(result?.exitCode).toBe(0);
65 | expect(fs.existsSync(path.join(cwd, 'node_modules', 'lodash'))).toBe(true);
66 | });
67 | test('yarn install', async () => {
68 | if (!(await canUseYarn())) {
69 | await execaWithStreamLog('npm', ['install', '-g', 'yarn'], {});
70 | }
71 | const result = await yarnInstall({ cwd });
72 | expect(result?.exitCode).toBe(0);
73 | expect(fs.existsSync(path.join(cwd, 'node_modules', 'lodash'))).toBe(true);
74 | });
75 | test('pnpm install', async () => {
76 | const result = await pnpmInstall({ cwd });
77 | expect(result?.exitCode).toBe(0);
78 | expect(fs.existsSync(path.join(cwd, 'node_modules', 'lodash'))).toBe(true);
79 | });
80 | });
81 |
--------------------------------------------------------------------------------
/packages/api/npm/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@modern-js/tsconfig/base",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "jsx": "preserve",
6 | "baseUrl": "./",
7 | "isolatedModules": true,
8 | "paths": {
9 | "@/*": ["./src/*"]
10 | }
11 | },
12 | "include": ["src"]
13 | }
14 |
--------------------------------------------------------------------------------
/packages/cli/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Modern.js
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/cli/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Modern.js
6 |
7 |
8 | A Progressive React Framework for modern web development.
9 |
10 |
11 | ## Getting Started
12 |
13 | Please follow [Quick Start](https://modernjs.dev/en/guides/get-started/quick-start) to get started with Modern.js.
14 |
15 | ## Documentation
16 |
17 | - [English Documentation](https://modernjs.dev/en/)
18 | - [中文文档](https://modernjs.dev)
19 |
20 | ## Contributing
21 |
22 | Please read the [Contributing Guide](https://github.com/web-infra-dev/modern.js/blob/main/CONTRIBUTING.md).
23 |
24 | ## License
25 |
26 | Modern.js is [MIT licensed](https://github.com/web-infra-dev/modern.js/blob/main/LICENSE).
27 |
--------------------------------------------------------------------------------
/packages/cli/bin/run.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 |
6 | const pkgInfo = require(path.join(__dirname, '../package.json'));
7 | const srcPath = pkgInfo['jsnext:source'];
8 | const distPath = pkgInfo.main;
9 | const project = path.join(__dirname, '../tsconfig.json');
10 | let env = 'production';
11 | if (fs.existsSync(project)) {
12 | env = 'development';
13 | }
14 | if (process.env.NODE_ENV) {
15 | env = process.env.NODE_ENV;
16 | }
17 |
18 | if (env === 'development') {
19 | require('ts-node').register({
20 | project,
21 | transpileOnly: true,
22 | typeCheck: false,
23 | });
24 | }
25 |
26 | try {
27 | require(`../${env === 'development' ? srcPath : distPath}`).default();
28 | } catch (e) {
29 | console.error(e);
30 | }
31 |
--------------------------------------------------------------------------------
/packages/cli/modern.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig, moduleTools } from '@modern-js/module-tools';
2 |
3 | import { testingPlugin } from '@modern-js/plugin-testing';
4 |
5 | export default defineConfig({
6 | buildConfig: {
7 | autoExternal: false,
8 | dts: false,
9 | sideEffects: false,
10 | },
11 | plugins: [moduleTools(), testingPlugin()],
12 | });
13 |
--------------------------------------------------------------------------------
/packages/cli/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@modern-js/codesmith-cli",
3 | "description": "codesmith cli tools",
4 | "homepage": "https://modernjs.dev",
5 | "bugs": "https://github.com/web-infra-dev/codesmith/issues",
6 | "repository": "web-infra-dev/codesmith",
7 | "license": "MIT",
8 | "keywords": [
9 | "react",
10 | "framework",
11 | "modern",
12 | "modern.js"
13 | ],
14 | "version": "2.6.8",
15 | "jsnext:source": "./src/index.ts",
16 | "main": "./dist/index.js",
17 | "bin": {
18 | "codesmith": "./bin/run.js"
19 | },
20 | "files": [
21 | "/bin",
22 | "/dist"
23 | ],
24 | "publishConfig": {
25 | "registry": "https://registry.npmjs.org/",
26 | "access": "public"
27 | },
28 | "scripts": {
29 | "prepare": "pnpm build",
30 | "new": "modern new",
31 | "build": "modern build",
32 | "test": "modern test --passWithNoTests"
33 | },
34 | "dependencies": {
35 | "commander": "10.0.0",
36 | "@swc/helpers": "0.5.1",
37 | "@modern-js/codesmith": "workspace:*",
38 | "@modern-js/codesmith-utils": "workspace:*",
39 | "@modern-js/plugin-i18n": "2.60.3"
40 | },
41 | "devDependencies": {
42 | "@modern-js/module-tools": "2.60.3",
43 | "@modern-js/plugin-testing": "2.60.3",
44 | "@types/jest": "^26.0.24",
45 | "@types/node": "^14.18.42",
46 | "ts-node": "^10.9.1",
47 | "typescript": "^4.9.5"
48 | },
49 | "sideEffects": false
50 | }
51 |
--------------------------------------------------------------------------------
/packages/cli/src/actions/genAction.ts:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import { CodeSmith } from '@modern-js/codesmith';
3 | import { getLocalLanguage } from '../utils';
4 |
5 | interface LocalOptions {
6 | debug?: boolean;
7 | time?: boolean;
8 | config: string;
9 | registry?: string;
10 | pwd?: string;
11 | }
12 |
13 | export async function genAction(generator: string, genOptions: LocalOptions) {
14 | const { debug, time, config, registry, pwd } = genOptions;
15 | const smith = new CodeSmith({
16 | debug,
17 | time,
18 | registryUrl: registry,
19 | });
20 |
21 | await smith.prepareGlobal();
22 |
23 | smith.logger.debug('💡 [Runtime Gen Action]');
24 | smith.logger.debug('💡 [Generator Name]:', generator);
25 | smith.logger.debug('💡 [Generator Pwd]:', pwd);
26 | smith.logger.debug('💡 [Generator Debug]:', debug);
27 | smith.logger.debug('💡 [Generator Options]:', config);
28 |
29 | let runPwd = process.cwd();
30 | if (pwd) {
31 | if (path.isAbsolute(pwd)) {
32 | runPwd = pwd;
33 | smith.logger.debug('💡 [PWD is Absolute Path]:', pwd);
34 | } else {
35 | runPwd = path.join(process.cwd(), pwd);
36 | smith.logger.debug('💡 [PWD is Relative Path]:', pwd);
37 | }
38 | }
39 |
40 | let targetConfig: Record = {};
41 | try {
42 | targetConfig = JSON.parse(config);
43 | } catch (e) {
44 | smith.logger.error('🔴 [Config Parse Error]:', e);
45 | return;
46 | }
47 |
48 | const tasks = [
49 | {
50 | name: generator,
51 | config: {
52 | locale: getLocalLanguage(),
53 | ...targetConfig,
54 | },
55 | },
56 | ];
57 |
58 | await smith.forge({
59 | tasks: tasks.map(runner => ({
60 | generator: runner.name,
61 | config: runner.config,
62 | })),
63 | pwd: runPwd,
64 | });
65 | }
66 |
--------------------------------------------------------------------------------
/packages/cli/src/index.ts:
--------------------------------------------------------------------------------
1 | import { Command } from 'commander';
2 | import { genAction } from './actions/genAction';
3 |
4 | export default function () {
5 | const program = new Command();
6 |
7 | program
8 | .command('gen ', { isDefault: true })
9 | .description('use csmith to generator something')
10 | .option('-d,--debug', 'using debug mode to log something', false)
11 | .option('--time', 'show time logger', false)
12 | .option('-p,--pwd ', 'process working directory', process.cwd())
13 | .option('--config ', 'config for this generator(json string)', '{}')
14 | .option(
15 | '--registry ',
16 | 'set npm registry url to run npm command',
17 | undefined,
18 | )
19 | .action(genAction);
20 |
21 | program.parse(process.argv);
22 | }
23 |
--------------------------------------------------------------------------------
/packages/cli/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | import { I18CLILanguageDetector } from '@modern-js/plugin-i18n/language-detector';
2 |
3 | export function getLocalLanguage() {
4 | const detector = new I18CLILanguageDetector();
5 | return detector.detect();
6 | }
7 |
--------------------------------------------------------------------------------
/packages/cli/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@modern-js/tsconfig/base",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "jsx": "preserve",
6 | "baseUrl": "./",
7 | "isolatedModules": true,
8 | "paths": {
9 | "@/*": ["./src/*"]
10 | }
11 | },
12 | "include": ["src"]
13 | }
14 |
--------------------------------------------------------------------------------
/packages/core/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | .pnp
4 | .pnp.js
5 | .env.*.local
6 | .history
7 | .rts*
8 | *.log*
9 | *.pid
10 | *.pid.*
11 | *.report
12 | *.lcov
13 | lib-cov
14 |
15 | node_modules/
16 | .npm
17 | .lock-wscript
18 | .yarn-integrity
19 | .node_repl_history
20 | .nyc_output
21 | *.tsbuildinfo
22 | .eslintcache
23 | .sonarlint
24 |
25 | coverage/
26 | release/
27 | output/
28 | output_resource/
29 |
30 | .vscode/**/*
31 | !.vscode/settings.json
32 | !.vscode/extensions.json
33 | .idea/
34 |
35 | **/*/api/typings/auto-generated
36 | **/*/adapters/**/index.ts
37 | **/*/adapters/**/index.js
38 |
39 | src/
40 | modern.config.*
41 | tsconfig.json
42 | CHANGELOG.md
43 |
--------------------------------------------------------------------------------
/packages/core/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Modern.js
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/core/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Modern.js
6 |
7 |
8 | A Progressive React Framework for modern web development.
9 |
10 |
11 | ## Getting Started
12 |
13 | Please follow [Quick Start](https://modernjs.dev/en/guides/get-started/quick-start) to get started with Modern.js.
14 |
15 | ## Documentation
16 |
17 | - [English Documentation](https://modernjs.dev/en/)
18 | - [中文文档](https://modernjs.dev)
19 |
20 | ## Contributing
21 |
22 | Please read the [Contributing Guide](https://github.com/web-infra-dev/modern.js/blob/main/CONTRIBUTING.md).
23 |
24 | ## License
25 |
26 | Modern.js is [MIT licensed](https://github.com/web-infra-dev/modern.js/blob/main/LICENSE).
27 |
--------------------------------------------------------------------------------
/packages/core/modern.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig, moduleTools } from '@modern-js/module-tools';
2 |
3 | import { testingPlugin } from '@modern-js/plugin-testing';
4 |
5 | export default defineConfig({
6 | buildPreset: 'modern-js-universal',
7 | plugins: [moduleTools(), testingPlugin()],
8 | });
9 |
--------------------------------------------------------------------------------
/packages/core/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@modern-js/codesmith",
3 | "description": "codesmith core implement",
4 | "homepage": "https://modernjs.dev",
5 | "bugs": "https://github.com/web-infra-dev/codesmith/issues",
6 | "repository": "web-infra-dev/codesmith",
7 | "license": "MIT",
8 | "keywords": [
9 | "react",
10 | "framework",
11 | "modern",
12 | "modern.js"
13 | ],
14 | "version": "2.6.8",
15 | "jsnext:source": "./src/index.ts",
16 | "types": "./dist/types/index.d.ts",
17 | "main": "./dist/cjs/index.js",
18 | "module": "./dist/esm-node/index.js",
19 | "publishConfig": {
20 | "registry": "https://registry.npmjs.org/",
21 | "access": "public"
22 | },
23 | "scripts": {
24 | "prepare": "pnpm build",
25 | "prepublishOnly": "pnpm build -- --platform",
26 | "new": "modern new",
27 | "build": "modern build",
28 | "test": "modern test --env=node"
29 | },
30 | "dependencies": {
31 | "@swc/helpers": "0.5.1",
32 | "axios": "^1.6.0",
33 | "debug": "4.3.7",
34 | "tar": "^6.1.13",
35 | "@modern-js/codesmith-utils": "workspace:*"
36 | },
37 | "devDependencies": {
38 | "@modern-js/module-tools": "2.60.3",
39 | "@modern-js/plugin-testing": "2.60.3",
40 | "@types/jest": "^26.0.24",
41 | "@types/node": "^14.18.42",
42 | "@types/tar": "^4.0.5",
43 | "@types/debug": "^4.1.12",
44 | "typescript": "^4.9.5"
45 | },
46 | "sideEffects": false
47 | }
48 |
--------------------------------------------------------------------------------
/packages/core/src/codesmith/constants.ts:
--------------------------------------------------------------------------------
1 | export interface ForgeTask {
2 | // generator name, support 'local generator' and 'npm generator'
3 | generator: string;
4 | // generator config
5 | config?: Record;
6 | }
7 |
8 | export interface ForgeOptions {
9 | tasks: ForgeTask[];
10 | pwd?: string;
11 | }
12 |
--------------------------------------------------------------------------------
/packages/core/src/codesmith/index.ts:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import { GeneratorCore } from '@/generator';
3 | import { Logger } from '@/logger';
4 | import { LoggerLevel } from '@/logger/constants';
5 | import { MaterialsManager } from '@/materials';
6 | import { FsMaterial } from '@/materials/FsMaterial';
7 | import type { ForgeOptions, ForgeTask } from './constants';
8 |
9 | interface ICreateOptions {
10 | debug?: boolean;
11 | time?: boolean;
12 | logger?: Logger;
13 | // custom npm registry
14 | registryUrl?: string;
15 | namespace?: string;
16 | }
17 |
18 | export class CodeSmith {
19 | core?: GeneratorCore;
20 |
21 | materialsManager: MaterialsManager;
22 |
23 | // current mode is debug mode
24 | debug = false;
25 |
26 | logger: Logger;
27 |
28 | constructor({ debug, time, logger, registryUrl, namespace }: ICreateOptions) {
29 | this.debug = debug || false;
30 | this.logger =
31 | logger ||
32 | new Logger(
33 | debug
34 | ? LoggerLevel.Debug
35 | : time
36 | ? LoggerLevel.Timing
37 | : LoggerLevel.Info,
38 | namespace,
39 | );
40 | this.materialsManager = new MaterialsManager(this.logger, registryUrl);
41 | }
42 |
43 | public async forge({ tasks, pwd }: ForgeOptions) {
44 | this.logger?.timing?.('🕒 Codesmith Task');
45 | this.core = new GeneratorCore({
46 | logger: this.logger,
47 | materialsManager: this.materialsManager,
48 | outputPath: pwd || process.cwd(),
49 | });
50 | this.core.addMaterial(
51 | 'default',
52 | new FsMaterial(path.resolve(pwd || process.cwd())),
53 | );
54 | try {
55 | for (const task of tasks) {
56 | await this.runTask(task);
57 | }
58 | } catch (e: unknown) {
59 | this.logger.error('🔴 [Run Forge Generator Error]:', e);
60 | throw new Error('run task error');
61 | } finally {
62 | this.logger?.timing?.('🕒 Codesmith Task', true);
63 | }
64 | }
65 |
66 | private async runTask(task: ForgeTask) {
67 | if (!this.core) {
68 | throw new Error("no core in 'runTask'");
69 | }
70 | const { generator, config } = task;
71 | this.logger?.timing?.(`🕒 RunTask ${generator}`);
72 | await this.core.runGenerator(generator, config);
73 | this.logger?.timing?.(`🕒 RunTask ${generator}`, true);
74 | }
75 |
76 | public async prepareGenerators(generators: string[]) {
77 | await this.materialsManager.prepareGenerators(generators);
78 | }
79 |
80 | public async prepareGlobal() {
81 | if ((global as any).CODESMITH_PREPARE_GLOBAL) {
82 | return;
83 | }
84 | await this.materialsManager.prepareGlobal();
85 | (global as any).CODESMITH_PREPARE_GLOBAL = true;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/packages/core/src/constants.ts:
--------------------------------------------------------------------------------
1 | export const NPM_API_TIMEOUT = 30000;
2 | export const CATCHE_VALIDITY_PREIOD = 7 * 24 * 3600 * 1000;
3 |
--------------------------------------------------------------------------------
/packages/core/src/generator/constants.ts:
--------------------------------------------------------------------------------
1 | import type { FsMaterial } from '@/materials/FsMaterial';
2 |
3 | export interface RuntimeCurrent {
4 | material: FsMaterial;
5 | }
6 |
7 | export interface GeneratorContext {
8 | materials: Record;
9 | config: Record; // Generator config
10 | data?: Record; // RuntimeCurrent context data
11 | current: RuntimeCurrent | null; // RuntimeCurrent
12 | [key: string]: any;
13 | }
14 |
--------------------------------------------------------------------------------
/packages/core/src/index.ts:
--------------------------------------------------------------------------------
1 | export type { ILogger } from './logger/constants';
2 | export { LoggerLevel } from './logger/constants';
3 | export { Logger } from './logger';
4 |
5 | export { CodeSmith } from './codesmith';
6 | export { GeneratorCore } from './generator';
7 | export type { GeneratorContext } from './generator/constants';
8 |
9 | export { MaterialsManager } from './materials';
10 | export { FsMaterial } from './materials/FsMaterial';
11 | export { FsResource, FS_RESOURCE } from './materials/FsResource';
12 |
13 | export * from './utils';
14 |
--------------------------------------------------------------------------------
/packages/core/src/logger/constants.ts:
--------------------------------------------------------------------------------
1 | export enum LoggerLevel {
2 | Error = 'error',
3 | Warn = 'warn',
4 | Info = 'info',
5 | Debug = 'debug',
6 | Verbose = 'verbose',
7 | Stream = 'stream',
8 | Timing = 'timing',
9 | }
10 |
11 | type LeveledLogMethod = (...meta: any[]) => void;
12 |
13 | type TimingMethod = (key: string, end?: boolean) => void;
14 |
15 | export interface ILogger {
16 | level: LoggerLevel;
17 | // for cli and npm levels
18 | [LoggerLevel.Error]: LeveledLogMethod;
19 | [LoggerLevel.Warn]: LeveledLogMethod;
20 | [LoggerLevel.Info]: LeveledLogMethod;
21 | [LoggerLevel.Timing]: TimingMethod;
22 | [LoggerLevel.Debug]: LeveledLogMethod;
23 | [LoggerLevel.Verbose]: LeveledLogMethod;
24 | [LoggerLevel.Stream]: LeveledLogMethod;
25 | }
26 |
--------------------------------------------------------------------------------
/packages/core/src/logger/index.ts:
--------------------------------------------------------------------------------
1 | import { chalk } from '@modern-js/codesmith-utils/chalk';
2 | import { type Debugger, debug } from 'debug';
3 | import { type ILogger, LoggerLevel } from './constants';
4 |
5 | export { LoggerLevel };
6 | export class Logger implements ILogger {
7 | level: LoggerLevel = LoggerLevel.Info;
8 | errorLogger: Debugger;
9 | warningLogger: Debugger;
10 | debugLogger: Debugger;
11 | timingLogger: Debugger;
12 | verboseLogger: Debugger;
13 | streamLogger: Debugger;
14 |
15 | constructor(level: LoggerLevel = LoggerLevel.Info, namespace = 'codesmith') {
16 | if (!process.env.DEBUG) {
17 | process.env.DEBUG = `${namespace}:*`;
18 | debug.enable(process.env.DEBUG);
19 | }
20 | this.level = level;
21 | this.warningLogger = debug(`${namespace}:warn`);
22 | this.errorLogger = debug(`${namespace}:error`);
23 | this.debugLogger = debug(`${namespace}:debug`);
24 | this.timingLogger = debug(`${namespace}:timing`);
25 | this.verboseLogger = debug(`${namespace}:verbose`);
26 | this.streamLogger = debug(`${namespace}:stream`);
27 | }
28 |
29 | info(...meta: any[]) {
30 | console.log(chalk.green('[INFO]'), ...meta);
31 | }
32 |
33 | error(message: string, ...args: any[]) {
34 | this.errorLogger(message, ...args);
35 | }
36 |
37 | warn(message: string, ...args: any[]) {
38 | this.warningLogger(message, ...args);
39 | }
40 |
41 | debug(message: string, ...args: any[]) {
42 | if (this.level === LoggerLevel.Timing) {
43 | return;
44 | }
45 | if (this.level === LoggerLevel.Debug) {
46 | this.debugLogger(message, ...args);
47 | }
48 | }
49 |
50 | timing(key: string, end?: boolean) {
51 | if (this.level !== LoggerLevel.Timing) {
52 | return;
53 | }
54 | if (end) {
55 | this.timingLogger(`[Time End] ${key}`);
56 | console.timeEnd(key);
57 | } else {
58 | this.timingLogger(`[Time Start] ${key}`);
59 | console.time(key);
60 | }
61 | }
62 |
63 | verbose(message: string, ...args: any[]) {
64 | if (this.level === LoggerLevel.Verbose) {
65 | this.verboseLogger(message, ...args);
66 | }
67 | }
68 |
69 | stream(message: string, ...args: any[]) {
70 | if (this.level === LoggerLevel.Stream) {
71 | this.streamLogger(message, ...args);
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/packages/core/src/materials/FsMaterial.ts:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import { glob } from '@modern-js/codesmith-utils/glob';
3 | import { FsResource } from './FsResource';
4 |
5 | const promisifyGlob = (
6 | pattern: string,
7 | options: glob.IOptions,
8 | ): Promise =>
9 | new Promise((resolve, reject) => {
10 | glob(pattern, options, (err, files) =>
11 | err === null ? resolve(files) : reject(err),
12 | );
13 | });
14 |
15 | export class FsMaterial {
16 | basePath: string;
17 |
18 | constructor(basePath: string) {
19 | this.basePath = basePath;
20 | }
21 |
22 | get(resourceKey: string) {
23 | return new FsResource(
24 | path.resolve(this.basePath, resourceKey),
25 | resourceKey,
26 | );
27 | }
28 |
29 | async find(
30 | globStr: string,
31 | options?: {
32 | nodir?: boolean;
33 | dot?: boolean;
34 | ignore?: string | readonly string[];
35 | },
36 | ): Promise> {
37 | const matches = await promisifyGlob(globStr, {
38 | cwd: path.resolve(this.basePath),
39 | nodir: options?.nodir,
40 | dot: options?.dot,
41 | ignore: options?.ignore,
42 | });
43 | return matches.reduce>((pre, cur) => {
44 | pre[cur] = new FsResource(path.resolve(this.basePath, cur), cur);
45 | return pre;
46 | }, {});
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/packages/core/src/materials/FsResource.ts:
--------------------------------------------------------------------------------
1 | import type { Buffer } from 'buffer';
2 | import path from 'path';
3 | import { fs } from '@modern-js/codesmith-utils/fs-extra';
4 | import { IMAGE_EXT_LIST } from './constants';
5 |
6 | export const FS_RESOURCE = '_codesmith_core_fs_resource';
7 | export class FsResource {
8 | _type: string = FS_RESOURCE;
9 |
10 | filePath: string;
11 |
12 | resourceKey: string;
13 |
14 | constructor(filePath: string, resourceKey: string) {
15 | this.filePath = filePath;
16 | this.resourceKey = resourceKey;
17 | }
18 |
19 | async value(): Promise<{ content: string | Buffer }> {
20 | const resourceFileExt = path.extname(this.filePath);
21 | if (IMAGE_EXT_LIST.includes(resourceFileExt)) {
22 | const buffer = await fs.readFile(path.resolve(this.filePath));
23 | return { content: buffer };
24 | }
25 | const text = await fs.readFile(path.resolve(this.filePath), 'utf8');
26 | return { content: text };
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/packages/core/src/materials/constants.ts:
--------------------------------------------------------------------------------
1 | export const IMAGE_EXT_LIST = [
2 | '.jpg',
3 | '.jpeg',
4 | '.png',
5 | '.gif',
6 | '.bmp',
7 | '.ico',
8 | '.icon',
9 | '.mpt',
10 | '.psd',
11 | '.wmf',
12 | ];
13 |
--------------------------------------------------------------------------------
/packages/core/src/materials/index.ts:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import type { Logger } from '@/logger';
3 | import {
4 | downloadPackage,
5 | getGeneratorVersion,
6 | getPackageInfo,
7 | nodeRequire,
8 | } from '@/utils';
9 | import { FsMaterial } from './FsMaterial';
10 |
11 | export class MaterialsManager {
12 | logger?: Logger;
13 |
14 | registryUrl?: string;
15 |
16 | materialMap: {
17 | [materialUri: string]: FsMaterial;
18 | };
19 |
20 | readyGenerators = new Set();
21 |
22 | constructor(logger?: Logger, registryUrl?: string) {
23 | this.logger = logger;
24 | this.registryUrl = registryUrl;
25 | this.materialMap = {};
26 | }
27 |
28 | loadLocalGenerator(generator: string): Promise {
29 | if (!path.isAbsolute(generator)) {
30 | return Promise.reject(new Error('only support absolute local path'));
31 | }
32 | const fsMaterial = new FsMaterial(generator);
33 | this.materialMap[generator] = fsMaterial;
34 | return Promise.resolve(fsMaterial);
35 | }
36 |
37 | async loadRemoteGenerator(generator: string): Promise {
38 | const { name, version } = getPackageInfo(generator);
39 | const localPath = await downloadPackage(name, version, {
40 | registryUrl: this.registryUrl,
41 | install: true,
42 | logger: this.logger,
43 | });
44 | const pkgJson = nodeRequire(`${localPath}/package.json`);
45 | const materialKey = `${pkgJson.name}@${pkgJson.version}`;
46 | this.materialMap[materialKey] = new FsMaterial(localPath);
47 | return Promise.resolve(this.materialMap[materialKey]);
48 | }
49 |
50 | async prepareGenerators(generators: string[]) {
51 | this.logger?.timing?.('🕒 Prepare Generators');
52 | await Promise.all(
53 | generators.map(async generator => {
54 | if (this.readyGenerators.has(generator)) {
55 | return Promise.resolve();
56 | }
57 | const { name, version: pkgVersion } = getPackageInfo(generator);
58 | const version = await getGeneratorVersion(name, pkgVersion, {
59 | registryUrl: this.registryUrl,
60 | logger: this.logger,
61 | });
62 | const materialKey = `${name}@${version}`;
63 | if (this.materialMap[materialKey] || generator.startsWith('file:')) {
64 | return Promise.resolve();
65 | }
66 | await this.loadRemoteGenerator(materialKey);
67 | this.readyGenerators.add(generator);
68 | }),
69 | );
70 | this.logger?.timing?.('🕒 Prepare Generators', true);
71 | }
72 |
73 | async prepareGlobal() {
74 | this.logger?.timing?.('🕒 Prepare Global');
75 | const globalPkgName = '@modern-js/codesmith-global';
76 | const globalResource = await this.loadRemoteGenerator(
77 | `${globalPkgName}@latest`,
78 | );
79 | require(globalResource.basePath);
80 | this.logger?.timing?.('🕒 Prepare Global', true);
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/packages/core/src/utils/fsExists.ts:
--------------------------------------------------------------------------------
1 | import { fs } from '@modern-js/codesmith-utils/fs-extra';
2 |
3 | /**
4 | * when the path can read successfully, the function will return true
5 | * @param {string} path
6 | * @returns {boolean}
7 | */
8 | export async function fsExists(path: string) {
9 | try {
10 | await fs.access(path);
11 | return true;
12 | } catch (e: unknown) {
13 | return false;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/packages/core/src/utils/getGeneratorDir.ts:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import { fs } from '@modern-js/codesmith-utils/fs-extra';
3 | import { fsExists } from './fsExists';
4 |
5 | const MaxTimes = 5;
6 |
7 | export async function getGeneratorDir(generator: string) {
8 | let result = generator;
9 | const isDirectory = (await fs.stat(generator)).isDirectory();
10 |
11 | if (!isDirectory) {
12 | result = path.dirname(generator);
13 | }
14 |
15 | let times = 0;
16 |
17 | while (
18 | times < MaxTimes &&
19 | !(await fsExists(path.join(result, 'package.json')))
20 | ) {
21 | result = path.join(result, '../');
22 | times++;
23 | }
24 |
25 | if (times >= MaxTimes) {
26 | throw Error('generator is not valid');
27 | }
28 |
29 | return result;
30 | }
31 |
--------------------------------------------------------------------------------
/packages/core/src/utils/getNpmPackageInfo.ts:
--------------------------------------------------------------------------------
1 | import { NPM_API_TIMEOUT } from '@/constants';
2 | import { execa } from '@modern-js/codesmith-utils/execa';
3 | import axios from 'axios';
4 | import type { ILogger } from '../logger/constants';
5 | import { getNpmRegistry } from './getNpmRegistry';
6 | import { timeoutPromise } from './timeoutPromise';
7 |
8 | interface Options {
9 | registryUrl?: string;
10 | logger?: ILogger;
11 | }
12 |
13 | interface PackageInfo {
14 | version: string;
15 | dist: {
16 | tarball: string;
17 | };
18 | }
19 |
20 | const NpmPackageInfoCache = new Map();
21 |
22 | async function getNpmPackageInfoWithCommand(
23 | pkgName: string,
24 | pkgVersion: string,
25 | options?: Options,
26 | ): Promise {
27 | const { registryUrl } = options || {};
28 | const params = [
29 | 'view',
30 | `${pkgName}@${pkgVersion}`,
31 | 'dist',
32 | 'version',
33 | '--json',
34 | ];
35 |
36 | if (registryUrl) {
37 | params.push('--registry');
38 | params.push(registryUrl);
39 | }
40 |
41 | const getPkgInfoPromise = execa('npm', params);
42 | const { stdout } = await timeoutPromise(
43 | getPkgInfoPromise,
44 | NPM_API_TIMEOUT,
45 | `Get npm tarball of '${pkgName}'`,
46 | );
47 |
48 | try {
49 | const pkgDistInfo = JSON.parse(stdout);
50 | return pkgDistInfo;
51 | } catch (e) {
52 | throw new Error(
53 | `Version \`${pkgVersion}\` for package \`${pkgName}\` could not be found`,
54 | );
55 | }
56 | }
57 |
58 | export async function getNpmPackageInfo(
59 | pkgName: string,
60 | pkgVersion: string,
61 | options?: Options,
62 | ): Promise {
63 | const packageName = `${pkgName}@${pkgVersion}`;
64 | const packageInfo = NpmPackageInfoCache.get(packageName);
65 | if (packageInfo) {
66 | return packageInfo;
67 | }
68 | const { registryUrl = await getNpmRegistry(), logger } = options || {};
69 |
70 | const url = `${registryUrl.replace(/\/$/, '')}/${pkgName}/${pkgVersion || 'latest'}`;
71 |
72 | let response: PackageInfo;
73 | try {
74 | response = (
75 | await timeoutPromise(
76 | axios.get(url),
77 | NPM_API_TIMEOUT,
78 | `Get npm package info of '${pkgName}'`,
79 | )
80 | ).data;
81 | // some registry not return version field, use command to compat
82 | if (!response.version) {
83 | response = await getNpmPackageInfoWithCommand(
84 | pkgName,
85 | pkgVersion,
86 | options,
87 | );
88 | }
89 | } catch (e) {
90 | logger?.error(e);
91 | response = await getNpmPackageInfoWithCommand(pkgName, pkgVersion, options);
92 | }
93 |
94 | const { version } = response;
95 |
96 | NpmPackageInfoCache.set(`${pkgName}@${version || pkgVersion}`, response);
97 |
98 | return response;
99 | }
100 |
--------------------------------------------------------------------------------
/packages/core/src/utils/getNpmRegistry.ts:
--------------------------------------------------------------------------------
1 | import { execa } from '@modern-js/codesmith-utils/execa';
2 |
3 | export async function getNpmRegistry() {
4 | try {
5 | const { stdout } = await execa('npm', [
6 | 'config',
7 | 'get',
8 | 'registry',
9 | '--no-workspaces',
10 | ]);
11 | return stdout.replace(/\/$/, '') || 'https://registry.npmjs.org';
12 | } catch (error) {
13 | // If getting registry fails, return default npm registry
14 | return 'https://registry.npmjs.org';
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/core/src/utils/getNpmTarballUrl.ts:
--------------------------------------------------------------------------------
1 | import type { ILogger } from '../logger/constants';
2 | import { getNpmPackageInfo } from './getNpmPackageInfo';
3 |
4 | interface Options {
5 | registryUrl?: string;
6 | logger?: ILogger;
7 | }
8 |
9 | export async function getNpmTarballUrl(
10 | pkgName: string,
11 | pkgVersion: string,
12 | options?: Options,
13 | ): Promise {
14 | const packageInfo = await getNpmPackageInfo(pkgName, pkgVersion, options);
15 |
16 | return packageInfo.dist.tarball;
17 | }
18 |
--------------------------------------------------------------------------------
/packages/core/src/utils/getNpmVersion.ts:
--------------------------------------------------------------------------------
1 | import type { ILogger } from '../logger/constants';
2 | import { getNpmPackageInfo } from './getNpmPackageInfo';
3 | /**
4 | * get package version
5 | * @param {string} packageName
6 | * @param {Options} options
7 | * @returns {string}
8 | */
9 |
10 | interface Options {
11 | registryUrl?: string;
12 | version?: string;
13 | logger?: ILogger;
14 | }
15 |
16 | export async function getNpmVersion(
17 | packageName: string,
18 | options?: Options,
19 | ): Promise {
20 | const { version = 'latest' } = options || {};
21 | const packageInfo = await getNpmPackageInfo(packageName, version, options);
22 |
23 | return packageInfo.version;
24 | }
25 |
--------------------------------------------------------------------------------
/packages/core/src/utils/getPackageInfo.ts:
--------------------------------------------------------------------------------
1 | import { semver } from '@modern-js/codesmith-utils/semver';
2 |
3 | /**
4 | * get package name and package version from package name string
5 | * @param {string} packageName
6 | * @returns {name: string, version: string}
7 | */
8 | export function getPackageInfo(packageName: string) {
9 | if (!packageName) {
10 | throw new Error('package is not exisit');
11 | }
12 | const splitAt = packageName.split('@');
13 | let pkgVersion = 'latest';
14 | let pkgName = packageName;
15 | if (
16 | (!packageName.startsWith('@') && splitAt.length === 2) ||
17 | (packageName.startsWith('@') && splitAt.length === 3)
18 | ) {
19 | const semverValid = semver.valid(splitAt[splitAt.length - 1]);
20 | if (semverValid === null) {
21 | pkgVersion = splitAt[splitAt.length - 1];
22 | pkgName = packageName.slice(0, packageName.lastIndexOf('@'));
23 | } else {
24 | pkgVersion = semverValid;
25 | pkgName = packageName.split(semverValid)[0].slice(0, -1);
26 | }
27 | }
28 | return {
29 | name: pkgName,
30 | version: pkgVersion,
31 | };
32 | }
33 |
--------------------------------------------------------------------------------
/packages/core/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | export { fsExists } from './fsExists';
2 | export { nodeRequire } from './nodeRequire';
3 | export { canUsePnpm, canUseYarn, runInstall } from './packageManager';
4 | export { timeoutPromise } from './timeoutPromise';
5 | export { downloadPackage, getGeneratorVersion } from './downloadPackage';
6 | export { getNpmVersion } from './getNpmVersion';
7 | export { getPackageInfo } from './getPackageInfo';
8 | export { getNpmRegistry } from './getNpmRegistry';
9 | export { getNpmPackageInfo } from './getNpmPackageInfo';
10 |
--------------------------------------------------------------------------------
/packages/core/src/utils/nodeRequire.ts:
--------------------------------------------------------------------------------
1 | declare function __non_webpack_require__(path: string): any;
2 |
3 | /**
4 | * requier function support webpack require
5 | * @param {string} path
6 | * @returns {unknown}
7 | */
8 | export const nodeRequire = (path: string) => {
9 | try {
10 | const module = __non_webpack_require__(path);
11 | if (module?.default) {
12 | return module.default;
13 | }
14 | return module;
15 | } catch (error) {
16 | const module = require(path);
17 | if (module?.default) {
18 | return module.default;
19 | }
20 | return module;
21 | }
22 | };
23 |
--------------------------------------------------------------------------------
/packages/core/src/utils/packageManager.ts:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import type { Logger } from '@/logger';
3 | import { execa } from '@modern-js/codesmith-utils/execa';
4 | import { fs } from '@modern-js/codesmith-utils/fs-extra';
5 |
6 | export async function canUseYarn() {
7 | try {
8 | await execa('yarn', ['--version'], {
9 | env: process.env,
10 | });
11 | return true;
12 | } catch (e) {
13 | return false;
14 | }
15 | }
16 |
17 | export async function canUsePnpm() {
18 | try {
19 | await execa('pnpm', ['--version'], {
20 | env: process.env,
21 | });
22 | return true;
23 | } catch (e) {
24 | return false;
25 | }
26 | }
27 |
28 | export async function runInstall(
29 | targetDir: string,
30 | registryUrl?: string,
31 | logger?: Logger,
32 | ) {
33 | const options = {
34 | cwd: targetDir,
35 | env: process.env,
36 | };
37 | // delete devDependencies
38 | try {
39 | const pkgPath = path.join(targetDir, 'package.json');
40 | const pkgJSON = JSON.parse(fs.readFileSync(pkgPath, { encoding: 'utf-8' }));
41 | pkgJSON.devDependencies = undefined;
42 | fs.writeFileSync(pkgPath, JSON.stringify(pkgJSON, null, 2), {
43 | encoding: 'utf-8',
44 | });
45 | } catch (e) {
46 | /**
47 | * no handle
48 | */
49 | }
50 |
51 | const showLog = logger?.level === 'debug';
52 |
53 | if (await canUsePnpm()) {
54 | const params = [
55 | 'install',
56 | '--prod',
57 | showLog ? null : '--reporter=silent', // if debug mode, console install log
58 | '--ignore-scripts',
59 | ].filter(Boolean) as string[];
60 | if (registryUrl) {
61 | params.push(`--registry=${registryUrl}`);
62 | }
63 | await execa('pnpm', params, options);
64 | } else if (await canUseYarn()) {
65 | const params = [
66 | 'install',
67 | '--production',
68 | showLog ? null : '--silent',
69 | '--ignore-scripts',
70 | ].filter(Boolean) as string[];
71 | if (registryUrl) {
72 | params.push(`--registry=${registryUrl}`);
73 | }
74 | await execa('yarn', params, options);
75 | } else {
76 | const params = [
77 | 'install',
78 | '--production',
79 | '--loglevel=error',
80 | '--ignore-scripts',
81 | ];
82 | if (registryUrl) {
83 | params.push(`--registry=${registryUrl}`);
84 | }
85 | await execa('npm', params, options);
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/packages/core/src/utils/timeoutPromise.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * when promise is timeput, reject promise
3 | * @param {Promise} promise
4 | * @param {number} ms
5 | * @param {string} reason
6 | * @returns {Promise}
7 | */
8 | export async function timeoutPromise(
9 | promise: Promise,
10 | ms: number,
11 | reason = 'Operation',
12 | ) {
13 | let timeoutId: NodeJS.Timeout | null = null;
14 | const delayPromise = (ms: number) =>
15 | new Promise(resolve => {
16 | timeoutId = setTimeout(resolve, ms);
17 | });
18 | const timeout = delayPromise(ms).then(() => {
19 | throw new Error(`${reason} timed out after ${ms}ms`);
20 | });
21 | try {
22 | const result = await Promise.race([promise, timeout]);
23 | return result;
24 | } finally {
25 | if (timeoutId) {
26 | clearTimeout(timeoutId);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/packages/core/tests/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@modern-js/tsconfig/base",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "jsx": "preserve",
6 | "baseUrl": "./",
7 | "isolatedModules": true,
8 | "paths": {
9 | "@/*": ["../src/*"]
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/packages/core/tests/utils/downloadPackage.test.ts:
--------------------------------------------------------------------------------
1 | import os from 'os';
2 | import path from 'path';
3 | import { downloadPackage } from '@/utils';
4 | import { fs } from '@modern-js/codesmith-utils/fs-extra';
5 |
6 | jest.setTimeout(100000);
7 |
8 | describe('downloadPackage function test', () => {
9 | beforeEach(() => {
10 | fs.removeSync(path.join(os.tmpdir(), 'csmith-generator'));
11 | });
12 | it.skip('download lodash package', async () => {
13 | const packageDir = await downloadPackage('lodash');
14 | expect(packageDir).toContain('csmith-generator/lodash');
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/packages/core/tests/utils/fsExists.test.ts:
--------------------------------------------------------------------------------
1 | import os from 'os';
2 | import path from 'path';
3 | import { fsExists } from '@/utils';
4 | import { fs } from '@modern-js/codesmith-utils/fs-extra';
5 |
6 | describe('fsExists function test', () => {
7 | beforeEach(() => {
8 | const tmpDir = os.tmpdir();
9 | fs.removeSync(path.join(tmpDir, '_codesmith_test'));
10 | });
11 |
12 | it('file exists', async () => {
13 | const tmpDir = os.tmpdir();
14 | const fileName = 'tmp.txt';
15 | const filePath = path.join(tmpDir, '_codesmith_test', fileName);
16 | await fs.createFile(filePath);
17 | const exists = await fsExists(filePath);
18 | expect(exists).toBe(true);
19 | });
20 | it('file not exists', async () => {
21 | const tmpDir = os.tmpdir();
22 | const fileName = 'tmp_not_exit.txt';
23 | const filePath = path.join(tmpDir, '_codesmith_test', fileName);
24 | const exists = await fsExists(filePath);
25 | expect(exists).toBe(false);
26 | });
27 | afterAll(() => {
28 | const tmpDir = os.tmpdir();
29 | const dirPath = path.join(tmpDir, '_codesmith_test');
30 | fs.remove(dirPath);
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/packages/core/tests/utils/getGeneratorDir.test.ts:
--------------------------------------------------------------------------------
1 | import * as os from 'os';
2 | import * as path from 'path';
3 | import { fsExists } from '@/utils';
4 | import { getGeneratorDir } from '@/utils/getGeneratorDir';
5 | import { fs } from '@modern-js/codesmith-utils/fs-extra';
6 |
7 | describe('getGeneratorDir function test', () => {
8 | it('normal', async () => {
9 | const tmpDir = path.join(os.tmpdir(), '__codesmith__test', 'generatorDir');
10 | const generarorPath = path.join(tmpDir, 'path1', 'path2');
11 | const file = path.join(tmpDir, 'package.json');
12 | if (await fsExists(tmpDir)) {
13 | fs.removeSync(tmpDir);
14 | }
15 | fs.mkdirpSync(generarorPath);
16 | fs.writeFile(file, '{}', 'utf-8');
17 | const generarorDir = await getGeneratorDir(generarorPath);
18 | const lastChar = generarorDir[generarorDir.length - 1];
19 | expect(
20 | lastChar === path.sep ? generarorDir.slice(0, -1) : generarorDir,
21 | ).toBe(tmpDir);
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/packages/core/tests/utils/getNpmVersion.test.ts:
--------------------------------------------------------------------------------
1 | import { getNpmVersion } from '@/utils';
2 |
3 | describe.skip('getNpmVersion function test', () => {
4 | it('package exists', async () => {
5 | const version = await getNpmVersion('lodash');
6 | expect(typeof version).toBe('string');
7 | });
8 | it('package not exists', async () => {
9 | try {
10 | await getNpmVersion('lodash_xx');
11 | } catch (e: any) {
12 | expect(e.message).toContain(`lodash_xx@latest' is not in this registry`);
13 | }
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/packages/core/tests/utils/getNpmtarballUrl.test.ts:
--------------------------------------------------------------------------------
1 | import { getNpmTarballUrl } from '@/utils';
2 |
3 | describe.skip('getNpmTarballUrl function test', () => {
4 | it('package exists', async () => {
5 | const tarball = await getNpmTarballUrl('lodash', '4.17.21');
6 | expect(tarball).toContain('lodash-4.17.21.tgz');
7 | });
8 | it('package not exists', async () => {
9 | try {
10 | await getNpmTarballUrl('lodash', '4.1.2');
11 | } catch (e: any) {
12 | expect(e.message).toContain(
13 | 'Version `4.1.2` for package `lodash` could not be found',
14 | );
15 | }
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/packages/core/tests/utils/getPackageInfo.test.ts:
--------------------------------------------------------------------------------
1 | import { getPackageInfo } from '@/utils';
2 |
3 | describe('getPackageInfo function test', () => {
4 | it('package not start with @', async () => {
5 | const packageInfo = await getPackageInfo('lodash@4.17.2');
6 | expect(packageInfo).toEqual({
7 | name: 'lodash',
8 | version: '4.17.2',
9 | });
10 | });
11 | it('package start with @', async () => {
12 | const packageInfo = await getPackageInfo('@babel/runtime@^7.14.8');
13 | expect(packageInfo).toEqual({
14 | name: '@babel/runtime',
15 | version: '^7.14.8',
16 | });
17 | });
18 | it('package start with @, but not contains version', async () => {
19 | const packageInfo = await getPackageInfo('@babel/runtime');
20 | expect(packageInfo).toEqual({
21 | name: '@babel/runtime',
22 | version: 'latest',
23 | });
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/packages/core/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@modern-js/tsconfig/base",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "jsx": "preserve",
6 | "baseUrl": "./",
7 | "isolatedModules": true,
8 | "paths": {
9 | "@/*": ["./src/*"]
10 | }
11 | },
12 | "include": ["src"]
13 | }
14 |
--------------------------------------------------------------------------------
/packages/formily/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | .pnp
4 | .pnp.js
5 | .env.*.local
6 | .history
7 | .rts*
8 | *.log*
9 | *.pid
10 | *.pid.*
11 | *.report
12 | *.lcov
13 | lib-cov
14 |
15 | node_modules/
16 | .npm
17 | .lock-wscript
18 | .yarn-integrity
19 | .node_repl_history
20 | .nyc_output
21 | *.tsbuildinfo
22 | .eslintcache
23 | .sonarlint
24 |
25 | coverage/
26 | release/
27 | output/
28 | output_resource/
29 |
30 | .vscode/**/*
31 | !.vscode/settings.json
32 | !.vscode/extensions.json
33 | .idea/
34 |
35 | **/*/api/typings/auto-generated
36 | **/*/adapters/**/index.ts
37 | **/*/adapters/**/index.js
38 |
39 | src/
40 |
41 | modern.config.*
42 | tsconfig.json
43 | CHANGELOG.md
44 |
--------------------------------------------------------------------------------
/packages/formily/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Modern.js
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/formily/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Modern.js
6 |
7 |
8 | A Progressive React Framework for modern web development.
9 |
10 |
11 | ## Getting Started
12 |
13 | Please follow [Quick Start](https://modernjs.dev/en/guides/get-started/quick-start) to get started with Modern.js.
14 |
15 | ## Documentation
16 |
17 | - [English Documentation](https://modernjs.dev/en/)
18 | - [中文文档](https://modernjs.dev)
19 |
20 | ## Contributing
21 |
22 | Please read the [Contributing Guide](https://github.com/web-infra-dev/modern.js/blob/main/CONTRIBUTING.md).
23 |
24 | ## License
25 |
26 | Modern.js is [MIT licensed](https://github.com/web-infra-dev/modern.js/blob/main/LICENSE).
27 |
--------------------------------------------------------------------------------
/packages/formily/modern.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig, moduleTools } from '@modern-js/module-tools';
2 |
3 | import { testingPlugin } from '@modern-js/plugin-testing';
4 |
5 | export default defineConfig({
6 | buildPreset: 'modern-js-universal',
7 | plugins: [moduleTools(), testingPlugin()],
8 | });
9 |
--------------------------------------------------------------------------------
/packages/formily/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@modern-js/codesmith-formily",
3 | "description": "codesmith support formly schema to inquirer question",
4 | "homepage": "https://modernjs.dev",
5 | "bugs": "https://github.com/web-infra-dev/codesmith/issues",
6 | "repository": "web-infra-dev/codesmith",
7 | "license": "MIT",
8 | "keywords": [
9 | "react",
10 | "framework",
11 | "modern",
12 | "modern.js"
13 | ],
14 | "version": "2.6.8",
15 | "jsnext:source": "./src/index.ts",
16 | "types": "./dist/types/index.d.ts",
17 | "main": "./dist/cjs/index.js",
18 | "module": "./dist/esm-node/index.js",
19 | "publishConfig": {
20 | "registry": "https://registry.npmjs.org/",
21 | "access": "public"
22 | },
23 | "scripts": {
24 | "prepare": "pnpm build",
25 | "prepublishOnly": "pnpm build --platform",
26 | "new": "modern new",
27 | "build": "modern build",
28 | "test": "modern test"
29 | },
30 | "dependencies": {
31 | "@swc/helpers": "0.5.1",
32 | "@formily/json-schema": "^2.2.24",
33 | "@formily/validator": "^2.2.24",
34 | "@modern-js/codesmith-utils": "workspace:*",
35 | "inquirer": "^8.2.5"
36 | },
37 | "peerDependencies": {
38 | "@modern-js/codesmith": "workspace:^2.6.8"
39 | },
40 | "devDependencies": {
41 | "@modern-js/codesmith": "workspace:*",
42 | "@modern-js/module-tools": "2.60.3",
43 | "@modern-js/plugin-testing": "2.60.3",
44 | "@types/inquirer": "^7.3.3",
45 | "@types/jest": "^26.0.24",
46 | "@types/node": "^14.18.42",
47 | "typescript": "^4.9.5"
48 | },
49 | "sideEffects": false
50 | }
51 |
--------------------------------------------------------------------------------
/packages/formily/src/index.ts:
--------------------------------------------------------------------------------
1 | import type { GeneratorContext } from '@modern-js/codesmith';
2 | import { merge } from '@modern-js/codesmith-utils/lodash';
3 | import { CLIReader } from './inquirer';
4 | import type { Schema } from './transform';
5 |
6 | export * from './inquirer';
7 | export type { Schema } from './transform';
8 | export type { SchemaEnum } from '@formily/json-schema';
9 | export { validate } from '@formily/validator';
10 |
11 | export class FormilyAPI {
12 | protected readonly generatorContext: GeneratorContext;
13 |
14 | constructor(generatorContext: GeneratorContext) {
15 | this.generatorContext = generatorContext;
16 | }
17 |
18 | private mergeAnswers(
19 | answers: Record,
20 | configValue: Record,
21 | ) {
22 | const inputData = merge(answers, configValue);
23 | this.generatorContext.config = merge(
24 | this.generatorContext.config,
25 | inputData,
26 | );
27 | return inputData;
28 | }
29 |
30 | public async getInputBySchemaFunc(
31 | schemaFunc: (config?: Record) => Schema,
32 | configValue: Record = {},
33 | validateMap: Record<
34 | string,
35 | (
36 | input: unknown,
37 | data?: Record,
38 | ) => { success: boolean; error?: string }
39 | > = {},
40 | initValue: Record = {},
41 | ) {
42 | const reader = new CLIReader({
43 | schema: schemaFunc(configValue),
44 | validateMap,
45 | initValue,
46 | });
47 | reader.setAnswers(configValue);
48 | const answers = await reader.start();
49 | return this.mergeAnswers(answers, configValue);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/packages/formily/src/inquirer.ts:
--------------------------------------------------------------------------------
1 | import { prompt } from './prompt';
2 | import type { Schema } from './transform';
3 |
4 | export interface ICLIReaderOptions {
5 | schema: Schema;
6 | validateMap?: Record<
7 | string,
8 | (
9 | input: unknown,
10 | data?: Record,
11 | ) => { success: boolean; error?: string }
12 | >;
13 | initValue?: Record;
14 | }
15 | export class CLIReader<
16 | T extends Record = Record,
17 | > {
18 | schema: Schema | null = null;
19 |
20 | validateMap: Record<
21 | string,
22 | (
23 | input: unknown,
24 | data?: Record,
25 | ) => { success: boolean; error?: string }
26 | >;
27 |
28 | initValue: Record;
29 |
30 | answers: Record = {};
31 |
32 | constructor(options: ICLIReaderOptions) {
33 | const { schema, validateMap, initValue } = options;
34 | this.schema = schema;
35 | this.validateMap = validateMap || {};
36 | this.initValue = initValue || {};
37 | }
38 |
39 | getAnswers() {
40 | return this.answers as T;
41 | }
42 |
43 | setAnswers(answers: Partial) {
44 | this.answers = { ...this.answers, ...answers };
45 | }
46 |
47 | async start() {
48 | if (!this.schema) {
49 | throw Error('schema is not valid');
50 | }
51 | const answers = await prompt(
52 | this.schema,
53 | this.answers,
54 | this.validateMap,
55 | this.initValue,
56 | );
57 | this.setAnswers(answers);
58 | return answers;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/packages/formily/tests/prompt.test.ts:
--------------------------------------------------------------------------------
1 | import { prompt } from '../src/prompt';
2 | import type { Schema } from '../src/transform';
3 |
4 | describe('prompt test', () => {
5 | it('has config value', async () => {
6 | const schema: Schema = {
7 | type: 'object',
8 | properties: {
9 | language: {
10 | type: 'string',
11 | title: '开发语言',
12 | default: 'ts',
13 | },
14 | },
15 | };
16 | const ans = await prompt(schema, { language: 'ts' }, {}, {});
17 | expect(ans).toEqual({ language: 'ts' });
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/packages/formily/tests/transform.test.ts:
--------------------------------------------------------------------------------
1 | import { type Question, type Schema, transformForm } from '../src/transform';
2 |
3 | function removeValidate(questions: Question[]) {
4 | return questions.map(question => {
5 | const { validate, ...extra } = question as any;
6 | return extra;
7 | });
8 | }
9 | describe('transform form', () => {
10 | it('input', () => {
11 | const schema: Schema = {
12 | type: 'object',
13 | properties: {
14 | language: {
15 | type: 'string',
16 | title: '开发语言',
17 | default: 'ts',
18 | },
19 | },
20 | };
21 | const questions = transformForm(schema, {}, {}, {});
22 | expect(removeValidate(questions)).toEqual([
23 | {
24 | type: 'input',
25 | name: 'language',
26 | message: '开发语言',
27 | default: 'ts',
28 | origin: {},
29 | when: true,
30 | },
31 | ]);
32 | });
33 | it('select', () => {
34 | const schema: Schema = {
35 | type: 'object',
36 | properties: {
37 | language: {
38 | type: 'string',
39 | title: '开发语言',
40 | default: 'ts',
41 | enum: [
42 | { label: 'TS', value: 'ts' },
43 | { label: 'ES6+', value: 'js' },
44 | ],
45 | },
46 | },
47 | };
48 | const questions = transformForm(schema, {}, {}, {});
49 |
50 | expect(removeValidate(questions)).toEqual([
51 | {
52 | type: 'list',
53 | name: 'language',
54 | message: '开发语言',
55 | default: 'ts',
56 | when: true,
57 | choices: [
58 | {
59 | type: 'choice',
60 | name: 'TS',
61 | value: 'ts',
62 | },
63 | {
64 | type: 'choice',
65 | name: 'ES6+',
66 | value: 'js',
67 | },
68 | ],
69 | origin: {},
70 | },
71 | ]);
72 | });
73 | });
74 |
--------------------------------------------------------------------------------
/packages/formily/tests/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@modern-js/tsconfig/base",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "jsx": "preserve",
6 | "baseUrl": "./",
7 | "isolatedModules": true,
8 | "paths": {
9 | "@/*": ["../src/*"]
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/packages/formily/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@modern-js/tsconfig/base",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "jsx": "preserve",
6 | "baseUrl": "./",
7 | "isolatedModules": true,
8 | "paths": {
9 | "@/*": ["./src/*"]
10 | }
11 | },
12 | "include": ["src"]
13 | }
14 |
--------------------------------------------------------------------------------
/packages/global/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | .pnp
4 | .pnp.js
5 | .env.*.local
6 | .history
7 | .rts*
8 | *.log*
9 | *.pid
10 | *.pid.*
11 | *.report
12 | *.lcov
13 | lib-cov
14 |
15 | node_modules/
16 | .npm
17 | .lock-wscript
18 | .yarn-integrity
19 | .node_repl_history
20 | .nyc_output
21 | *.tsbuildinfo
22 | .eslintcache
23 | .sonarlint
24 |
25 | coverage/
26 | release/
27 | output/
28 | output_resource/
29 |
30 | .vscode/**/*
31 | !.vscode/settings.json
32 | !.vscode/extensions.json
33 | .idea/
34 |
35 | **/*/api/typings/auto-generated
36 | **/*/adapters/**/index.ts
37 | **/*/adapters/**/index.js
38 |
39 | src/
40 | modern.config.*
41 | tsconfig.json
42 | CHANGELOG.md
43 |
--------------------------------------------------------------------------------
/packages/global/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # @modern-js/codesmith-global
2 |
3 | ## 2.6.8
4 |
5 | ## 2.6.7
6 |
7 | ## 2.6.6
8 |
9 | ## 2.6.5
10 |
11 | ## 2.6.4
12 |
13 | ## 2.6.3
14 |
15 | ## 2.6.2
16 |
17 | ## 2.6.1
18 |
19 | ## 2.6.0
20 |
--------------------------------------------------------------------------------
/packages/global/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Modern.js
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/global/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Modern.js
6 |
7 |
8 | A Progressive React Framework for modern web development.
9 |
10 |
11 | ## Getting Started
12 |
13 | Please follow [Quick Start](https://modernjs.dev/en/guides/get-started/quick-start) to get started with Modern.js.
14 |
15 | ## Documentation
16 |
17 | - [English Documentation](https://modernjs.dev/en/)
18 | - [中文文档](https://modernjs.dev)
19 |
20 | ## Contributing
21 |
22 | Please read the [Contributing Guide](https://github.com/web-infra-dev/modern.js/blob/main/CONTRIBUTING.md).
23 |
24 | ## License
25 |
26 | Modern.js is [MIT licensed](https://github.com/web-infra-dev/modern.js/blob/main/LICENSE).
27 |
--------------------------------------------------------------------------------
/packages/global/modern.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig, moduleTools } from '@modern-js/module-tools';
2 |
3 | export default defineConfig({
4 | buildConfig: {
5 | target: 'es2020',
6 | dts: false,
7 | format: 'umd',
8 | autoExternal: false,
9 | alias: {
10 | '@modern-js/utils/lodash': require.resolve(
11 | '@modern-js/codesmith-utils/lodash',
12 | ),
13 | },
14 | minify: 'terser',
15 | },
16 | plugins: [moduleTools()],
17 | });
18 |
--------------------------------------------------------------------------------
/packages/global/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@modern-js/codesmith-global",
3 | "description": "codesmith core implement",
4 | "homepage": "https://modernjs.dev",
5 | "bugs": "https://github.com/web-infra-dev/codesmith/issues",
6 | "repository": "web-infra-dev/codesmith",
7 | "license": "MIT",
8 | "keywords": [
9 | "react",
10 | "framework",
11 | "modern",
12 | "modern.js"
13 | ],
14 | "version": "2.6.8",
15 | "jsnext:source": "./src/index.ts",
16 | "main": "./dist/index.js",
17 | "publishConfig": {
18 | "registry": "https://registry.npmjs.org/",
19 | "access": "public"
20 | },
21 | "scripts": {
22 | "prepare": "pnpm build",
23 | "prepublishOnly": "pnpm build -- --platform",
24 | "new": "modern new",
25 | "build": "modern build",
26 | "test": "echo 'No tests'"
27 | },
28 | "devDependencies": {
29 | "@modern-js/codesmith": "workspace:*",
30 | "@modern-js/codesmith-api-app": "workspace:*",
31 | "@modern-js/codesmith-api-git": "workspace:*",
32 | "@modern-js/codesmith-api-npm": "workspace:*",
33 | "@modern-js/codesmith-api-ejs": "workspace:*",
34 | "@modern-js/codesmith-api-fs": "workspace:*",
35 | "@modern-js/codesmith-api-handlebars": "workspace:*",
36 | "@modern-js/codesmith-api-json": "workspace:*",
37 | "@modern-js/codesmith-formily": "workspace:*",
38 | "@modern-js/codesmith-utils": "workspace:*",
39 | "@modern-js/plugin-i18n": "2.60.3",
40 | "@modern-js/module-tools": "2.60.3",
41 | "@types/node": "^14",
42 | "typescript": "^5"
43 | },
44 | "sideEffects": false
45 | }
46 |
--------------------------------------------------------------------------------
/packages/global/src/index.ts:
--------------------------------------------------------------------------------
1 | import * as codesmith from '@modern-js/codesmith';
2 | import * as codesmithApiApp from '@modern-js/codesmith-api-app';
3 | import * as codesmithApiEjs from '@modern-js/codesmith-api-ejs';
4 | import * as codesmithApiFs from '@modern-js/codesmith-api-fs';
5 | import * as codesmithApiGit from '@modern-js/codesmith-api-git';
6 | import * as codesmithApiHandlebars from '@modern-js/codesmith-api-handlebars';
7 | import * as codesmithApiJson from '@modern-js/codesmith-api-json';
8 | import * as codesmithApiNpm from '@modern-js/codesmith-api-npm';
9 | import * as codesmithFormily from '@modern-js/codesmith-formily';
10 | import * as codesmithUtils from '@modern-js/codesmith-utils';
11 | import * as codesmithChalkUtils from '@modern-js/codesmith-utils/chalk';
12 | import * as codesmithExecaUtils from '@modern-js/codesmith-utils/execa';
13 | import * as codesmithFsUtils from '@modern-js/codesmith-utils/fs-extra';
14 | import * as codesmithGlobUtils from '@modern-js/codesmith-utils/glob';
15 | import * as codesmithLodashUtils from '@modern-js/codesmith-utils/lodash';
16 | import * as codesmithNpmUtils from '@modern-js/codesmith-utils/npm';
17 | import * as codesmithOraUtils from '@modern-js/codesmith-utils/ora';
18 | import * as codesmithSemverUtils from '@modern-js/codesmith-utils/semver';
19 | import * as pluginI18N from '@modern-js/plugin-i18n';
20 |
21 | (global as any).codesmith = codesmith;
22 | (global as any).codesmithApiApp = codesmithApiApp;
23 | (global as any).codesmithApiJson = codesmithApiJson;
24 | (global as any).codesmithApiGit = codesmithApiGit;
25 | (global as any).codesmithUtils = codesmithUtils;
26 | (global as any).codesmithGlobUtils = codesmithGlobUtils;
27 | (global as any).codesmithLodashUtils = codesmithLodashUtils;
28 | (global as any).codesmithFsUtils = codesmithFsUtils;
29 | (global as any).codesmithChalkUtils = codesmithChalkUtils;
30 | (global as any).codesmithExecaUtils = codesmithExecaUtils;
31 | (global as any).codesmithNpmUtils = codesmithNpmUtils;
32 | (global as any).codesmithOraUtils = codesmithOraUtils;
33 | (global as any).codesmithSemverUtils = codesmithSemverUtils;
34 | (global as any).codesmithFormily = codesmithFormily;
35 | (global as any).codesmithApiNpm = codesmithApiNpm;
36 | (global as any).codesmithApiEjs = codesmithApiEjs;
37 | (global as any).codesmithApiFs = codesmithApiFs;
38 | (global as any).codesmithApiHandlebars = codesmithApiHandlebars;
39 | (global as any).pluginI18N = pluginI18N;
40 |
--------------------------------------------------------------------------------
/packages/global/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@modern-js/tsconfig/base",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "jsx": "preserve",
6 | "baseUrl": "./",
7 | "isolatedModules": true,
8 | "paths": {
9 | "@/*": ["./src/*"]
10 | }
11 | },
12 | "include": ["src"]
13 | }
14 |
--------------------------------------------------------------------------------
/packages/inquirer/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | .pnp
4 | .pnp.js
5 | .env.*.local
6 | .history
7 | .rts*
8 | *.log*
9 | *.pid
10 | *.pid.*
11 | *.report
12 | *.lcov
13 | lib-cov
14 |
15 | node_modules/
16 | .npm
17 | .lock-wscript
18 | .yarn-integrity
19 | .node_repl_history
20 | .nyc_output
21 | *.tsbuildinfo
22 | .eslintcache
23 | .sonarlint
24 |
25 | coverage/
26 | release/
27 | output/
28 | output_resource/
29 |
30 | .vscode/**/*
31 | !.vscode/settings.json
32 | !.vscode/extensions.json
33 | .idea/
34 |
35 | **/*/api/typings/auto-generated
36 | **/*/adapters/**/index.ts
37 | **/*/adapters/**/index.js
38 |
39 | src/
40 |
41 | modern.config.*
42 | tsconfig.json
43 | CHANGELOG.md
44 |
--------------------------------------------------------------------------------
/packages/inquirer/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # @modern-js/inquirer-types
2 |
3 | ## 2.6.8
4 |
5 | ### Patch Changes
6 |
7 | - @modern-js/codesmith-utils@2.6.8
8 |
9 | ## 2.6.7
10 |
11 | ### Patch Changes
12 |
13 | - @modern-js/codesmith-utils@2.6.7
14 |
15 | ## 2.6.6
16 |
17 | ### Patch Changes
18 |
19 | - Updated dependencies [29e8f3d]
20 | - @modern-js/codesmith-utils@2.6.6
21 |
22 | ## 2.6.5
23 |
24 | ### Patch Changes
25 |
26 | - @modern-js/codesmith-utils@2.6.5
27 |
28 | ## 2.6.4
29 |
30 | ### Patch Changes
31 |
32 | - @modern-js/codesmith-utils@2.6.4
33 |
34 | ## 2.6.3
35 |
36 | ### Patch Changes
37 |
38 | - @modern-js/codesmith-utils@2.6.3
39 |
40 | ## 2.6.2
41 |
42 | ### Patch Changes
43 |
44 | - @modern-js/codesmith-utils@2.6.2
45 |
46 | ## 2.6.1
47 |
48 | ### Patch Changes
49 |
50 | - @modern-js/codesmith-utils@2.6.1
51 |
52 | ## 2.6.0
53 |
54 | ### Patch Changes
55 |
56 | - @modern-js/codesmith-utils@2.6.0
57 |
58 | ## 2.5.2
59 |
60 | ## 2.5.1
61 |
62 | ## 2.5.0
63 |
64 | ## 2.4.2
65 |
66 | ## 2.4.1
67 |
68 | ### Patch Changes
69 |
70 | - 798f3d9: feat: npm publish ignore src file
71 |
72 | ## 2.4.0
73 |
74 | ## 2.3.6
75 |
76 | ## 2.3.5
77 |
78 | ## 2.3.4
79 |
80 | ## 2.3.3
81 |
82 | ## 2.3.2
83 |
84 | ## 2.3.1
85 |
86 | ## 2.3.0
87 |
88 | ### Minor Changes
89 |
90 | - 562a50f: feat: upgrade modern version && update module output path
91 |
92 | ## 2.2.8
93 |
94 | ## 2.2.7
95 |
96 | ## 2.2.6
97 |
98 | ### Patch Changes
99 |
100 | - de1d271: feat: bump modern dependencies version
101 |
102 | fea: 升级 modern 依赖版本
103 |
104 | - eb5ec83: chore: publishConfig add provenance config
105 |
106 | chore: publishConfig 增加 provenance 配置
107 |
108 | ## 2.2.5
109 |
110 | ## 2.2.4
111 |
112 | ## 2.2.3
113 |
114 | ## 2.2.2
115 |
116 | ## 2.2.1
117 |
118 | ## 2.2.0
119 |
120 | ### Minor Changes
121 |
122 | - f7d3176: chore: bump modern version && fix @modern-js/utils version
123 |
124 | ## 2.1.1
125 |
126 | ## 2.1.0
127 |
128 | ### Minor Changes
129 |
130 | - 1452195: feat: upgrade modern version to v2
131 |
132 | ## 2.0.5
133 |
134 | ## 2.0.4
135 |
136 | ## 2.0.3
137 |
138 | ## 2.0.2
139 |
140 | ## 2.0.1
141 |
142 | ## 2.0.0
143 |
144 | ## 1.6.3
145 |
146 | ## 1.6.2
147 |
148 | ## 1.6.1
149 |
150 | ## 1.6.0
151 |
152 | ## 1.5.1
153 |
154 | ## 1.5.0
155 |
156 | ## 1.3.0
157 |
158 | ### Minor Changes
159 |
160 | - e71e509: feat: adjust `package.json` field, delete `module` and `exports` field
161 |
162 | feat: 调整 `package.json` 中字段,删除 `module` 和 `exports` 字段
163 |
164 | ## 1.2.2
165 |
166 | ### Patch Changes
167 |
168 | - 7430860: fix: rxjs version
169 |
170 | ## 1.0.9
171 |
172 | ### Patch Changes
173 |
174 | - c40ea75: feat: bump @modern-js/utils version
175 |
176 | ## 1.0.8
177 |
178 | ### Patch Changes
179 |
180 | - 4791c02: feat: using prebundled deps from @modern-js/utils
181 |
182 | ## 1.0.7
183 |
184 | ### Patch Changes
185 |
186 | - d1f4956: feat: support noNeedInstall params
187 |
188 | ## 1.0.6
189 |
190 | ### Patch Changes
191 |
192 | - 0af3795: feat: support change git init branch
193 |
194 | ## 1.0.5
195 |
196 | ### Patch Changes
197 |
198 | - fix: build product
199 |
200 | ## 1.0.4
201 |
202 | ### Patch Changes
203 |
204 | - feat: export codesmith utils
205 |
206 | ## 1.0.3
207 |
208 | ### Patch Changes
209 |
210 | - 3ef5a43: feat: add release workflow
211 |
212 | ## 1.0.2
213 |
214 | ### Patch Changes
215 |
216 | - a6a1c5c: feat: remove run install '--ignore-scripts' params
217 |
218 | ## 1.0.1
219 |
220 | ### Patch Changes
221 |
222 | - fix: publish not container dist
223 |
224 | ## 1.0.0
225 |
226 | ### Patch Changes
227 |
228 | - feat: initial publish
229 |
--------------------------------------------------------------------------------
/packages/inquirer/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Modern.js
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/inquirer/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Modern.js
6 |
7 |
8 | A Progressive React Framework for modern web development.
9 |
10 |
11 | ## Getting Started
12 |
13 | Please follow [Quick Start](https://modernjs.dev/en/guides/get-started/quick-start) to get started with Modern.js.
14 |
15 | ## Documentation
16 |
17 | - [English Documentation](https://modernjs.dev/en/)
18 | - [中文文档](https://modernjs.dev)
19 |
20 | ## Contributing
21 |
22 | Please read the [Contributing Guide](https://github.com/web-infra-dev/modern.js/blob/main/CONTRIBUTING.md).
23 |
24 | ## License
25 |
26 | Modern.js is [MIT licensed](https://github.com/web-infra-dev/modern.js/blob/main/LICENSE).
27 |
--------------------------------------------------------------------------------
/packages/inquirer/modern.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig, moduleTools } from '@modern-js/module-tools';
2 |
3 | import { testingPlugin } from '@modern-js/plugin-testing';
4 |
5 | export default defineConfig({
6 | buildPreset: 'modern-js-universal',
7 | plugins: [moduleTools(), testingPlugin()],
8 | });
9 |
--------------------------------------------------------------------------------
/packages/inquirer/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@modern-js/inquirer-types",
3 | "description": "codesmith inquirer plugin to custom question",
4 | "homepage": "https://modernjs.dev",
5 | "bugs": "https://github.com/web-infra-dev/codesmith/issues",
6 | "repository": "web-infra-dev/codesmith",
7 | "license": "MIT",
8 | "keywords": [
9 | "react",
10 | "framework",
11 | "modern",
12 | "modern.js"
13 | ],
14 | "version": "2.6.8",
15 | "jsnext:source": "./src/index.ts",
16 | "types": "./dist/types/index.d.ts",
17 | "main": "./dist/cjs/index.js",
18 | "module": "./dist/esm-node/index.js",
19 | "publishConfig": {
20 | "registry": "https://registry.npmjs.org/",
21 | "access": "public"
22 | },
23 | "scripts": {
24 | "prepare": "pnpm build",
25 | "prepublishOnly": "pnpm build -- --platform",
26 | "new": "modern new",
27 | "build": "modern build",
28 | "test": "modern test --passWithNoTests"
29 | },
30 | "dependencies": {
31 | "@swc/helpers": "0.5.1",
32 | "cli-cursor": "^3.1.0",
33 | "inquirer": "8.1.3",
34 | "run-async": "^2.4.1",
35 | "rxjs": "^7.8.0",
36 | "@modern-js/codesmith-utils": "workspace:*"
37 | },
38 | "devDependencies": {
39 | "@modern-js/module-tools": "2.60.3",
40 | "@modern-js/plugin-testing": "2.60.3",
41 | "@types/inquirer": "^7.3.3",
42 | "@types/jest": "^26.0.24",
43 | "@types/lodash": "^4.14.192",
44 | "@types/node": "^14.18.42",
45 | "typescript": "^4.9.5"
46 | },
47 | "sideEffects": false
48 | }
49 |
--------------------------------------------------------------------------------
/packages/inquirer/src/index.ts:
--------------------------------------------------------------------------------
1 | export { List } from './list';
2 |
--------------------------------------------------------------------------------
/packages/inquirer/src/types/index.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'inquirer/lib/utils/incrementListIndex' {
2 | export default function incrementListIndex(
3 | current: number,
4 | dir: string,
5 | opt: { loop: boolean },
6 | ): number;
7 | }
8 |
9 | declare module 'run-async';
10 |
--------------------------------------------------------------------------------
/packages/inquirer/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | import { chalk } from '@modern-js/codesmith-utils/chalk';
2 | import type { Answers } from 'inquirer';
3 | import type OriginChoices from 'inquirer/lib/objects/choices';
4 | import { pointer as pointerCharacter } from './pointer';
5 |
6 | export type ChoiceItem = Answers & {
7 | disabled: boolean | ((answers: Answers) => boolean);
8 | };
9 |
10 | export type Choices = OriginChoices & {
11 | type?: 'separator' | 'choices';
12 | };
13 |
14 | /**
15 | * Function for rendering list choices
16 | * @param {Number} pointer Position of the pointer
17 | * @return {String} Rendered content
18 | */
19 | export function listRender(
20 | choices: Choices,
21 | pointer: number,
22 | answers: Answers,
23 | ): string {
24 | let output = '';
25 | let separatorOffset = 0;
26 |
27 | choices.forEach((choice, i) => {
28 | if (choice.type === 'separator') {
29 | separatorOffset++;
30 | // separator class toString result
31 | output += ` ${choice as any as string}\n`;
32 | return;
33 | }
34 |
35 | if (choice.disabled) {
36 | // TODO confirm
37 | if (typeof choice.disabled === 'function') {
38 | choice.disabled = (choice.disabled as (answers: Answers) => boolean)(
39 | answers,
40 | );
41 | }
42 | separatorOffset++;
43 | let choiceItem = '';
44 | choiceItem += ` - ${choice.name}`;
45 | choiceItem += ` (${
46 | typeof choice.disabled === 'string' ? choice.disabled : 'Disabled'
47 | })`;
48 | output += chalk.dim(choiceItem);
49 | output += '\n';
50 | return;
51 | }
52 |
53 | const isSelected = i - separatorOffset === pointer;
54 |
55 | let line = (isSelected ? `${pointerCharacter} ` : ' ') + choice.name;
56 |
57 | if (isSelected) {
58 | line = chalk.cyan(line);
59 | }
60 | output += `${line} \n`;
61 | });
62 |
63 | return output.replace(/\n$/, '');
64 | }
65 |
--------------------------------------------------------------------------------
/packages/inquirer/src/utils/pointer.ts:
--------------------------------------------------------------------------------
1 | function isUnicodeSupported() {
2 | if (process.platform !== 'win32') {
3 | return process.env.TERM !== 'linux'; // Linux console (kernel)
4 | }
5 |
6 | return (
7 | Boolean(process.env.CI) ||
8 | Boolean(process.env.WT_SESSION) || // Windows Terminal
9 | process.env.ConEmuTask === '{cmd::Cmder}' || // ConEmu and cmder
10 | process.env.TERM_PROGRAM === 'vscode' ||
11 | process.env.TERM === 'xterm-256color' ||
12 | process.env.TERM === 'alacritty'
13 | );
14 | }
15 |
16 | const shouldUseMain = isUnicodeSupported();
17 | const pointer = shouldUseMain ? '❯' : '>';
18 |
19 | export { pointer };
20 |
--------------------------------------------------------------------------------
/packages/inquirer/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@modern-js/tsconfig/base",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "jsx": "preserve",
6 | "baseUrl": "./",
7 | "isolatedModules": true,
8 | "paths": {
9 | "@/*": ["./src/*"]
10 | }
11 | },
12 | "include": ["src"]
13 | }
14 |
--------------------------------------------------------------------------------
/packages/utils/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | .pnp
4 | .pnp.js
5 | .env.*.local
6 | .history
7 | .rts*
8 | *.log*
9 | *.pid
10 | *.pid.*
11 | *.report
12 | *.lcov
13 | lib-cov
14 |
15 | node_modules/
16 | .npm
17 | .lock-wscript
18 | .yarn-integrity
19 | .node_repl_history
20 | .nyc_output
21 | *.tsbuildinfo
22 | .eslintcache
23 | .sonarlint
24 |
25 | coverage/
26 | release/
27 | output/
28 | output_resource/
29 |
30 | .vscode/**/*
31 | !.vscode/settings.json
32 | !.vscode/extensions.json
33 | .idea/
34 |
35 | **/*/api/typings/auto-generated
36 | **/*/adapters/**/index.ts
37 | **/*/adapters/**/index.js
38 |
39 | src/
40 | modern.config.*
41 | tsconfig.json
42 | CHANGELOG.md
43 |
--------------------------------------------------------------------------------
/packages/utils/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # @modern-js/codesmith-utils
2 |
3 | ## 2.6.8
4 |
5 | ## 2.6.7
6 |
7 | ## 2.6.6
8 |
9 | ### Patch Changes
10 |
11 | - 29e8f3d: feat: support fnm
12 |
13 | feat: 支持 fnm
14 |
15 | ## 2.6.5
16 |
17 | ## 2.6.4
18 |
19 | ## 2.6.3
20 |
21 | ## 2.6.2
22 |
23 | ## 2.6.1
24 |
25 | ## 2.6.0
26 |
--------------------------------------------------------------------------------
/packages/utils/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Modern.js
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/utils/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Modern.js
6 |
7 |
8 | A Progressive React Framework for modern web development.
9 |
10 |
11 | ## Getting Started
12 |
13 | Please follow [Quick Start](https://modernjs.dev/en/guides/get-started/quick-start) to get started with Modern.js.
14 |
15 | ## Documentation
16 |
17 | - [English Documentation](https://modernjs.dev/en/)
18 | - [中文文档](https://modernjs.dev)
19 |
20 | ## Contributing
21 |
22 | Please read the [Contributing Guide](https://github.com/web-infra-dev/modern.js/blob/main/CONTRIBUTING.md).
23 |
24 | ## License
25 |
26 | Modern.js is [MIT licensed](https://github.com/web-infra-dev/modern.js/blob/main/LICENSE).
27 |
--------------------------------------------------------------------------------
/packages/utils/modern.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig, moduleTools } from '@modern-js/module-tools';
2 |
3 | export default defineConfig({
4 | buildPreset: 'modern-js-universal',
5 | plugins: [moduleTools()],
6 | });
7 |
--------------------------------------------------------------------------------
/packages/utils/src/chalk.ts:
--------------------------------------------------------------------------------
1 | import chalk from 'chalk';
2 |
3 | export { chalk };
4 |
--------------------------------------------------------------------------------
/packages/utils/src/execa.ts:
--------------------------------------------------------------------------------
1 | import execa, { type ExecaReturnValue } from 'execa';
2 |
3 | export { execa, type ExecaReturnValue };
4 |
--------------------------------------------------------------------------------
/packages/utils/src/fs-extra.ts:
--------------------------------------------------------------------------------
1 | import fs from 'fs-extra';
2 |
3 | export { fs };
4 |
--------------------------------------------------------------------------------
/packages/utils/src/glob.ts:
--------------------------------------------------------------------------------
1 | import glob from 'glob';
2 |
3 | export { glob };
4 |
--------------------------------------------------------------------------------
/packages/utils/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './chalk';
2 | export * from './execa';
3 | export * from './fs-extra';
4 | export * from './glob';
5 | export * from './lodash';
6 | export * from './ora';
7 | export * from './semver';
8 | export * from './npm';
9 |
--------------------------------------------------------------------------------
/packages/utils/src/lodash.ts:
--------------------------------------------------------------------------------
1 | import flattenDeep from 'lodash.flattendeep';
2 | import get from 'lodash.get';
3 | import isFunction from 'lodash.isfunction';
4 | import isObject from 'lodash.isobject';
5 | import isString from 'lodash.isstring';
6 | import merge from 'lodash.merge';
7 |
8 | export { merge, isFunction, isObject, get, isString, flattenDeep };
9 |
--------------------------------------------------------------------------------
/packages/utils/src/npm.ts:
--------------------------------------------------------------------------------
1 | import execa from 'execa';
2 |
3 | export async function canUseNvm() {
4 | try {
5 | await execa('source ~/.nvm/nvm.sh', {
6 | env: process.env,
7 | shell: true,
8 | });
9 | return true;
10 | } catch (e) {
11 | return false;
12 | }
13 | }
14 |
15 | export async function canUseFnm() {
16 | try {
17 | await execa('fnm --version', {
18 | env: process.env,
19 | shell: true,
20 | });
21 | return true;
22 | } catch (e) {
23 | return false;
24 | }
25 | }
26 |
27 | export async function canUseNpm() {
28 | try {
29 | await execa('npm', ['--version'], {
30 | env: process.env,
31 | });
32 | return true;
33 | } catch (e) {
34 | return false;
35 | }
36 | }
37 |
38 | export async function canUseYarn() {
39 | try {
40 | await execa('yarn', ['--version'], {
41 | env: process.env,
42 | });
43 | return true;
44 | } catch (e) {
45 | return false;
46 | }
47 | }
48 |
49 | export async function canUsePnpm() {
50 | try {
51 | await execa('pnpm', ['--version'], {
52 | env: process.env,
53 | });
54 | return true;
55 | } catch (e) {
56 | return false;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/packages/utils/src/ora.ts:
--------------------------------------------------------------------------------
1 | import ora from 'ora';
2 |
3 | export { ora };
4 |
--------------------------------------------------------------------------------
/packages/utils/src/semver.ts:
--------------------------------------------------------------------------------
1 | import semver from 'semver';
2 |
3 | export { semver };
4 |
--------------------------------------------------------------------------------
/packages/utils/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@modern-js/tsconfig/base",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "jsx": "preserve",
6 | "baseUrl": "./",
7 | "isolatedModules": true,
8 | "paths": {
9 | "@/*": ["./src/*"]
10 | }
11 | },
12 | "include": ["src"]
13 | }
14 |
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - 'apps/**'
3 | - 'examples/**'
4 | - 'services/**'
5 | - 'features/**'
6 | - 'packages/**'
7 | - 'packages/api/**'
8 | - 'packages/easy-form/**'
9 | - 'scripts'
10 |
--------------------------------------------------------------------------------
/scripts/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: '@modern-js',
3 | parserOptions: {
4 | project: require.resolve('./tsconfig.json'),
5 | },
6 | rules: {
7 | 'no-console': 'off',
8 | },
9 | };
10 |
--------------------------------------------------------------------------------
/scripts/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@modern-js-codesmith/scripts",
3 | "private": true,
4 | "version": "0.0.0",
5 | "scripts": {
6 | "get-release-version": "tsx ./src/get-release-version.ts"
7 | },
8 | "dependencies": {
9 | "@changesets/assemble-release-plan": "^5.2.1",
10 | "@changesets/config": "^2.1.1",
11 | "@changesets/read": "^0.6.0",
12 | "@manypkg/get-packages": "^1.1.3"
13 | },
14 | "devDependencies": {
15 | "@types/node": "^18.0.1",
16 | "tsx": "~3.12.7"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/scripts/src/get-release-version.ts:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import assembleReleasePlan from '@changesets/assemble-release-plan';
3 | import { read } from '@changesets/config';
4 | import readChangesets from '@changesets/read';
5 | import { getPackages } from '@manypkg/get-packages';
6 |
7 | async function run() {
8 | const cwd = process.cwd();
9 | const repoDir = path.join(cwd, '..');
10 | const changesets = await readChangesets(repoDir, process.env.BASE_BRANCH);
11 | const packages = await getPackages(repoDir);
12 | const config = await read(repoDir, packages);
13 | const releasePlan = assembleReleasePlan(
14 | changesets,
15 | packages,
16 | config,
17 | undefined,
18 | );
19 | if (releasePlan.releases.length === 0) {
20 | return;
21 | }
22 | const releaseVersion = `v${releasePlan.releases[0].newVersion}`;
23 | console.log(releaseVersion);
24 | }
25 |
26 | run().catch(e => {
27 | console.error(e);
28 | // eslint-disable-next-line no-process-exit
29 | process.exit(1);
30 | });
31 |
--------------------------------------------------------------------------------
/scripts/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@modern-js/tsconfig/base",
3 | "compilerOptions": {
4 | "baseUrl": "./",
5 | "outDir": "./dist"
6 | },
7 | "include": ["src"]
8 | }
9 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@modern-js/tsconfig/react",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "jsx": "preserve"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------