├── .node-version
├── .prettierignore
├── template
├── stylelint
│ ├── _stylelintignore
│ └── stylelint.config.js
├── vitest
│ ├── _stylelintignore
│ ├── _gitignore
│ ├── __tests__
│ │ └── utils
│ │ │ └── index.spec.js
│ ├── src
│ │ └── utils
│ │ │ └── index.js
│ └── vitest.config.js
├── base
│ ├── _npmrc
│ ├── src
│ │ ├── pages
│ │ │ ├── home
│ │ │ │ ├── index.json
│ │ │ │ ├── index.html
│ │ │ │ └── index.css
│ │ │ └── mine
│ │ │ │ ├── index.json
│ │ │ │ ├── index.html
│ │ │ │ └── index.css
│ │ ├── images
│ │ │ ├── home-dark.png
│ │ │ ├── home-light.png
│ │ │ ├── mine-dark.png
│ │ │ ├── mine-light.png
│ │ │ ├── vue-mini.png
│ │ │ ├── home-dark-selected.png
│ │ │ ├── home-light-selected.png
│ │ │ ├── mine-dark-selected.png
│ │ │ └── mine-light-selected.png
│ │ ├── sitemap.json
│ │ ├── app.css
│ │ ├── theme.json
│ │ └── app.json
│ ├── _gitignore
│ ├── _editorconfig
│ ├── postcss.config.js
│ ├── project.config.json
│ └── package.json.ejs
├── vitest-typescript
│ ├── _stylelintignore
│ ├── _gitignore
│ ├── __tests__
│ │ └── utils
│ │ │ └── index.spec.ts
│ ├── src
│ │ └── utils
│ │ │ └── index.ts
│ ├── vitest.config.ts
│ └── tsconfig.json
├── vitest-pnpm
│ └── pnpm-workspace.yaml
├── pinia
│ └── src
│ │ ├── pinia.js
│ │ ├── app.js
│ │ └── stores
│ │ └── count.js
├── prettier
│ └── prettier.config.js
├── pinia-typescript
│ └── src
│ │ ├── pinia.ts
│ │ ├── app.ts
│ │ └── stores
│ │ └── count.ts
├── javascript
│ ├── src
│ │ ├── app.js
│ │ └── pages
│ │ │ ├── mine
│ │ │ └── index.js
│ │ │ └── home
│ │ │ └── index.js
│ ├── babel.config.js
│ └── build.js
├── typescript
│ ├── src
│ │ ├── app.ts
│ │ └── pages
│ │ │ ├── mine
│ │ │ └── index.ts
│ │ │ └── home
│ │ │ └── index.ts
│ ├── tsconfig.json
│ ├── babel.config.js
│ └── build.js
└── eslint
│ └── eslint.config.js.ejs
├── .gitignore
├── media
└── screenshot-cli-v2.png
├── .vscode
└── settings.json
├── prettier.config.js
├── .editorconfig
├── .github
└── workflows
│ └── ci.yml
├── tsconfig.json
├── eslint.config.js
├── LICENSE
├── package.json
├── README.md
├── index.ts
└── pnpm-lock.yaml
/.node-version:
--------------------------------------------------------------------------------
1 | v25.2.1
2 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | template
2 |
--------------------------------------------------------------------------------
/template/stylelint/_stylelintignore:
--------------------------------------------------------------------------------
1 | dist
2 |
--------------------------------------------------------------------------------
/template/vitest/_stylelintignore:
--------------------------------------------------------------------------------
1 | coverage
2 | dist
3 |
--------------------------------------------------------------------------------
/template/base/_npmrc:
--------------------------------------------------------------------------------
1 | registry=https://registry.npmmirror.com/
2 |
--------------------------------------------------------------------------------
/template/vitest-typescript/_stylelintignore:
--------------------------------------------------------------------------------
1 | coverage
2 | dist
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | *.log*
4 |
5 | outfile.js
6 |
--------------------------------------------------------------------------------
/template/base/src/pages/home/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {}
3 | }
4 |
--------------------------------------------------------------------------------
/template/base/src/pages/mine/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {}
3 | }
4 |
--------------------------------------------------------------------------------
/template/vitest-pnpm/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | onlyBuiltDependencies:
2 | - esbuild
3 |
--------------------------------------------------------------------------------
/template/base/_gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | dist
4 | *.log*
5 | .vscode
6 | .idea
7 |
--------------------------------------------------------------------------------
/template/vitest/_gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | coverage
4 | dist
5 | *.log*
6 | .vscode
7 | .idea
8 |
--------------------------------------------------------------------------------
/media/screenshot-cli-v2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vue-mini/create-vue-mini/HEAD/media/screenshot-cli-v2.png
--------------------------------------------------------------------------------
/template/pinia/src/pinia.js:
--------------------------------------------------------------------------------
1 | import { createPinia } from '@vue-mini/pinia';
2 |
3 | export const pinia = createPinia();
4 |
--------------------------------------------------------------------------------
/template/prettier/prettier.config.js:
--------------------------------------------------------------------------------
1 | const config = {
2 | singleQuote: true,
3 | };
4 |
5 | export default config;
6 |
--------------------------------------------------------------------------------
/template/vitest-typescript/_gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | coverage
4 | dist
5 | *.log*
6 | .vscode
7 | .idea
8 |
--------------------------------------------------------------------------------
/template/base/src/images/home-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vue-mini/create-vue-mini/HEAD/template/base/src/images/home-dark.png
--------------------------------------------------------------------------------
/template/base/src/images/home-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vue-mini/create-vue-mini/HEAD/template/base/src/images/home-light.png
--------------------------------------------------------------------------------
/template/base/src/images/mine-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vue-mini/create-vue-mini/HEAD/template/base/src/images/mine-dark.png
--------------------------------------------------------------------------------
/template/base/src/images/mine-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vue-mini/create-vue-mini/HEAD/template/base/src/images/mine-light.png
--------------------------------------------------------------------------------
/template/base/src/images/vue-mini.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vue-mini/create-vue-mini/HEAD/template/base/src/images/vue-mini.png
--------------------------------------------------------------------------------
/template/pinia-typescript/src/pinia.ts:
--------------------------------------------------------------------------------
1 | import { createPinia } from '@vue-mini/pinia';
2 |
3 | export const pinia = createPinia();
4 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "typescript.tsdk": "node_modules/typescript/lib",
3 | "typescript.enablePromptUseWorkspaceTsdk": true
4 | }
5 |
--------------------------------------------------------------------------------
/template/javascript/src/app.js:
--------------------------------------------------------------------------------
1 | import { createApp } from '@vue-mini/core';
2 |
3 | createApp(() => {
4 | console.log('App Launched!');
5 | });
6 |
--------------------------------------------------------------------------------
/template/typescript/src/app.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from '@vue-mini/core';
2 |
3 | createApp(() => {
4 | console.log('App Launched!');
5 | });
6 |
--------------------------------------------------------------------------------
/template/base/src/images/home-dark-selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vue-mini/create-vue-mini/HEAD/template/base/src/images/home-dark-selected.png
--------------------------------------------------------------------------------
/template/base/src/images/home-light-selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vue-mini/create-vue-mini/HEAD/template/base/src/images/home-light-selected.png
--------------------------------------------------------------------------------
/template/base/src/images/mine-dark-selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vue-mini/create-vue-mini/HEAD/template/base/src/images/mine-dark-selected.png
--------------------------------------------------------------------------------
/template/base/src/images/mine-light-selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vue-mini/create-vue-mini/HEAD/template/base/src/images/mine-light-selected.png
--------------------------------------------------------------------------------
/template/pinia/src/app.js:
--------------------------------------------------------------------------------
1 | import { createApp } from '@vue-mini/core';
2 | import './pinia';
3 |
4 | createApp(() => {
5 | console.log('App Launched!');
6 | });
7 |
--------------------------------------------------------------------------------
/template/pinia-typescript/src/app.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from '@vue-mini/core';
2 | import './pinia';
3 |
4 | createApp(() => {
5 | console.log('App Launched!');
6 | });
7 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | const config = {
2 | semi: false,
3 | singleQuote: true,
4 | objectWrap: 'collapse',
5 | experimentalTernaries: true,
6 | }
7 |
8 | export default config
9 |
--------------------------------------------------------------------------------
/template/base/src/pages/home/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ greeting }}
4 |
5 |
--------------------------------------------------------------------------------
/template/base/src/pages/mine/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ greeting }}
4 |
5 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/template/base/_editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/template/javascript/src/pages/mine/index.js:
--------------------------------------------------------------------------------
1 | import { defineComponent, ref } from '@vue-mini/core';
2 |
3 | defineComponent(() => {
4 | const greeting = ref('希望你会喜欢');
5 |
6 | return {
7 | greeting,
8 | };
9 | });
10 |
--------------------------------------------------------------------------------
/template/typescript/src/pages/mine/index.ts:
--------------------------------------------------------------------------------
1 | import { defineComponent, ref } from '@vue-mini/core';
2 |
3 | defineComponent(() => {
4 | const greeting = ref('希望你会喜欢');
5 |
6 | return {
7 | greeting,
8 | };
9 | });
10 |
--------------------------------------------------------------------------------
/template/javascript/src/pages/home/index.js:
--------------------------------------------------------------------------------
1 | import { defineComponent, ref } from '@vue-mini/core';
2 |
3 | defineComponent(() => {
4 | const greeting = ref('欢迎使用 Vue Mini');
5 |
6 | return {
7 | greeting,
8 | };
9 | });
10 |
--------------------------------------------------------------------------------
/template/typescript/src/pages/home/index.ts:
--------------------------------------------------------------------------------
1 | import { defineComponent, ref } from '@vue-mini/core';
2 |
3 | defineComponent(() => {
4 | const greeting = ref('欢迎使用 Vue Mini');
5 |
6 | return {
7 | greeting,
8 | };
9 | });
10 |
--------------------------------------------------------------------------------
/template/base/src/sitemap.json:
--------------------------------------------------------------------------------
1 | {
2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
3 | "rules": [
4 | {
5 | "action": "allow",
6 | "page": "*"
7 | }
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/template/vitest/__tests__/utils/index.spec.js:
--------------------------------------------------------------------------------
1 | import { describe, test, expect } from 'vitest';
2 | import { stringifyQuery } from '@/utils';
3 |
4 | describe('utils', () => {
5 | test('stringifyQuery', () => {
6 | expect(stringifyQuery({ page: '1', size: '10', status: 'a,b' })).toBe(
7 | '?page=1&size=10&status=a%2Cb',
8 | );
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/template/base/src/app.css:
--------------------------------------------------------------------------------
1 | page {
2 | color: #181818;
3 | font-size: 28px;
4 | font-family:
5 | ui-sans-serif,
6 | system-ui,
7 | -apple-system,
8 | BlinkMacSystemFont,
9 | sans-serif;
10 | background: #fff;
11 | }
12 |
13 | @media (prefers-color-scheme: dark) {
14 | page {
15 | color: #fff;
16 | background: #181818;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/template/vitest-typescript/__tests__/utils/index.spec.ts:
--------------------------------------------------------------------------------
1 | import { describe, test, expect } from 'vitest';
2 | import { stringifyQuery } from '@/utils';
3 |
4 | describe('utils', () => {
5 | test('stringifyQuery', () => {
6 | expect(stringifyQuery({ page: '1', size: '10', status: 'a,b' })).toBe(
7 | '?page=1&size=10&status=a%2Cb',
8 | );
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/template/base/src/pages/home/index.css:
--------------------------------------------------------------------------------
1 | .home {
2 | text-align: center;
3 | }
4 |
5 | .logo {
6 | width: 400px;
7 | height: 400px;
8 | margin-top: 120px;
9 | }
10 |
11 | .greeting {
12 | color: #2c3e50;
13 | font-size: 64px;
14 | font-weight: bold;
15 | }
16 |
17 | @media (prefers-color-scheme: dark) {
18 | .greeting {
19 | color: #fff;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/template/base/src/pages/mine/index.css:
--------------------------------------------------------------------------------
1 | .mine {
2 | text-align: center;
3 | }
4 |
5 | .logo {
6 | width: 400px;
7 | height: 400px;
8 | margin-top: 120px;
9 | }
10 |
11 | .greeting {
12 | color: #2c3e50;
13 | font-size: 64px;
14 | font-weight: bold;
15 | }
16 |
17 | @media (prefers-color-scheme: dark) {
18 | .greeting {
19 | color: #fff;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/template/stylelint/stylelint.config.js:
--------------------------------------------------------------------------------
1 | const config = {
2 | extends: 'stylelint-config-standard',
3 | rules: {
4 | 'alpha-value-notation': 'number',
5 | 'color-function-notation': 'legacy',
6 | 'selector-type-no-unknown': [
7 | true,
8 | {
9 | ignoreTypes: ['page'],
10 | },
11 | ],
12 | },
13 | };
14 |
15 | export default config;
16 |
--------------------------------------------------------------------------------
/template/vitest/src/utils/index.js:
--------------------------------------------------------------------------------
1 | export function stringifyQuery(query) {
2 | let queryString = '';
3 | for (const [key, value] of Object.entries(query)) {
4 | queryString = `${queryString}&${encodeURIComponent(
5 | key,
6 | )}=${encodeURIComponent(value)}`;
7 | }
8 |
9 | queryString &&= queryString.replace(/^&/, '?');
10 |
11 | return queryString;
12 | }
13 |
--------------------------------------------------------------------------------
/template/pinia/src/stores/count.js:
--------------------------------------------------------------------------------
1 | import { ref, computed } from '@vue-mini/core';
2 | import { defineStore } from '@vue-mini/pinia';
3 |
4 | export const useCountStore = defineStore('count', () => {
5 | const count = ref(0);
6 | const double = computed(() => count.value * 2);
7 |
8 | const increment = () => {
9 | count.value++;
10 | };
11 |
12 | return { count, double, increment };
13 | });
14 |
--------------------------------------------------------------------------------
/template/pinia-typescript/src/stores/count.ts:
--------------------------------------------------------------------------------
1 | import { ref, computed } from '@vue-mini/core';
2 | import { defineStore } from '@vue-mini/pinia';
3 |
4 | export const useCountStore = defineStore('count', () => {
5 | const count = ref(0);
6 | const double = computed(() => count.value * 2);
7 |
8 | const increment = () => {
9 | count.value++;
10 | };
11 |
12 | return { count, double, increment };
13 | });
14 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on: push
3 | jobs:
4 | run:
5 | runs-on: ubuntu-latest
6 | steps:
7 | - uses: actions/checkout@v5
8 | - uses: pnpm/action-setup@v4
9 | - uses: actions/setup-node@v6
10 | with:
11 | node-version: 24.x
12 | cache: pnpm
13 | - run: pnpm install
14 | - run: pnpm format
15 | - run: pnpm lint
16 | - run: pnpm type
17 |
--------------------------------------------------------------------------------
/template/vitest-typescript/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | export function stringifyQuery(query: Record): string {
2 | let queryString = '';
3 | for (const [key, value] of Object.entries(query)) {
4 | queryString = `${queryString}&${encodeURIComponent(
5 | key,
6 | )}=${encodeURIComponent(value)}`;
7 | }
8 |
9 | queryString &&= queryString.replace(/^&/, '?');
10 |
11 | return queryString;
12 | }
13 |
--------------------------------------------------------------------------------
/template/base/postcss.config.js:
--------------------------------------------------------------------------------
1 | import pxtorpx from 'postcss-pxtorpx-pro';
2 |
3 | const config = {
4 | plugins: [
5 | {
6 | postcssPlugin: 'postcss-import-css-to-wxss',
7 | AtRule: {
8 | import: (atRule) => {
9 | atRule.params = atRule.params.replace('.css', '.wxss');
10 | },
11 | },
12 | },
13 | pxtorpx({ transform: (x) => x }),
14 | ],
15 | };
16 |
17 | export default config;
18 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2022",
4 | "lib": ["es2023"],
5 | "skipLibCheck": true,
6 | "esModuleInterop": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "module": "nodenext",
10 | "moduleResolution": "nodenext",
11 | "isolatedModules": true,
12 | "resolveJsonModule": true,
13 | "noFallthroughCasesInSwitch": true,
14 | "noUnusedLocals": true,
15 | "noUnusedParameters": true
16 | },
17 | "include": ["index.ts"]
18 | }
19 |
--------------------------------------------------------------------------------
/template/vitest/vitest.config.js:
--------------------------------------------------------------------------------
1 | import { fileURLToPath } from 'node:url';
2 | import { defineConfig } from 'vitest/config';
3 |
4 | export default defineConfig({
5 | resolve: {
6 | alias: {
7 | '@': fileURLToPath(new URL('src', import.meta.url)),
8 | },
9 | },
10 | test: {
11 | include: ['__tests__/**/*.spec.js'],
12 | sequence: {
13 | hooks: 'list',
14 | },
15 | coverage: {
16 | provider: 'v8',
17 | reporter: ['text', 'html', 'json'],
18 | include: ['src/**/*.js'],
19 | },
20 | },
21 | });
22 |
--------------------------------------------------------------------------------
/template/vitest-typescript/vitest.config.ts:
--------------------------------------------------------------------------------
1 | import { fileURLToPath } from 'node:url';
2 | import { defineConfig } from 'vitest/config';
3 |
4 | export default defineConfig({
5 | resolve: {
6 | alias: {
7 | '@': fileURLToPath(new URL('src', import.meta.url)),
8 | },
9 | },
10 | test: {
11 | include: ['__tests__/**/*.spec.ts'],
12 | sequence: {
13 | hooks: 'list',
14 | },
15 | coverage: {
16 | provider: 'v8',
17 | reporter: ['text', 'html', 'json'],
18 | include: ['src/**/*.ts'],
19 | },
20 | },
21 | });
22 |
--------------------------------------------------------------------------------
/template/typescript/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "lib": ["esnext", "dom"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "esModuleInterop": true,
8 | "strict": true,
9 | "strictFunctionTypes": false,
10 | "forceConsistentCasingInFileNames": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "isolatedModules": true,
14 | "noEmit": true,
15 | "noFallthroughCasesInSwitch": true,
16 | "noUnusedLocals": true,
17 | "noUnusedParameters": true,
18 | "paths": {
19 | "@/*": ["./src/*"]
20 | }
21 | },
22 | "include": ["src"]
23 | }
24 |
--------------------------------------------------------------------------------
/template/base/src/theme.json:
--------------------------------------------------------------------------------
1 | {
2 | "light": {
3 | "style": "black",
4 | "color": "#181818",
5 | "bgColor": "#ffffff",
6 | "homeIcon": "/images/home-light.png",
7 | "homeSelectedIcon": "/images/home-light-selected.png",
8 | "mineIcon": "/images/mine-light.png",
9 | "mineSelectedIcon": "/images/mine-light-selected.png"
10 | },
11 | "dark": {
12 | "style": "white",
13 | "color": "#ffffff",
14 | "bgColor": "#181818",
15 | "homeIcon": "/images/home-dark.png",
16 | "homeSelectedIcon": "/images/home-dark-selected.png",
17 | "mineIcon": "/images/mine-dark.png",
18 | "mineSelectedIcon": "/images/mine-dark-selected.png"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/template/vitest-typescript/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "lib": ["esnext", "dom"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "esModuleInterop": true,
8 | "strict": true,
9 | "strictFunctionTypes": false,
10 | "forceConsistentCasingInFileNames": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "isolatedModules": true,
14 | "noEmit": true,
15 | "noFallthroughCasesInSwitch": true,
16 | "noUnusedLocals": true,
17 | "noUnusedParameters": true,
18 | "paths": {
19 | "@/*": ["./src/*"]
20 | }
21 | },
22 | "include": ["src", "__tests__", "vitest.config.ts"]
23 | }
24 |
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | import eslint from '@eslint/js'
2 | import tseslint from 'typescript-eslint'
3 |
4 | const config = [
5 | { ignores: ['template/', 'outfile.js'] },
6 | {
7 | files: ['**/*.js', '**/*.ts'],
8 | linterOptions: { reportUnusedDisableDirectives: true },
9 | rules: {
10 | ...eslint.configs.recommended.rules,
11 | // Avoid conflicts with Prettier
12 | // https://github.com/prettier/eslint-config-prettier#no-unexpected-multiline
13 | 'no-unexpected-multiline': 'off',
14 | },
15 | },
16 | ...tseslint.configs.recommendedTypeChecked.map((c) => ({
17 | ...c,
18 | files: ['**/*.ts'],
19 | })),
20 | {
21 | files: ['**/*.ts'],
22 | languageOptions: {
23 | parserOptions: {
24 | projectService: true,
25 | tsconfigRootDir: import.meta.dirname,
26 | },
27 | },
28 | },
29 | ]
30 |
31 | export default config
32 |
--------------------------------------------------------------------------------
/template/base/src/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "darkmode": true,
3 | "themeLocation": "theme.json",
4 | "pages": ["pages/home/index", "pages/mine/index"],
5 | "window": {
6 | "navigationBarBackgroundColor": "@bgColor",
7 | "navigationBarTextStyle": "@style",
8 | "navigationBarTitleText": "vue-mini-project",
9 | "backgroundColor": "@bgColor",
10 | "backgroundColorTop": "@bgColor",
11 | "backgroundColorBottom": "@bgColor"
12 | },
13 | "tabBar": {
14 | "color": "@color",
15 | "selectedColor": "@color",
16 | "backgroundColor": "@bgColor",
17 | "borderStyle": "@style",
18 | "list": [
19 | {
20 | "text": "主页",
21 | "pagePath": "pages/home/index",
22 | "iconPath": "@homeIcon",
23 | "selectedIconPath": "@homeSelectedIcon"
24 | },
25 | {
26 | "text": "我",
27 | "pagePath": "pages/mine/index",
28 | "iconPath": "@mineIcon",
29 | "selectedIconPath": "@mineSelectedIcon"
30 | }
31 | ]
32 | },
33 | "sitemapLocation": "sitemap.json",
34 | "lazyCodeLoading": "requiredComponents"
35 | }
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Vue Mini
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 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "create-vue-mini",
3 | "version": "1.4.3",
4 | "type": "module",
5 | "packageManager": "pnpm@10.24.0",
6 | "description": "Vue Mini 脚手架",
7 | "bin": {
8 | "create-vue-mini": "outfile.js"
9 | },
10 | "files": [
11 | "outfile.js",
12 | "template"
13 | ],
14 | "engines": {
15 | "node": ">=18.19.1 <19 || >=20.6.1"
16 | },
17 | "scripts": {
18 | "format": "prettier --check \"**/*.{js,ts,json,md}\"",
19 | "lint": "eslint .",
20 | "type": "tsc --noEmit",
21 | "build": "tsc && mv index.js outfile.js"
22 | },
23 | "repository": "https://github.com/vue-mini/create-vue-mini.git",
24 | "author": "Yang Mingshan ",
25 | "license": "MIT",
26 | "dependencies": {
27 | "ejs": "^3.1.10",
28 | "kolorist": "^1.8.0",
29 | "prompts": "^2.4.2"
30 | },
31 | "devDependencies": {
32 | "@eslint/js": "^9.39.1",
33 | "@types/ejs": "^3.1.5",
34 | "@types/node": "^24.10.1",
35 | "@types/prompts": "^2.4.9",
36 | "eslint": "^9.39.1",
37 | "prettier": "^3.7.2",
38 | "typescript": "^5.9.3",
39 | "typescript-eslint": "^8.48.0"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # create-vue-mini
2 |
3 | 创建 Vue Mini 小程序项目的最佳方案。
4 |
5 |
6 |
7 |
8 |
9 | ## 使用
10 |
11 | 要使用 `create-vue-mini` 创建一个全新的 Vue Mini 小程序项目,请直接在终端内运行以下命令:
12 |
13 | ```bash
14 | npm create vue-mini@latest
15 | ```
16 |
17 |
18 | > [!NOTE]
19 | > `@latest` **不能**省略,否则 `npm` 可能会使用已缓存的旧版本。
20 |
21 | ## 常见问题
22 |
23 | ### 如何使用小程序组件库?
24 |
25 | `create-vue-mini` 对小程序组件库提供了开箱支持,**不需要**使用微信开发者工具的 `工具 -> 构建 npm` 功能,**不需要**勾选 `将 JS 编译成 ES5`,只需要将小程序组件库作为**生产依赖**(即 dependencies)安装,就可以直接使用。`create-vue-mini` 会在幕后帮你将一切处理妥当。视频介绍:[《Vue Mini 如何使用小程序组件库》](https://www.bilibili.com/video/BV1w1421t7US/)
26 |
27 | ### 支持小程序独立分包吗?
28 |
29 | 支持。但是不支持动态添加独立分包,也就是说在 `app.json` 添加独立分包后需要重启开发服务器。
30 |
31 | ## 致谢
32 |
33 | 此项目由 [create-vue](https://github.com/vuejs/create-vue) 修改而来。
34 |
35 | ## 许可证
36 |
37 | [MIT](https://opensource.org/licenses/MIT)
38 |
39 | Copyright (c) 2024-present Yang Mingshan
40 |
--------------------------------------------------------------------------------
/template/javascript/babel.config.js:
--------------------------------------------------------------------------------
1 | import fs from 'node:fs';
2 |
3 | const runtimeVersion = JSON.parse(
4 | fs.readFileSync(
5 | new URL(import.meta.resolve('@babel/runtime/package.json')),
6 | 'utf8',
7 | ),
8 | ).version;
9 |
10 | const config = {
11 | targets: {},
12 | assumptions: {
13 | arrayLikeIsIterable: true,
14 | constantReexports: true,
15 | constantSuper: true,
16 | enumerableModuleMeta: true,
17 | ignoreFunctionLength: true,
18 | ignoreToPrimitiveHint: true,
19 | iterableIsArray: true,
20 | mutableTemplateObject: true,
21 | noClassCalls: true,
22 | noDocumentAll: true,
23 | noNewArrows: true,
24 | objectRestNoSymbols: true,
25 | privateFieldsAsProperties: true,
26 | pureGetters: true,
27 | setClassMethods: true,
28 | setComputedProperties: true,
29 | setPublicClassFields: true,
30 | setSpreadProperties: true,
31 | skipForOfIteratorClosing: true,
32 | superIsCallableConstructor: true,
33 | },
34 | presets: [
35 | [
36 | '@babel/preset-env',
37 | {
38 | bugfixes: true,
39 | modules: 'commonjs',
40 | },
41 | ],
42 | ],
43 | plugins: [
44 | [
45 | '@babel/plugin-transform-runtime',
46 | {
47 | version: runtimeVersion,
48 | },
49 | ],
50 | 'transform-inline-environment-variables',
51 | [
52 | 'module-resolver',
53 | {
54 | alias: {
55 | '@': './src',
56 | },
57 | },
58 | ],
59 | 'autocomplete-index',
60 | ],
61 | };
62 |
63 | export default config;
64 |
--------------------------------------------------------------------------------
/template/typescript/babel.config.js:
--------------------------------------------------------------------------------
1 | import fs from 'node:fs';
2 |
3 | const runtimeVersion = JSON.parse(
4 | fs.readFileSync(
5 | new URL(import.meta.resolve('@babel/runtime/package.json')),
6 | 'utf8',
7 | ),
8 | ).version;
9 |
10 | const config = {
11 | targets: {},
12 | assumptions: {
13 | arrayLikeIsIterable: true,
14 | constantReexports: true,
15 | constantSuper: true,
16 | enumerableModuleMeta: true,
17 | ignoreFunctionLength: true,
18 | ignoreToPrimitiveHint: true,
19 | iterableIsArray: true,
20 | mutableTemplateObject: true,
21 | noClassCalls: true,
22 | noDocumentAll: true,
23 | noNewArrows: true,
24 | objectRestNoSymbols: true,
25 | privateFieldsAsProperties: true,
26 | pureGetters: true,
27 | setClassMethods: true,
28 | setComputedProperties: true,
29 | setPublicClassFields: true,
30 | setSpreadProperties: true,
31 | skipForOfIteratorClosing: true,
32 | superIsCallableConstructor: true,
33 | },
34 | presets: [
35 | [
36 | '@babel/preset-env',
37 | {
38 | bugfixes: true,
39 | modules: 'commonjs',
40 | },
41 | ],
42 | '@babel/preset-typescript',
43 | ],
44 | plugins: [
45 | [
46 | '@babel/plugin-transform-runtime',
47 | {
48 | version: runtimeVersion,
49 | },
50 | ],
51 | 'transform-inline-environment-variables',
52 | [
53 | 'module-resolver',
54 | {
55 | alias: {
56 | '@': './src',
57 | },
58 | },
59 | ],
60 | 'autocomplete-index',
61 | ],
62 | };
63 |
64 | export default config;
65 |
--------------------------------------------------------------------------------
/template/base/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "项目配置文件",
3 | "miniprogramRoot": "dist/",
4 | "packOptions": {
5 | "ignore": [],
6 | "include": []
7 | },
8 | "setting": {
9 | "urlCheck": false,
10 | "es6": false,
11 | "enhance": false,
12 | "postcss": false,
13 | "preloadBackgroundData": false,
14 | "minified": false,
15 | "newFeature": true,
16 | "coverView": true,
17 | "nodeModules": false,
18 | "autoAudits": false,
19 | "showShadowRootInWxmlPanel": false,
20 | "scopeDataCheck": false,
21 | "uglifyFileName": false,
22 | "checkInvalidKey": true,
23 | "checkSiteMap": true,
24 | "uploadWithSourceMap": false,
25 | "compileHotReLoad": true,
26 | "lazyloadPlaceholderEnable": false,
27 | "useMultiFrameRuntime": true,
28 | "useApiHook": true,
29 | "useApiHostProcess": true,
30 | "babelSetting": {
31 | "ignore": [],
32 | "disablePlugins": [],
33 | "outputPath": ""
34 | },
35 | "useIsolateContext": false,
36 | "userConfirmedUseIsolateContext": false,
37 | "userConfirmedBundleSwitch": false,
38 | "packNpmManually": false,
39 | "packNpmRelationList": [],
40 | "minifyWXSS": true,
41 | "disableUseStrict": false,
42 | "minifyWXML": true,
43 | "showES6CompileOption": false,
44 | "useCompilerPlugins": false,
45 | "ignoreUploadUnusedFiles": true,
46 | "compileWorklet": false,
47 | "localPlugins": false,
48 | "condition": false,
49 | "swc": false,
50 | "disableSWC": true,
51 | "skylineRenderEnable": false,
52 | "useStaticServer": false,
53 | "useLanDebug": false,
54 | "ignoreDevUnusedFiles": true,
55 | "bigPackageSizeSupport": false
56 | },
57 | "compileType": "miniprogram",
58 | "libVersion": "development",
59 | "appid": "",
60 | "projectname": "vue-mini-project",
61 | "simulatorType": "wechat",
62 | "simulatorPluginLibVersion": {},
63 | "condition": {},
64 | "srcMiniprogramRoot": "dist/",
65 | "editorSetting": {
66 | "tabIndent": "insertSpaces",
67 | "tabSize": 2
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/template/eslint/eslint.config.js.ejs:
--------------------------------------------------------------------------------
1 | import globals from 'globals';
2 | import eslint from '@eslint/js';
3 | <%_ if (needsTypeScript) { _%>
4 | import tseslint from 'typescript-eslint';
5 | <%_ } _%>
6 | <%_ if (needsPrettier) { _%>
7 | import prettier from 'eslint-config-prettier';
8 | <%_ } _%>
9 |
10 | <%_ if (needsTypeScript) { _%>
11 | const config = [
12 | {
13 | <%_ if (needsVitest) { _%>
14 | ignores: ['dist/', 'coverage/'],
15 | <%_ } else { _%>
16 | ignores: ['dist/'],
17 | <%_ } _%>
18 | },
19 | {
20 | files: ['**/*.js', '**/*.ts'],
21 | linterOptions: {
22 | reportUnusedDisableDirectives: true,
23 | },
24 | ...eslint.configs.recommended,
25 | },
26 | {
27 | files: ['**/*.js'],
28 | languageOptions: {
29 | globals: {
30 | ...globals.node,
31 | wx: 'readonly',
32 | getApp: 'readonly',
33 | getCurrentPages: 'readonly',
34 | },
35 | },
36 | <%_ if (needsPrettier) { _%>
37 | ...prettier,
38 | <%_ } _%>
39 | },
40 | ...tseslint.configs.recommendedTypeChecked.map((c) => ({
41 | ...c,
42 | files: ['**/*.ts'],
43 | })),
44 | {
45 | files: ['**/*.ts'],
46 | languageOptions: {
47 | parserOptions: {
48 | projectService: true,
49 | tsconfigRootDir: import.meta.dirname,
50 | },
51 | },
52 | <%_ if (needsPrettier) { _%>
53 | ...prettier,
54 | <%_ } _%>
55 | },
56 | ];
57 | <%_ } else { _%>
58 | const config = [
59 | {
60 | files: ['**/*.js'],
61 | <%_ if (needsVitest) { _%>
62 | ignores: ['dist/**/*', 'coverage/**/*'],
63 | <%_ } else { _%>
64 | ignores: ['dist/**/*'],
65 | <%_ } _%>
66 | linterOptions: {
67 | reportUnusedDisableDirectives: true,
68 | },
69 | languageOptions: {
70 | globals: {
71 | ...globals.node,
72 | wx: 'readonly',
73 | getApp: 'readonly',
74 | getCurrentPages: 'readonly',
75 | },
76 | },
77 | <%_ if (needsPrettier) { _%>
78 | rules: {
79 | ...eslint.configs.recommended.rules,
80 | ...prettier.rules,
81 | },
82 | <%_ } else { _%>
83 | ...eslint.configs.recommended,
84 | <%_ } _%>
85 | },
86 | ];
87 | <%_ } _%>
88 |
89 | export default config;
90 |
--------------------------------------------------------------------------------
/template/base/package.json.ejs:
--------------------------------------------------------------------------------
1 | {
2 | "name": "<%- packageName %>",
3 | "version": "1.0.0",
4 | "private": true,
5 | "type": "module",
6 | <%_ if (packageManager) { _%>
7 | "packageManager": "<%- packageManager %>",
8 | <%_ } _%>
9 | "engines": {
10 | "node": ">=18.19.1 <19 || >=20.6.1"
11 | },
12 | "scripts": {
13 | <%_ if (needsPrettier) { _%>
14 | "format": "prettier --write \"**/*.{js<% if (needsEslint) { %>,cjs<% } %><% if (needsTypeScript) { %>,ts<% } %>,json,css,html,md}\"",
15 | <%_ } _%>
16 | <%_ if (needsEslint) { _%>
17 | "lint<% if (needsStylelint) { %>:script<% } %>": "eslint .",
18 | <%_ } _%>
19 | <%_ if (needsStylelint) { _%>
20 | "lint<% if (needsEslint) { %>:style<% } %>": "stylelint \"src/**/*.css\"",
21 | <%_ } _%>
22 | <%_ if (needsTypeScript) { _%>
23 | "type-check": "tsc",
24 | <%_ } _%>
25 | <%_ if (needsVitest) { _%>
26 | "test": "vitest",
27 | <%_ } _%>
28 | "dev": "cross-env NODE_ENV=development node build.js",
29 | "build": "cross-env NODE_ENV=production node build.js"
30 | },
31 | "dependencies": {
32 | "@babel/runtime": "^7.28.4",
33 | "@vue-mini/core": "^1.2.8",
34 | <%_ if (needsPinia) { _%>
35 | "@vue-mini/pinia": "^1.0.0",
36 | <%_ } _%>
37 | trailing-comma
38 | },
39 | "devDependencies": {
40 | "@babel/core": "^7.28.5",
41 | "@babel/plugin-transform-runtime": "^7.28.5",
42 | "@babel/preset-env": "^7.28.5",
43 | <%_ if (needsTypeScript) { _%>
44 | "@babel/preset-typescript": "^7.28.5",
45 | <%_ } _%>
46 | "@babel/traverse": "^7.28.5",
47 | "@babel/types": "^7.28.5",
48 | <%_ if (needsEslint) { _%>
49 | "@eslint/js": "^9.39.1",
50 | <%_ } _%>
51 | "@rollup/plugin-commonjs": "^29.0.0",
52 | "@rollup/plugin-node-resolve": "^16.0.3",
53 | "@rollup/plugin-replace": "^6.0.3",
54 | "@rollup/plugin-terser": "^0.4.4",
55 | <%_ if (needsTypeScript && needsVitest) { _%>
56 | "@types/node": "^24.10.1",
57 | <%_ } _%>
58 | <%_ if (needsVitest) { _%>
59 | "@vitest/coverage-v8": "^4.0.14",
60 | <%_ } _%>
61 | "babel-plugin-autocomplete-index": "^0.2.0",
62 | "babel-plugin-module-resolver": "^5.0.2",
63 | "babel-plugin-transform-inline-environment-variables": "^0.4.4",
64 | "chokidar": "^5.0.0",
65 | "cross-env": "^10.1.0",
66 | <%_ if (needsEslint) { _%>
67 | "eslint": "^9.39.1",
68 | <%_ if (needsPrettier) { _%>
69 | "eslint-config-prettier": "^10.1.8",
70 | <%_ } _%>
71 | <%_ } _%>
72 | "fs-extra": "^11.3.2",
73 | <%_ if (needsEslint) { _%>
74 | "globals": "^16.5.0",
75 | <%_ } _%>
76 | "kolorist": "^1.8.0",
77 | "local-pkg": "^1.1.2",
78 | "postcss": "^8.5.6",
79 | "postcss-load-config": "^6.0.1",
80 | "postcss-pxtorpx-pro": "^2.0.0",
81 | <%_ if (needsPrettier) { _%>
82 | "prettier": "^3.7.2",
83 | <%_ } _%>
84 | "rollup": "^4.53.3",
85 | <%_ if (needsStylelint) { _%>
86 | "stylelint": "^16.26.1",
87 | "stylelint-config-standard": "^39.0.1",
88 | <%_ } _%>
89 | "terser": "^5.44.1",
90 | <%_ if (needsTypeScript) { _%>
91 | "typescript": "^5.9.3",
92 | <%_ } _%>
93 | <%_ if (needsTypeScript && needsEslint) { _%>
94 | "typescript-eslint": "^8.48.0",
95 | <%_ } _%>
96 | <%_ if (needsVitest) { _%>
97 | "vitest": "^4.0.14",
98 | <%_ } _%>
99 | trailing-comma
100 | },
101 | "browserslist": [
102 | "iOS >= 10",
103 | "Chrome >= 63"
104 | ]
105 | }
106 |
--------------------------------------------------------------------------------
/template/javascript/build.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @version v1.4.3
3 | * https://github.com/vue-mini/create-vue-mini
4 | * 请谨慎修改此文件,改动过多可能会导致你后续升级困难。
5 | */
6 | import path from 'node:path';
7 | import process from 'node:process';
8 | import fs from 'fs-extra';
9 | import chokidar from 'chokidar';
10 | import babel from '@babel/core';
11 | import traverse from '@babel/traverse';
12 | import t from '@babel/types';
13 | import { minify } from 'terser';
14 | import postcss from 'postcss';
15 | import postcssrc from 'postcss-load-config';
16 | import { rollup } from 'rollup';
17 | import replace from '@rollup/plugin-replace';
18 | import terser from '@rollup/plugin-terser';
19 | import resolve from '@rollup/plugin-node-resolve';
20 | import commonjs from '@rollup/plugin-commonjs';
21 | import { green, bold } from 'kolorist';
22 | import { getPackageInfo } from 'local-pkg';
23 |
24 | let topLevelJobs = [];
25 | let bundleJobs = [];
26 | const startTime = Date.now();
27 | const NODE_ENV = process.env.NODE_ENV || 'production';
28 | const __PROD__ = NODE_ENV === 'production';
29 | const terserOptions = {
30 | ecma: 2016,
31 | toplevel: true,
32 | safari10: true,
33 | format: { comments: false },
34 | };
35 |
36 | let independentPackages = [];
37 | async function findIndependentPackages() {
38 | const { subpackages } = await fs.readJson(
39 | path.resolve('src', 'app.json'),
40 | 'utf8',
41 | );
42 | if (subpackages) {
43 | independentPackages = subpackages
44 | .filter(({ independent }) => independent)
45 | .map(({ root }) => root);
46 | }
47 | }
48 |
49 | const builtLibraries = [];
50 | const bundledModules = new Map();
51 | async function bundleModule(module, pkg) {
52 | const bundled = bundledModules.get(pkg);
53 | if (
54 | bundled?.has(module) ||
55 | builtLibraries.some((library) => module.startsWith(library))
56 | ) {
57 | return false;
58 | }
59 | if (bundled) {
60 | bundled.add(module);
61 | } else {
62 | bundledModules.set(pkg, new Set([module]));
63 | }
64 |
65 | const {
66 | packageJson: { peerDependencies },
67 | } = await getPackageInfo(module);
68 | const bundle = await rollup({
69 | input: module,
70 | external: peerDependencies ? Object.keys(peerDependencies) : undefined,
71 | plugins: [
72 | commonjs(),
73 | replace({
74 | preventAssignment: true,
75 | values: {
76 | 'process.env.NODE_ENV': JSON.stringify(NODE_ENV),
77 | },
78 | }),
79 | resolve(),
80 | __PROD__ && terser(terserOptions),
81 | ].filter(Boolean),
82 | });
83 | await bundle.write({
84 | exports: 'named',
85 | file: `${pkg.replace('src', 'dist')}/miniprogram_npm/${module}/index.js`,
86 | format: 'cjs',
87 | });
88 | return true;
89 | }
90 |
91 | function traverseAST(ast, pkg, babelOnly = false) {
92 | traverse.default(ast, {
93 | CallExpression({ node }) {
94 | if (
95 | node.callee.name !== 'require' ||
96 | !t.isStringLiteral(node.arguments[0]) ||
97 | node.arguments[0].value.startsWith('.') ||
98 | (babelOnly && !node.arguments[0].value.startsWith('@babel/runtime'))
99 | ) {
100 | return;
101 | }
102 |
103 | const module = node.arguments[0].value;
104 | let promise = bundleModule(module, pkg);
105 | if (babelOnly) {
106 | promise = promise.then((valid) => {
107 | if (!valid) return;
108 | return Promise.all(
109 | independentPackages.map((item) => {
110 | const bundled = bundledModules.get(item);
111 | if (bundled) {
112 | bundled.add(module);
113 | } else {
114 | bundledModules.set(pkg, new Set([module]));
115 | }
116 | return fs.copy(
117 | path.resolve('dist', 'miniprogram_npm', module),
118 | path.resolve('dist', item, 'miniprogram_npm', module),
119 | );
120 | }),
121 | );
122 | });
123 | }
124 | bundleJobs?.push(promise);
125 | },
126 | });
127 | }
128 |
129 | async function buildComponentLibrary(name) {
130 | const {
131 | rootPath,
132 | packageJson: { miniprogram },
133 | } = await getPackageInfo(name);
134 |
135 | let source = '';
136 | if (miniprogram) {
137 | source = path.join(rootPath, miniprogram);
138 | } else {
139 | try {
140 | const dist = path.join(rootPath, 'miniprogram_dist');
141 | const stats = await fs.stat(dist);
142 | if (stats.isDirectory()) {
143 | source = dist;
144 | }
145 | } catch {
146 | // Empty
147 | }
148 | }
149 |
150 | if (!source) return;
151 |
152 | builtLibraries.push(name);
153 | const destination = path.resolve('dist', 'miniprogram_npm', name);
154 | await fs.copy(source, destination);
155 |
156 | return new Promise((resolve) => {
157 | const jobs = [];
158 | const tnm = async (filePath) => {
159 | const result = await babel.transformFileAsync(filePath, { ast: true });
160 | traverseAST(result.ast, 'src', true);
161 | const code = __PROD__
162 | ? (await minify(result.code, terserOptions)).code
163 | : result.code;
164 | await fs.writeFile(filePath, code);
165 | };
166 |
167 | const watcher = chokidar.watch([destination], {
168 | ignored: (file, stats) => stats?.isFile() && !file.endsWith('.js'),
169 | });
170 | watcher.on('add', (filePath) => {
171 | const promise = tnm(filePath);
172 | jobs.push(promise);
173 | });
174 | watcher.on('ready', async () => {
175 | const promise = watcher.close();
176 | jobs.push(promise);
177 | await Promise.all(jobs);
178 | if (independentPackages.length > 0) {
179 | await Promise.all(
180 | independentPackages.map((item) =>
181 | fs.copy(
182 | destination,
183 | path.resolve('dist', item, 'miniprogram_npm', name),
184 | ),
185 | ),
186 | );
187 | }
188 | resolve();
189 | });
190 | });
191 | }
192 |
193 | async function scanDependencies() {
194 | const { dependencies } = await fs.readJson('package.json', 'utf8');
195 | for (const name of Object.keys(dependencies)) {
196 | const promise = buildComponentLibrary(name);
197 | topLevelJobs.push(promise);
198 | }
199 | }
200 |
201 | async function processScript(filePath) {
202 | let ast, code;
203 | try {
204 | const result = await babel.transformFileAsync(path.resolve(filePath), {
205 | ast: true,
206 | });
207 | ast = result.ast;
208 | code = result.code;
209 | } catch (error) {
210 | console.error(`Failed to compile ${filePath}`);
211 |
212 | if (__PROD__) throw error;
213 |
214 | console.error(error);
215 | return;
216 | }
217 |
218 | const pkg = independentPackages.find((item) =>
219 | filePath.startsWith(path.normalize(`src/${item}`)),
220 | );
221 | // The `src/` prefix is added to to distinguish `src` and `src/src`.
222 | traverseAST(ast, pkg ? `src/${pkg}` : 'src');
223 |
224 | if (__PROD__) {
225 | code = (await minify(code, terserOptions)).code;
226 | }
227 |
228 | const destination = filePath.replace('src', 'dist');
229 | // Make sure the directory already exists when write file
230 | await fs.copy(filePath, destination);
231 | await fs.writeFile(destination, code);
232 | }
233 |
234 | async function processTemplate(filePath) {
235 | const destination = filePath
236 | .replace('src', 'dist')
237 | .replace(/\.html$/, '.wxml');
238 | await fs.copy(filePath, destination);
239 | }
240 |
241 | async function processStyle(filePath) {
242 | const source = await fs.readFile(filePath, 'utf8');
243 | const { plugins, options } = await postcssrc({ from: filePath });
244 |
245 | let css;
246 | try {
247 | const result = await postcss(plugins).process(source, options);
248 | css = result.css;
249 | } catch (error) {
250 | console.error(`Failed to compile ${filePath}`);
251 |
252 | if (__PROD__) throw error;
253 |
254 | console.error(error);
255 | return;
256 | }
257 |
258 | const destination = filePath
259 | .replace('src', 'dist')
260 | .replace(/\.css$/, '.wxss');
261 | // Make sure the directory already exists when write file
262 | await fs.copy(filePath, destination);
263 | await fs.writeFile(destination, css);
264 | }
265 |
266 | const cb = async (filePath) => {
267 | if (filePath.endsWith('.js')) {
268 | await processScript(filePath);
269 | return;
270 | }
271 |
272 | if (filePath.endsWith('.html')) {
273 | await processTemplate(filePath);
274 | return;
275 | }
276 |
277 | if (filePath.endsWith('.css')) {
278 | await processStyle(filePath);
279 | return;
280 | }
281 |
282 | await fs.copy(filePath, filePath.replace('src', 'dist'));
283 | };
284 |
285 | async function dev() {
286 | await fs.remove('dist');
287 | await findIndependentPackages();
288 | await scanDependencies();
289 | chokidar
290 | .watch(['src'], {
291 | ignored: (file, stats) =>
292 | stats?.isFile() &&
293 | (file.endsWith('.gitkeep') || file.endsWith('.DS_Store')),
294 | })
295 | .on('add', (filePath) => {
296 | const promise = cb(filePath);
297 | topLevelJobs?.push(promise);
298 | })
299 | .on('change', (filePath) => {
300 | cb(filePath);
301 | })
302 | .on('ready', async () => {
303 | await Promise.all(topLevelJobs);
304 | await Promise.all(bundleJobs);
305 | console.log(bold(green(`启动完成,耗时:${Date.now() - startTime}ms`)));
306 | console.log(bold(green('监听文件变化中...')));
307 | // Release memory.
308 | topLevelJobs = null;
309 | bundleJobs = null;
310 | });
311 | }
312 |
313 | async function prod() {
314 | await fs.remove('dist');
315 | await findIndependentPackages();
316 | await scanDependencies();
317 | const watcher = chokidar.watch(['src'], {
318 | ignored: (file, stats) =>
319 | stats?.isFile() &&
320 | (file.endsWith('.gitkeep') || file.endsWith('.DS_Store')),
321 | });
322 | watcher.on('add', (filePath) => {
323 | const promise = cb(filePath);
324 | topLevelJobs.push(promise);
325 | });
326 | watcher.on('ready', async () => {
327 | const promise = watcher.close();
328 | topLevelJobs.push(promise);
329 | await Promise.all(topLevelJobs);
330 | await Promise.all(bundleJobs);
331 | console.log(bold(green(`构建完成,耗时:${Date.now() - startTime}ms`)));
332 | });
333 | }
334 |
335 | if (__PROD__) {
336 | await prod();
337 | } else {
338 | await dev();
339 | }
340 |
--------------------------------------------------------------------------------
/template/typescript/build.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @version v1.4.3
3 | * https://github.com/vue-mini/create-vue-mini
4 | * 请谨慎修改此文件,改动过多可能会导致你后续升级困难。
5 | */
6 | import path from 'node:path';
7 | import process from 'node:process';
8 | import fs from 'fs-extra';
9 | import chokidar from 'chokidar';
10 | import babel from '@babel/core';
11 | import traverse from '@babel/traverse';
12 | import t from '@babel/types';
13 | import { minify } from 'terser';
14 | import postcss from 'postcss';
15 | import postcssrc from 'postcss-load-config';
16 | import { rollup } from 'rollup';
17 | import replace from '@rollup/plugin-replace';
18 | import terser from '@rollup/plugin-terser';
19 | import resolve from '@rollup/plugin-node-resolve';
20 | import commonjs from '@rollup/plugin-commonjs';
21 | import { green, bold } from 'kolorist';
22 | import { getPackageInfo } from 'local-pkg';
23 |
24 | let topLevelJobs = [];
25 | let bundleJobs = [];
26 | const startTime = Date.now();
27 | const NODE_ENV = process.env.NODE_ENV || 'production';
28 | const __PROD__ = NODE_ENV === 'production';
29 | const terserOptions = {
30 | ecma: 2016,
31 | toplevel: true,
32 | safari10: true,
33 | format: { comments: false },
34 | };
35 |
36 | let independentPackages = [];
37 | async function findIndependentPackages() {
38 | const { subpackages } = await fs.readJson(
39 | path.resolve('src', 'app.json'),
40 | 'utf8',
41 | );
42 | if (subpackages) {
43 | independentPackages = subpackages
44 | .filter(({ independent }) => independent)
45 | .map(({ root }) => root);
46 | }
47 | }
48 |
49 | const builtLibraries = [];
50 | const bundledModules = new Map();
51 | async function bundleModule(module, pkg) {
52 | const bundled = bundledModules.get(pkg);
53 | if (
54 | bundled?.has(module) ||
55 | builtLibraries.some((library) => module.startsWith(library))
56 | ) {
57 | return false;
58 | }
59 | if (bundled) {
60 | bundled.add(module);
61 | } else {
62 | bundledModules.set(pkg, new Set([module]));
63 | }
64 |
65 | const {
66 | packageJson: { peerDependencies },
67 | } = await getPackageInfo(module);
68 | const bundle = await rollup({
69 | input: module,
70 | external: peerDependencies ? Object.keys(peerDependencies) : undefined,
71 | plugins: [
72 | commonjs(),
73 | replace({
74 | preventAssignment: true,
75 | values: {
76 | 'process.env.NODE_ENV': JSON.stringify(NODE_ENV),
77 | },
78 | }),
79 | resolve(),
80 | __PROD__ && terser(terserOptions),
81 | ].filter(Boolean),
82 | });
83 | await bundle.write({
84 | exports: 'named',
85 | file: `${pkg.replace('src', 'dist')}/miniprogram_npm/${module}/index.js`,
86 | format: 'cjs',
87 | });
88 | return true;
89 | }
90 |
91 | function traverseAST(ast, pkg, babelOnly = false) {
92 | traverse.default(ast, {
93 | CallExpression({ node }) {
94 | if (
95 | node.callee.name !== 'require' ||
96 | !t.isStringLiteral(node.arguments[0]) ||
97 | node.arguments[0].value.startsWith('.') ||
98 | (babelOnly && !node.arguments[0].value.startsWith('@babel/runtime'))
99 | ) {
100 | return;
101 | }
102 |
103 | const module = node.arguments[0].value;
104 | let promise = bundleModule(module, pkg);
105 | if (babelOnly) {
106 | promise = promise.then((valid) => {
107 | if (!valid) return;
108 | return Promise.all(
109 | independentPackages.map((item) => {
110 | const bundled = bundledModules.get(item);
111 | if (bundled) {
112 | bundled.add(module);
113 | } else {
114 | bundledModules.set(pkg, new Set([module]));
115 | }
116 | return fs.copy(
117 | path.resolve('dist', 'miniprogram_npm', module),
118 | path.resolve('dist', item, 'miniprogram_npm', module),
119 | );
120 | }),
121 | );
122 | });
123 | }
124 | bundleJobs?.push(promise);
125 | },
126 | });
127 | }
128 |
129 | async function buildComponentLibrary(name) {
130 | const {
131 | rootPath,
132 | packageJson: { miniprogram },
133 | } = await getPackageInfo(name);
134 |
135 | let source = '';
136 | if (miniprogram) {
137 | source = path.join(rootPath, miniprogram);
138 | } else {
139 | try {
140 | const dist = path.join(rootPath, 'miniprogram_dist');
141 | const stats = await fs.stat(dist);
142 | if (stats.isDirectory()) {
143 | source = dist;
144 | }
145 | } catch {
146 | // Empty
147 | }
148 | }
149 |
150 | if (!source) return;
151 |
152 | builtLibraries.push(name);
153 | const destination = path.resolve('dist', 'miniprogram_npm', name);
154 | await fs.copy(source, destination);
155 |
156 | return new Promise((resolve) => {
157 | const jobs = [];
158 | const tnm = async (filePath) => {
159 | const result = await babel.transformFileAsync(filePath, { ast: true });
160 | traverseAST(result.ast, 'src', true);
161 | const code = __PROD__
162 | ? (await minify(result.code, terserOptions)).code
163 | : result.code;
164 | await fs.writeFile(filePath, code);
165 | };
166 |
167 | const watcher = chokidar.watch([destination], {
168 | ignored: (file, stats) => stats?.isFile() && !file.endsWith('.js'),
169 | });
170 | watcher.on('add', (filePath) => {
171 | const promise = tnm(filePath);
172 | jobs.push(promise);
173 | });
174 | watcher.on('ready', async () => {
175 | const promise = watcher.close();
176 | jobs.push(promise);
177 | await Promise.all(jobs);
178 | if (independentPackages.length > 0) {
179 | await Promise.all(
180 | independentPackages.map((item) =>
181 | fs.copy(
182 | destination,
183 | path.resolve('dist', item, 'miniprogram_npm', name),
184 | ),
185 | ),
186 | );
187 | }
188 | resolve();
189 | });
190 | });
191 | }
192 |
193 | async function scanDependencies() {
194 | const { dependencies } = await fs.readJson('package.json', 'utf8');
195 | for (const name of Object.keys(dependencies)) {
196 | const promise = buildComponentLibrary(name);
197 | topLevelJobs.push(promise);
198 | }
199 | }
200 |
201 | async function processScript(filePath) {
202 | let ast, code;
203 | try {
204 | const result = await babel.transformFileAsync(path.resolve(filePath), {
205 | ast: true,
206 | });
207 | ast = result.ast;
208 | code = result.code;
209 | } catch (error) {
210 | console.error(`Failed to compile ${filePath}`);
211 |
212 | if (__PROD__) throw error;
213 |
214 | console.error(error);
215 | return;
216 | }
217 |
218 | const pkg = independentPackages.find((item) =>
219 | filePath.startsWith(path.normalize(`src/${item}`)),
220 | );
221 | // The `src/` prefix is added to to distinguish `src` and `src/src`.
222 | traverseAST(ast, pkg ? `src/${pkg}` : 'src');
223 |
224 | if (__PROD__) {
225 | code = (await minify(code, terserOptions)).code;
226 | }
227 |
228 | const destination = filePath.replace('src', 'dist').replace(/\.ts$/, '.js');
229 | // Make sure the directory already exists when write file
230 | await fs.copy(filePath, destination);
231 | await fs.writeFile(destination, code);
232 | }
233 |
234 | async function processTemplate(filePath) {
235 | const destination = filePath
236 | .replace('src', 'dist')
237 | .replace(/\.html$/, '.wxml');
238 | await fs.copy(filePath, destination);
239 | }
240 |
241 | async function processStyle(filePath) {
242 | const source = await fs.readFile(filePath, 'utf8');
243 | const { plugins, options } = await postcssrc({ from: filePath });
244 |
245 | let css;
246 | try {
247 | const result = await postcss(plugins).process(source, options);
248 | css = result.css;
249 | } catch (error) {
250 | console.error(`Failed to compile ${filePath}`);
251 |
252 | if (__PROD__) throw error;
253 |
254 | console.error(error);
255 | return;
256 | }
257 |
258 | const destination = filePath
259 | .replace('src', 'dist')
260 | .replace(/\.css$/, '.wxss');
261 | // Make sure the directory already exists when write file
262 | await fs.copy(filePath, destination);
263 | await fs.writeFile(destination, css);
264 | }
265 |
266 | const cb = async (filePath) => {
267 | if (filePath.endsWith('.ts') || filePath.endsWith('.js')) {
268 | await processScript(filePath);
269 | return;
270 | }
271 |
272 | if (filePath.endsWith('.html')) {
273 | await processTemplate(filePath);
274 | return;
275 | }
276 |
277 | if (filePath.endsWith('.css')) {
278 | await processStyle(filePath);
279 | return;
280 | }
281 |
282 | await fs.copy(filePath, filePath.replace('src', 'dist'));
283 | };
284 |
285 | async function dev() {
286 | await fs.remove('dist');
287 | await findIndependentPackages();
288 | await scanDependencies();
289 | chokidar
290 | .watch(['src'], {
291 | ignored: (file, stats) =>
292 | stats?.isFile() &&
293 | (file.endsWith('.gitkeep') || file.endsWith('.DS_Store')),
294 | })
295 | .on('add', (filePath) => {
296 | const promise = cb(filePath);
297 | topLevelJobs?.push(promise);
298 | })
299 | .on('change', (filePath) => {
300 | cb(filePath);
301 | })
302 | .on('ready', async () => {
303 | await Promise.all(topLevelJobs);
304 | await Promise.all(bundleJobs);
305 | console.log(bold(green(`启动完成,耗时:${Date.now() - startTime}ms`)));
306 | console.log(bold(green('监听文件变化中...')));
307 | // Release memory.
308 | topLevelJobs = null;
309 | bundleJobs = null;
310 | });
311 | }
312 |
313 | async function prod() {
314 | await fs.remove('dist');
315 | await findIndependentPackages();
316 | await scanDependencies();
317 | const watcher = chokidar.watch(['src'], {
318 | ignored: (file, stats) =>
319 | stats?.isFile() &&
320 | (file.endsWith('.gitkeep') || file.endsWith('.DS_Store')),
321 | });
322 | watcher.on('add', (filePath) => {
323 | const promise = cb(filePath);
324 | topLevelJobs.push(promise);
325 | });
326 | watcher.on('ready', async () => {
327 | const promise = watcher.close();
328 | topLevelJobs.push(promise);
329 | await Promise.all(topLevelJobs);
330 | await Promise.all(bundleJobs);
331 | console.log(bold(green(`构建完成,耗时:${Date.now() - startTime}ms`)));
332 | });
333 | }
334 |
335 | if (__PROD__) {
336 | await prod();
337 | } else {
338 | await dev();
339 | }
340 |
--------------------------------------------------------------------------------
/index.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /* eslint-disable @typescript-eslint/no-unsafe-member-access */
4 | /* eslint-disable @typescript-eslint/no-unsafe-assignment */
5 | import fs from 'node:fs'
6 | import path from 'node:path'
7 | import process from 'node:process'
8 | import { fileURLToPath } from 'node:url'
9 | import ejs from 'ejs'
10 | import prompts from 'prompts'
11 | import { red, green, bold } from 'kolorist'
12 |
13 | const defaultBanner = 'Vue Mini - 简单,强大,高性能的小程序框架'
14 |
15 | // Generated by the following code:
16 | //
17 | // require('gradient-string')([
18 | // { color: '#42d392', pos: 0 },
19 | // { color: '#42d392', pos: 0.1 },
20 | // { color: '#647eff', pos: 1 }
21 | // ])('Vue Mini - 简单,强大,高性能的小程序框架')
22 | //
23 | // Use the output directly here to keep the bundle small.
24 | const gradientBanner =
25 | '\u001B[38;2;66;211;146mV\u001B[39m\u001B[38;2;66;211;146mu\u001B[39m\u001B[38;2;66;211;146me\u001B[39m \u001B[38;2;68;207;151mM\u001B[39m\u001B[38;2;69;203;157mi\u001B[39m\u001B[38;2;71;198;162mn\u001B[39m\u001B[38;2;73;194;168mi\u001B[39m \u001B[38;2;75;190;173m-\u001B[39m \u001B[38;2;76;186;179m简\u001B[39m\u001B[38;2;78;181;184m单\u001B[39m\u001B[38;2;80;177;190m,\u001B[39m\u001B[38;2;81;173;195m强\u001B[39m\u001B[38;2;83;169;201m大\u001B[39m\u001B[38;2;85;164;206m,\u001B[39m\u001B[38;2;86;160;211m高\u001B[39m\u001B[38;2;88;156;217m性\u001B[39m\u001B[38;2;90;152;222m能\u001B[39m\u001B[38;2;92;147;228m的\u001B[39m\u001B[38;2;93;143;233m小\u001B[39m\u001B[38;2;95;139;239m程\u001B[39m\u001B[38;2;97;135;244m序\u001B[39m\u001B[38;2;98;130;250m框\u001B[39m\u001B[38;2;100;126;255m架\u001B[39m'
26 |
27 | function postOrderDirectoryTraverse(
28 | dir: string,
29 | dirCallback: (dir: string) => void,
30 | fileCallback: (file: string) => void,
31 | ) {
32 | for (const filename of fs.readdirSync(dir)) {
33 | if (filename === '.git') {
34 | continue
35 | }
36 |
37 | const fullpath = path.resolve(dir, filename)
38 | if (fs.lstatSync(fullpath).isDirectory()) {
39 | postOrderDirectoryTraverse(fullpath, dirCallback, fileCallback)
40 | dirCallback(fullpath)
41 | continue
42 | }
43 |
44 | fileCallback(fullpath)
45 | }
46 | }
47 |
48 | function isValidPackageName(projectName: string) {
49 | return /^(?:@[a-z\d-*~][a-z\d-*._~]*\/)?[a-z\d-~][a-z\d-._~]*$/.test(
50 | projectName,
51 | )
52 | }
53 |
54 | function toValidPackageName(projectName: string) {
55 | return projectName
56 | .trim()
57 | .toLowerCase()
58 | .replaceAll(/\s+/g, '-')
59 | .replace(/^[._]/, '')
60 | .replaceAll(/[^a-z\d-~]+/g, '-')
61 | }
62 |
63 | function canSkipEmptying(dir: string) {
64 | if (!fs.existsSync(dir)) {
65 | return true
66 | }
67 |
68 | const files = fs.readdirSync(dir)
69 | if (files.length === 0) {
70 | return true
71 | }
72 |
73 | if (files.length === 1 && files[0] === '.git') {
74 | return true
75 | }
76 |
77 | return false
78 | }
79 |
80 | function emptyDir(dir: string) {
81 | if (!fs.existsSync(dir)) {
82 | return
83 | }
84 |
85 | postOrderDirectoryTraverse(
86 | dir,
87 | (dir) => {
88 | fs.rmdirSync(dir)
89 | },
90 | (file) => {
91 | fs.unlinkSync(file)
92 | },
93 | )
94 | }
95 |
96 | type Result = {
97 | projectName?: string
98 | shouldOverwrite?: boolean
99 | packageName?: string
100 | needsTypeScript?: boolean
101 | needsPinia?: boolean
102 | needsVitest?: boolean
103 | needsEslint?: boolean
104 | needsStylelint?: boolean
105 | needsPrettier?: boolean
106 | }
107 |
108 | function renderTemplate(
109 | src: string,
110 | dest: string,
111 | result: Required> & {
112 | packageManager: string
113 | },
114 | ) {
115 | const stats = fs.statSync(src)
116 |
117 | if (stats.isDirectory()) {
118 | // If it's a directory, render its subdirectories and files recursively
119 | fs.mkdirSync(dest, { recursive: true })
120 | for (const file of fs.readdirSync(src)) {
121 | renderTemplate(
122 | path.resolve(src, file),
123 | path.resolve(
124 | dest,
125 | /^_[a-z]/.test(file) ? file.replace('_', '.') : file,
126 | ),
127 | result,
128 | )
129 | }
130 |
131 | return
132 | }
133 |
134 | const filename = path.basename(src)
135 |
136 | if (filename.endsWith('.ejs')) {
137 | const template = fs.readFileSync(src, 'utf8')
138 | let content = ejs.render(template, result)
139 |
140 | if (filename === 'package.json.ejs') {
141 | content = content.replaceAll(',\n trailing-comma', '')
142 | }
143 |
144 | fs.writeFileSync(dest.replace(/\.ejs$/, ''), content)
145 | return
146 | }
147 |
148 | if (filename === 'project.config.json') {
149 | const project = JSON.parse(fs.readFileSync(src, 'utf8'))
150 | project.projectname = result.packageName
151 | fs.writeFileSync(dest, JSON.stringify(project, null, 2) + '\n')
152 | return
153 | }
154 |
155 | if (filename === 'app.json') {
156 | const app = JSON.parse(fs.readFileSync(src, 'utf8'))
157 | app.window.navigationBarTitleText = result.packageName
158 | fs.writeFileSync(dest, JSON.stringify(app, null, 2) + '\n')
159 | return
160 | }
161 |
162 | fs.copyFileSync(src, dest)
163 | }
164 |
165 | function getCommand(packageManager: string, scriptName: string) {
166 | if (scriptName === 'install') {
167 | return packageManager === 'yarn' ? 'yarn' : `${packageManager} install`
168 | }
169 |
170 | return ['npm', 'bun'].includes(packageManager) ?
171 | `${packageManager} run ${scriptName}`
172 | : `${packageManager} ${scriptName}`
173 | }
174 |
175 | function generateReadme({
176 | packageManager,
177 | projectName,
178 | needsTypeScript,
179 | needsVitest,
180 | needsEslint,
181 | needsStylelint,
182 | needsPrettier,
183 | }: { packageManager: string } & Required<
184 | Omit
185 | >) {
186 | let readme = `# ${projectName}
187 |
188 | ⚠️ 注意:将此项目导入微信开发者工具时请选择项目根目录而非 \`dist\` 目录。
189 |
190 | 更多信息请访问官方文档:[vuemini.org](https://vuemini.org)
191 |
192 | ## 依赖安装
193 |
194 | \`\`\`sh
195 | ${getCommand(packageManager, 'install')}
196 | \`\`\`
197 |
198 | ## 本地开发
199 |
200 | \`\`\`sh
201 | ${getCommand(packageManager, 'dev')}
202 | \`\`\`
203 |
204 | ## 生产构建
205 |
206 | \`\`\`sh
207 | ${getCommand(packageManager, 'build')}
208 | \`\`\`
209 | `
210 |
211 | if (needsPrettier) {
212 | readme += `
213 | ## 代码格式化
214 |
215 | \`\`\`sh
216 | ${getCommand(packageManager, 'format')}
217 | \`\`\`
218 | `
219 | }
220 |
221 | if (needsEslint) {
222 | readme += `
223 | ## ${needsTypeScript ? 'TS' : 'JS'} 代码质量检测
224 |
225 | \`\`\`sh
226 | ${getCommand(packageManager, needsStylelint ? 'lint:script' : 'lint')}
227 | \`\`\`
228 | `
229 | }
230 |
231 | if (needsStylelint) {
232 | readme += `
233 | ## CSS 代码质量检测
234 |
235 | \`\`\`sh
236 | ${getCommand(packageManager, needsEslint ? 'lint:style' : 'lint')}
237 | \`\`\`
238 | `
239 | }
240 |
241 | if (needsTypeScript) {
242 | readme += `
243 | ## 类型检测
244 |
245 | \`\`\`sh
246 | ${getCommand(packageManager, 'type-check')}
247 | \`\`\`
248 | `
249 | }
250 |
251 | if (needsVitest) {
252 | readme += `
253 | ## 单元测试
254 |
255 | \`\`\`sh
256 | ${getCommand(packageManager, 'test')}
257 | \`\`\`
258 | `
259 | }
260 |
261 | return readme
262 | }
263 |
264 | async function init() {
265 | console.log()
266 | console.log(
267 | process.stdout.isTTY && process.stdout.getColorDepth() > 8 ?
268 | gradientBanner
269 | : defaultBanner,
270 | )
271 | console.log()
272 |
273 | const cwd = process.cwd()
274 | let targetDir = process.argv[2]
275 | const defaultProjectName = targetDir ?? 'vue-mini-project'
276 |
277 | let result: Result = {}
278 |
279 | try {
280 | // Prompts:
281 | // - Project name:
282 | // - whether to overwrite the existing directory or not?
283 | // - enter a valid package name for package.json
284 | result = await prompts(
285 | [
286 | {
287 | name: 'projectName',
288 | type: targetDir ? null : 'text',
289 | message: '请输入项目名称:',
290 | initial: defaultProjectName,
291 | onState(state) {
292 | targetDir = String(state.value).trim() || defaultProjectName
293 | },
294 | },
295 | {
296 | name: 'shouldOverwrite',
297 | type: () => (canSkipEmptying(targetDir) ? null : 'toggle'),
298 | message() {
299 | const dirForPrompt =
300 | targetDir === '.' ? '当前目录' : `目标文件夹 "${targetDir}"`
301 |
302 | return `${dirForPrompt} 非空,是否覆盖?`
303 | },
304 | initial: true,
305 | active: '是',
306 | inactive: '否',
307 | },
308 | {
309 | name: 'overwriteChecker',
310 | type(_, values) {
311 | if (values.shouldOverwrite === false) {
312 | throw new Error(red('✖') + ` 操作取消`)
313 | }
314 |
315 | return null
316 | },
317 | },
318 | {
319 | name: 'packageName',
320 | type: () => (isValidPackageName(targetDir) ? null : 'text'),
321 | message: '请输入包名称:',
322 | initial: () => toValidPackageName(targetDir),
323 | validate: (dir: string) =>
324 | isValidPackageName(dir) || '无效的 package.json 名称',
325 | },
326 | {
327 | name: 'needsTypeScript',
328 | type: 'toggle',
329 | message: '是否使用 TypeScript 语法?',
330 | initial: false,
331 | active: '是',
332 | inactive: '否',
333 | },
334 | {
335 | name: 'needsPinia',
336 | type: 'toggle',
337 | message: '是否引入 Pinia 用于状态管理?',
338 | initial: false,
339 | active: '是',
340 | inactive: '否',
341 | },
342 | {
343 | name: 'needsVitest',
344 | type: 'toggle',
345 | message: '是否引入 Vitest 用于单元测试?',
346 | initial: false,
347 | active: '是',
348 | inactive: '否',
349 | },
350 | {
351 | name: 'needsEslint',
352 | type: 'toggle',
353 | message: (_, values) =>
354 | `是否引入 ESLint 用于 ${values.needsTypeScript ? 'TS' : 'JS'} 代码质量检测?`,
355 | initial: false,
356 | active: '是',
357 | inactive: '否',
358 | },
359 | {
360 | name: 'needsStylelint',
361 | type: 'toggle',
362 | message: '是否引入 Stylelint 用于 CSS 代码质量检测?',
363 | initial: false,
364 | active: '是',
365 | inactive: '否',
366 | },
367 | {
368 | name: 'needsPrettier',
369 | type: 'toggle',
370 | message: '是否引入 Prettier 用于代码格式化?',
371 | initial: false,
372 | active: '是',
373 | inactive: '否',
374 | },
375 | ],
376 | {
377 | onCancel() {
378 | throw new Error(red('✖') + ` 操作取消`)
379 | },
380 | },
381 | )
382 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
383 | } catch (error: any) {
384 | console.error(error.message)
385 | process.exit(1)
386 | }
387 |
388 | // `initial` won't take effect if the prompt type is null
389 | // so we still have to assign the default values here
390 | const {
391 | projectName,
392 | shouldOverwrite = false,
393 | packageName = projectName ?? defaultProjectName,
394 | needsTypeScript = false,
395 | needsPinia = false,
396 | needsVitest = false,
397 | needsEslint = false,
398 | needsStylelint = false,
399 | needsPrettier = false,
400 | } = result
401 |
402 | const root = path.join(cwd, targetDir)
403 |
404 | if (fs.existsSync(root) && shouldOverwrite) {
405 | emptyDir(root)
406 | } else if (!fs.existsSync(root)) {
407 | fs.mkdirSync(root)
408 | }
409 |
410 | console.log(`\n正在初始化项目 ${root}...`)
411 |
412 | const templateRoot = fileURLToPath(new URL('template', import.meta.url))
413 |
414 | // Instructions:
415 | // Supported package managers: pnpm > yarn > npm
416 | const userAgent = process.env.npm_config_user_agent ?? ''
417 | const packageManager =
418 | userAgent.includes('pnpm') ? 'pnpm'
419 | : userAgent.includes('yarn') ? 'yarn'
420 | : userAgent.includes('bun') ? 'bun'
421 | : 'npm'
422 |
423 | const render = (templateName: string) => {
424 | renderTemplate(path.resolve(templateRoot, templateName), root, {
425 | packageName,
426 | needsTypeScript,
427 | needsPinia,
428 | needsVitest,
429 | needsEslint,
430 | needsStylelint,
431 | needsPrettier,
432 | packageManager:
433 | ['npm', 'bun'].includes(packageManager) ? '' : (
434 | userAgent.split(' ')[0].replace('/', '@')
435 | ),
436 | })
437 | }
438 |
439 | render('base')
440 |
441 | if (needsTypeScript) {
442 | render('typescript')
443 | } else {
444 | render('javascript')
445 | }
446 |
447 | if (needsPinia) {
448 | if (needsTypeScript) {
449 | render('pinia-typescript')
450 | } else {
451 | render('pinia')
452 | }
453 | }
454 |
455 | if (needsEslint) {
456 | render('eslint')
457 | }
458 |
459 | if (needsStylelint) {
460 | render('stylelint')
461 | }
462 |
463 | if (needsPrettier) {
464 | render('prettier')
465 | }
466 |
467 | // Vitest should be the last one to render.
468 | if (needsVitest) {
469 | if (packageManager === 'pnpm') {
470 | render('vitest-pnpm')
471 | }
472 |
473 | if (needsTypeScript) {
474 | render('vitest-typescript')
475 | } else {
476 | render('vitest')
477 | }
478 | }
479 |
480 | fs.writeFileSync(
481 | path.resolve(root, 'README.md'),
482 | generateReadme({
483 | packageManager,
484 | projectName: projectName ?? packageName ?? defaultProjectName,
485 | needsTypeScript,
486 | needsPinia,
487 | needsVitest,
488 | needsEslint,
489 | needsStylelint,
490 | needsPrettier,
491 | }),
492 | )
493 |
494 | console.log(`\n项目初始化完成,可执行以下命令:\n`)
495 | if (root !== cwd) {
496 | const cdProjectName = path.relative(cwd, root)
497 | console.log(
498 | ` ${bold(green(`cd ${cdProjectName.includes(' ') ? `"${cdProjectName}"` : cdProjectName}`))}`,
499 | )
500 | }
501 |
502 | console.log(` ${bold(green(getCommand(packageManager, 'install')))}`)
503 |
504 | if (needsPrettier) {
505 | console.log(` ${bold(green(getCommand(packageManager, 'format')))}`)
506 | }
507 |
508 | console.log(` ${bold(green(getCommand(packageManager, 'dev')))}`)
509 | console.log()
510 | }
511 |
512 | try {
513 | await init()
514 | } catch (error) {
515 | console.error(error)
516 | }
517 |
--------------------------------------------------------------------------------
/pnpm-lock.yaml:
--------------------------------------------------------------------------------
1 | lockfileVersion: '9.0'
2 |
3 | settings:
4 | autoInstallPeers: true
5 | excludeLinksFromLockfile: false
6 |
7 | importers:
8 |
9 | .:
10 | dependencies:
11 | ejs:
12 | specifier: ^3.1.10
13 | version: 3.1.10
14 | kolorist:
15 | specifier: ^1.8.0
16 | version: 1.8.0
17 | prompts:
18 | specifier: ^2.4.2
19 | version: 2.4.2
20 | devDependencies:
21 | '@eslint/js':
22 | specifier: ^9.39.1
23 | version: 9.39.1
24 | '@types/ejs':
25 | specifier: ^3.1.5
26 | version: 3.1.5
27 | '@types/node':
28 | specifier: ^24.10.1
29 | version: 24.10.1
30 | '@types/prompts':
31 | specifier: ^2.4.9
32 | version: 2.4.9
33 | eslint:
34 | specifier: ^9.39.1
35 | version: 9.39.1
36 | prettier:
37 | specifier: ^3.7.2
38 | version: 3.7.2
39 | typescript:
40 | specifier: ^5.9.3
41 | version: 5.9.3
42 | typescript-eslint:
43 | specifier: ^8.48.0
44 | version: 8.48.0(eslint@9.39.1)(typescript@5.9.3)
45 |
46 | packages:
47 |
48 | '@eslint-community/eslint-utils@4.9.0':
49 | resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==}
50 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
51 | peerDependencies:
52 | eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
53 |
54 | '@eslint-community/regexpp@4.12.2':
55 | resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==}
56 | engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
57 |
58 | '@eslint/config-array@0.21.1':
59 | resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==}
60 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
61 |
62 | '@eslint/config-helpers@0.4.2':
63 | resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==}
64 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
65 |
66 | '@eslint/core@0.17.0':
67 | resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==}
68 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
69 |
70 | '@eslint/eslintrc@3.3.3':
71 | resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==}
72 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
73 |
74 | '@eslint/js@9.39.1':
75 | resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==}
76 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
77 |
78 | '@eslint/object-schema@2.1.7':
79 | resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==}
80 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
81 |
82 | '@eslint/plugin-kit@0.4.1':
83 | resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==}
84 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
85 |
86 | '@humanfs/core@0.19.1':
87 | resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
88 | engines: {node: '>=18.18.0'}
89 |
90 | '@humanfs/node@0.16.7':
91 | resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==}
92 | engines: {node: '>=18.18.0'}
93 |
94 | '@humanwhocodes/module-importer@1.0.1':
95 | resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
96 | engines: {node: '>=12.22'}
97 |
98 | '@humanwhocodes/retry@0.4.3':
99 | resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
100 | engines: {node: '>=18.18'}
101 |
102 | '@types/ejs@3.1.5':
103 | resolution: {integrity: sha512-nv+GSx77ZtXiJzwKdsASqi+YQ5Z7vwHsTP0JY2SiQgjGckkBRKZnk8nIM+7oUZ1VCtuTz0+By4qVR7fqzp/Dfg==}
104 |
105 | '@types/estree@1.0.8':
106 | resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
107 |
108 | '@types/json-schema@7.0.15':
109 | resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
110 |
111 | '@types/node@24.10.1':
112 | resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==}
113 |
114 | '@types/prompts@2.4.9':
115 | resolution: {integrity: sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==}
116 |
117 | '@typescript-eslint/eslint-plugin@8.48.0':
118 | resolution: {integrity: sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ==}
119 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
120 | peerDependencies:
121 | '@typescript-eslint/parser': ^8.48.0
122 | eslint: ^8.57.0 || ^9.0.0
123 | typescript: '>=4.8.4 <6.0.0'
124 |
125 | '@typescript-eslint/parser@8.48.0':
126 | resolution: {integrity: sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==}
127 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
128 | peerDependencies:
129 | eslint: ^8.57.0 || ^9.0.0
130 | typescript: '>=4.8.4 <6.0.0'
131 |
132 | '@typescript-eslint/project-service@8.48.0':
133 | resolution: {integrity: sha512-Ne4CTZyRh1BecBf84siv42wv5vQvVmgtk8AuiEffKTUo3DrBaGYZueJSxxBZ8fjk/N3DrgChH4TOdIOwOwiqqw==}
134 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
135 | peerDependencies:
136 | typescript: '>=4.8.4 <6.0.0'
137 |
138 | '@typescript-eslint/scope-manager@8.48.0':
139 | resolution: {integrity: sha512-uGSSsbrtJrLduti0Q1Q9+BF1/iFKaxGoQwjWOIVNJv0o6omrdyR8ct37m4xIl5Zzpkp69Kkmvom7QFTtue89YQ==}
140 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
141 |
142 | '@typescript-eslint/tsconfig-utils@8.48.0':
143 | resolution: {integrity: sha512-WNebjBdFdyu10sR1M4OXTt2OkMd5KWIL+LLfeH9KhgP+jzfDV/LI3eXzwJ1s9+Yc0Kzo2fQCdY/OpdusCMmh6w==}
144 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
145 | peerDependencies:
146 | typescript: '>=4.8.4 <6.0.0'
147 |
148 | '@typescript-eslint/type-utils@8.48.0':
149 | resolution: {integrity: sha512-zbeVaVqeXhhab6QNEKfK96Xyc7UQuoFWERhEnj3mLVnUWrQnv15cJNseUni7f3g557gm0e46LZ6IJ4NJVOgOpw==}
150 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
151 | peerDependencies:
152 | eslint: ^8.57.0 || ^9.0.0
153 | typescript: '>=4.8.4 <6.0.0'
154 |
155 | '@typescript-eslint/types@8.48.0':
156 | resolution: {integrity: sha512-cQMcGQQH7kwKoVswD1xdOytxQR60MWKM1di26xSUtxehaDs/32Zpqsu5WJlXTtTTqyAVK8R7hvsUnIXRS+bjvA==}
157 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
158 |
159 | '@typescript-eslint/typescript-estree@8.48.0':
160 | resolution: {integrity: sha512-ljHab1CSO4rGrQIAyizUS6UGHHCiAYhbfcIZ1zVJr5nMryxlXMVWS3duFPSKvSUbFPwkXMFk1k0EMIjub4sRRQ==}
161 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
162 | peerDependencies:
163 | typescript: '>=4.8.4 <6.0.0'
164 |
165 | '@typescript-eslint/utils@8.48.0':
166 | resolution: {integrity: sha512-yTJO1XuGxCsSfIVt1+1UrLHtue8xz16V8apzPYI06W0HbEbEWHxHXgZaAgavIkoh+GeV6hKKd5jm0sS6OYxWXQ==}
167 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
168 | peerDependencies:
169 | eslint: ^8.57.0 || ^9.0.0
170 | typescript: '>=4.8.4 <6.0.0'
171 |
172 | '@typescript-eslint/visitor-keys@8.48.0':
173 | resolution: {integrity: sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg==}
174 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
175 |
176 | acorn-jsx@5.3.2:
177 | resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
178 | peerDependencies:
179 | acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
180 |
181 | acorn@8.15.0:
182 | resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
183 | engines: {node: '>=0.4.0'}
184 | hasBin: true
185 |
186 | ajv@6.12.6:
187 | resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
188 |
189 | ansi-styles@4.3.0:
190 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
191 | engines: {node: '>=8'}
192 |
193 | argparse@2.0.1:
194 | resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
195 |
196 | async@3.2.6:
197 | resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
198 |
199 | balanced-match@1.0.2:
200 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
201 |
202 | brace-expansion@1.1.12:
203 | resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==}
204 |
205 | brace-expansion@2.0.2:
206 | resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
207 |
208 | callsites@3.1.0:
209 | resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
210 | engines: {node: '>=6'}
211 |
212 | chalk@4.1.2:
213 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
214 | engines: {node: '>=10'}
215 |
216 | color-convert@2.0.1:
217 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
218 | engines: {node: '>=7.0.0'}
219 |
220 | color-name@1.1.4:
221 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
222 |
223 | concat-map@0.0.1:
224 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
225 |
226 | cross-spawn@7.0.6:
227 | resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
228 | engines: {node: '>= 8'}
229 |
230 | debug@4.4.3:
231 | resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
232 | engines: {node: '>=6.0'}
233 | peerDependencies:
234 | supports-color: '*'
235 | peerDependenciesMeta:
236 | supports-color:
237 | optional: true
238 |
239 | deep-is@0.1.4:
240 | resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
241 |
242 | ejs@3.1.10:
243 | resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==}
244 | engines: {node: '>=0.10.0'}
245 | hasBin: true
246 |
247 | escape-string-regexp@4.0.0:
248 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
249 | engines: {node: '>=10'}
250 |
251 | eslint-scope@8.4.0:
252 | resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==}
253 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
254 |
255 | eslint-visitor-keys@3.4.3:
256 | resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
257 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
258 |
259 | eslint-visitor-keys@4.2.1:
260 | resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==}
261 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
262 |
263 | eslint@9.39.1:
264 | resolution: {integrity: sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==}
265 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
266 | hasBin: true
267 | peerDependencies:
268 | jiti: '*'
269 | peerDependenciesMeta:
270 | jiti:
271 | optional: true
272 |
273 | espree@10.4.0:
274 | resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==}
275 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
276 |
277 | esquery@1.6.0:
278 | resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
279 | engines: {node: '>=0.10'}
280 |
281 | esrecurse@4.3.0:
282 | resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
283 | engines: {node: '>=4.0'}
284 |
285 | estraverse@5.3.0:
286 | resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
287 | engines: {node: '>=4.0'}
288 |
289 | esutils@2.0.3:
290 | resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
291 | engines: {node: '>=0.10.0'}
292 |
293 | fast-deep-equal@3.1.3:
294 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
295 |
296 | fast-json-stable-stringify@2.1.0:
297 | resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
298 |
299 | fast-levenshtein@2.0.6:
300 | resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
301 |
302 | fdir@6.5.0:
303 | resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
304 | engines: {node: '>=12.0.0'}
305 | peerDependencies:
306 | picomatch: ^3 || ^4
307 | peerDependenciesMeta:
308 | picomatch:
309 | optional: true
310 |
311 | file-entry-cache@8.0.0:
312 | resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
313 | engines: {node: '>=16.0.0'}
314 |
315 | filelist@1.0.4:
316 | resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==}
317 |
318 | find-up@5.0.0:
319 | resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
320 | engines: {node: '>=10'}
321 |
322 | flat-cache@4.0.1:
323 | resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
324 | engines: {node: '>=16'}
325 |
326 | flatted@3.3.3:
327 | resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
328 |
329 | glob-parent@6.0.2:
330 | resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
331 | engines: {node: '>=10.13.0'}
332 |
333 | globals@14.0.0:
334 | resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
335 | engines: {node: '>=18'}
336 |
337 | graphemer@1.4.0:
338 | resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
339 |
340 | has-flag@4.0.0:
341 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
342 | engines: {node: '>=8'}
343 |
344 | ignore@5.3.2:
345 | resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
346 | engines: {node: '>= 4'}
347 |
348 | ignore@7.0.5:
349 | resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==}
350 | engines: {node: '>= 4'}
351 |
352 | import-fresh@3.3.1:
353 | resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
354 | engines: {node: '>=6'}
355 |
356 | imurmurhash@0.1.4:
357 | resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
358 | engines: {node: '>=0.8.19'}
359 |
360 | is-extglob@2.1.1:
361 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
362 | engines: {node: '>=0.10.0'}
363 |
364 | is-glob@4.0.3:
365 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
366 | engines: {node: '>=0.10.0'}
367 |
368 | isexe@2.0.0:
369 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
370 |
371 | jake@10.9.4:
372 | resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==}
373 | engines: {node: '>=10'}
374 | hasBin: true
375 |
376 | js-yaml@4.1.1:
377 | resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
378 | hasBin: true
379 |
380 | json-buffer@3.0.1:
381 | resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
382 |
383 | json-schema-traverse@0.4.1:
384 | resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
385 |
386 | json-stable-stringify-without-jsonify@1.0.1:
387 | resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
388 |
389 | keyv@4.5.4:
390 | resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
391 |
392 | kleur@3.0.3:
393 | resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
394 | engines: {node: '>=6'}
395 |
396 | kolorist@1.8.0:
397 | resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
398 |
399 | levn@0.4.1:
400 | resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
401 | engines: {node: '>= 0.8.0'}
402 |
403 | locate-path@6.0.0:
404 | resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
405 | engines: {node: '>=10'}
406 |
407 | lodash.merge@4.6.2:
408 | resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
409 |
410 | minimatch@3.1.2:
411 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
412 |
413 | minimatch@5.1.6:
414 | resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
415 | engines: {node: '>=10'}
416 |
417 | minimatch@9.0.5:
418 | resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
419 | engines: {node: '>=16 || 14 >=14.17'}
420 |
421 | ms@2.1.3:
422 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
423 |
424 | natural-compare@1.4.0:
425 | resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
426 |
427 | optionator@0.9.4:
428 | resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
429 | engines: {node: '>= 0.8.0'}
430 |
431 | p-limit@3.1.0:
432 | resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
433 | engines: {node: '>=10'}
434 |
435 | p-locate@5.0.0:
436 | resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
437 | engines: {node: '>=10'}
438 |
439 | parent-module@1.0.1:
440 | resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
441 | engines: {node: '>=6'}
442 |
443 | path-exists@4.0.0:
444 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
445 | engines: {node: '>=8'}
446 |
447 | path-key@3.1.1:
448 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
449 | engines: {node: '>=8'}
450 |
451 | picocolors@1.1.1:
452 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
453 |
454 | picomatch@4.0.3:
455 | resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
456 | engines: {node: '>=12'}
457 |
458 | prelude-ls@1.2.1:
459 | resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
460 | engines: {node: '>= 0.8.0'}
461 |
462 | prettier@3.7.2:
463 | resolution: {integrity: sha512-n3HV2J6QhItCXndGa3oMWvWFAgN1ibnS7R9mt6iokScBOC0Ul9/iZORmU2IWUMcyAQaMPjTlY3uT34TqocUxMA==}
464 | engines: {node: '>=14'}
465 | hasBin: true
466 |
467 | prompts@2.4.2:
468 | resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
469 | engines: {node: '>= 6'}
470 |
471 | punycode@2.3.1:
472 | resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
473 | engines: {node: '>=6'}
474 |
475 | resolve-from@4.0.0:
476 | resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
477 | engines: {node: '>=4'}
478 |
479 | semver@7.7.3:
480 | resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==}
481 | engines: {node: '>=10'}
482 | hasBin: true
483 |
484 | shebang-command@2.0.0:
485 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
486 | engines: {node: '>=8'}
487 |
488 | shebang-regex@3.0.0:
489 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
490 | engines: {node: '>=8'}
491 |
492 | sisteransi@1.0.5:
493 | resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
494 |
495 | strip-json-comments@3.1.1:
496 | resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
497 | engines: {node: '>=8'}
498 |
499 | supports-color@7.2.0:
500 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
501 | engines: {node: '>=8'}
502 |
503 | tinyglobby@0.2.15:
504 | resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
505 | engines: {node: '>=12.0.0'}
506 |
507 | ts-api-utils@2.1.0:
508 | resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==}
509 | engines: {node: '>=18.12'}
510 | peerDependencies:
511 | typescript: '>=4.8.4'
512 |
513 | type-check@0.4.0:
514 | resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
515 | engines: {node: '>= 0.8.0'}
516 |
517 | typescript-eslint@8.48.0:
518 | resolution: {integrity: sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw==}
519 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
520 | peerDependencies:
521 | eslint: ^8.57.0 || ^9.0.0
522 | typescript: '>=4.8.4 <6.0.0'
523 |
524 | typescript@5.9.3:
525 | resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
526 | engines: {node: '>=14.17'}
527 | hasBin: true
528 |
529 | undici-types@7.16.0:
530 | resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
531 |
532 | uri-js@4.4.1:
533 | resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
534 |
535 | which@2.0.2:
536 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
537 | engines: {node: '>= 8'}
538 | hasBin: true
539 |
540 | word-wrap@1.2.5:
541 | resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
542 | engines: {node: '>=0.10.0'}
543 |
544 | yocto-queue@0.1.0:
545 | resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
546 | engines: {node: '>=10'}
547 |
548 | snapshots:
549 |
550 | '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1)':
551 | dependencies:
552 | eslint: 9.39.1
553 | eslint-visitor-keys: 3.4.3
554 |
555 | '@eslint-community/regexpp@4.12.2': {}
556 |
557 | '@eslint/config-array@0.21.1':
558 | dependencies:
559 | '@eslint/object-schema': 2.1.7
560 | debug: 4.4.3
561 | minimatch: 3.1.2
562 | transitivePeerDependencies:
563 | - supports-color
564 |
565 | '@eslint/config-helpers@0.4.2':
566 | dependencies:
567 | '@eslint/core': 0.17.0
568 |
569 | '@eslint/core@0.17.0':
570 | dependencies:
571 | '@types/json-schema': 7.0.15
572 |
573 | '@eslint/eslintrc@3.3.3':
574 | dependencies:
575 | ajv: 6.12.6
576 | debug: 4.4.3
577 | espree: 10.4.0
578 | globals: 14.0.0
579 | ignore: 5.3.2
580 | import-fresh: 3.3.1
581 | js-yaml: 4.1.1
582 | minimatch: 3.1.2
583 | strip-json-comments: 3.1.1
584 | transitivePeerDependencies:
585 | - supports-color
586 |
587 | '@eslint/js@9.39.1': {}
588 |
589 | '@eslint/object-schema@2.1.7': {}
590 |
591 | '@eslint/plugin-kit@0.4.1':
592 | dependencies:
593 | '@eslint/core': 0.17.0
594 | levn: 0.4.1
595 |
596 | '@humanfs/core@0.19.1': {}
597 |
598 | '@humanfs/node@0.16.7':
599 | dependencies:
600 | '@humanfs/core': 0.19.1
601 | '@humanwhocodes/retry': 0.4.3
602 |
603 | '@humanwhocodes/module-importer@1.0.1': {}
604 |
605 | '@humanwhocodes/retry@0.4.3': {}
606 |
607 | '@types/ejs@3.1.5': {}
608 |
609 | '@types/estree@1.0.8': {}
610 |
611 | '@types/json-schema@7.0.15': {}
612 |
613 | '@types/node@24.10.1':
614 | dependencies:
615 | undici-types: 7.16.0
616 |
617 | '@types/prompts@2.4.9':
618 | dependencies:
619 | '@types/node': 24.10.1
620 | kleur: 3.0.3
621 |
622 | '@typescript-eslint/eslint-plugin@8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)':
623 | dependencies:
624 | '@eslint-community/regexpp': 4.12.2
625 | '@typescript-eslint/parser': 8.48.0(eslint@9.39.1)(typescript@5.9.3)
626 | '@typescript-eslint/scope-manager': 8.48.0
627 | '@typescript-eslint/type-utils': 8.48.0(eslint@9.39.1)(typescript@5.9.3)
628 | '@typescript-eslint/utils': 8.48.0(eslint@9.39.1)(typescript@5.9.3)
629 | '@typescript-eslint/visitor-keys': 8.48.0
630 | eslint: 9.39.1
631 | graphemer: 1.4.0
632 | ignore: 7.0.5
633 | natural-compare: 1.4.0
634 | ts-api-utils: 2.1.0(typescript@5.9.3)
635 | typescript: 5.9.3
636 | transitivePeerDependencies:
637 | - supports-color
638 |
639 | '@typescript-eslint/parser@8.48.0(eslint@9.39.1)(typescript@5.9.3)':
640 | dependencies:
641 | '@typescript-eslint/scope-manager': 8.48.0
642 | '@typescript-eslint/types': 8.48.0
643 | '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3)
644 | '@typescript-eslint/visitor-keys': 8.48.0
645 | debug: 4.4.3
646 | eslint: 9.39.1
647 | typescript: 5.9.3
648 | transitivePeerDependencies:
649 | - supports-color
650 |
651 | '@typescript-eslint/project-service@8.48.0(typescript@5.9.3)':
652 | dependencies:
653 | '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.9.3)
654 | '@typescript-eslint/types': 8.48.0
655 | debug: 4.4.3
656 | typescript: 5.9.3
657 | transitivePeerDependencies:
658 | - supports-color
659 |
660 | '@typescript-eslint/scope-manager@8.48.0':
661 | dependencies:
662 | '@typescript-eslint/types': 8.48.0
663 | '@typescript-eslint/visitor-keys': 8.48.0
664 |
665 | '@typescript-eslint/tsconfig-utils@8.48.0(typescript@5.9.3)':
666 | dependencies:
667 | typescript: 5.9.3
668 |
669 | '@typescript-eslint/type-utils@8.48.0(eslint@9.39.1)(typescript@5.9.3)':
670 | dependencies:
671 | '@typescript-eslint/types': 8.48.0
672 | '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3)
673 | '@typescript-eslint/utils': 8.48.0(eslint@9.39.1)(typescript@5.9.3)
674 | debug: 4.4.3
675 | eslint: 9.39.1
676 | ts-api-utils: 2.1.0(typescript@5.9.3)
677 | typescript: 5.9.3
678 | transitivePeerDependencies:
679 | - supports-color
680 |
681 | '@typescript-eslint/types@8.48.0': {}
682 |
683 | '@typescript-eslint/typescript-estree@8.48.0(typescript@5.9.3)':
684 | dependencies:
685 | '@typescript-eslint/project-service': 8.48.0(typescript@5.9.3)
686 | '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.9.3)
687 | '@typescript-eslint/types': 8.48.0
688 | '@typescript-eslint/visitor-keys': 8.48.0
689 | debug: 4.4.3
690 | minimatch: 9.0.5
691 | semver: 7.7.3
692 | tinyglobby: 0.2.15
693 | ts-api-utils: 2.1.0(typescript@5.9.3)
694 | typescript: 5.9.3
695 | transitivePeerDependencies:
696 | - supports-color
697 |
698 | '@typescript-eslint/utils@8.48.0(eslint@9.39.1)(typescript@5.9.3)':
699 | dependencies:
700 | '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1)
701 | '@typescript-eslint/scope-manager': 8.48.0
702 | '@typescript-eslint/types': 8.48.0
703 | '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3)
704 | eslint: 9.39.1
705 | typescript: 5.9.3
706 | transitivePeerDependencies:
707 | - supports-color
708 |
709 | '@typescript-eslint/visitor-keys@8.48.0':
710 | dependencies:
711 | '@typescript-eslint/types': 8.48.0
712 | eslint-visitor-keys: 4.2.1
713 |
714 | acorn-jsx@5.3.2(acorn@8.15.0):
715 | dependencies:
716 | acorn: 8.15.0
717 |
718 | acorn@8.15.0: {}
719 |
720 | ajv@6.12.6:
721 | dependencies:
722 | fast-deep-equal: 3.1.3
723 | fast-json-stable-stringify: 2.1.0
724 | json-schema-traverse: 0.4.1
725 | uri-js: 4.4.1
726 |
727 | ansi-styles@4.3.0:
728 | dependencies:
729 | color-convert: 2.0.1
730 |
731 | argparse@2.0.1: {}
732 |
733 | async@3.2.6: {}
734 |
735 | balanced-match@1.0.2: {}
736 |
737 | brace-expansion@1.1.12:
738 | dependencies:
739 | balanced-match: 1.0.2
740 | concat-map: 0.0.1
741 |
742 | brace-expansion@2.0.2:
743 | dependencies:
744 | balanced-match: 1.0.2
745 |
746 | callsites@3.1.0: {}
747 |
748 | chalk@4.1.2:
749 | dependencies:
750 | ansi-styles: 4.3.0
751 | supports-color: 7.2.0
752 |
753 | color-convert@2.0.1:
754 | dependencies:
755 | color-name: 1.1.4
756 |
757 | color-name@1.1.4: {}
758 |
759 | concat-map@0.0.1: {}
760 |
761 | cross-spawn@7.0.6:
762 | dependencies:
763 | path-key: 3.1.1
764 | shebang-command: 2.0.0
765 | which: 2.0.2
766 |
767 | debug@4.4.3:
768 | dependencies:
769 | ms: 2.1.3
770 |
771 | deep-is@0.1.4: {}
772 |
773 | ejs@3.1.10:
774 | dependencies:
775 | jake: 10.9.4
776 |
777 | escape-string-regexp@4.0.0: {}
778 |
779 | eslint-scope@8.4.0:
780 | dependencies:
781 | esrecurse: 4.3.0
782 | estraverse: 5.3.0
783 |
784 | eslint-visitor-keys@3.4.3: {}
785 |
786 | eslint-visitor-keys@4.2.1: {}
787 |
788 | eslint@9.39.1:
789 | dependencies:
790 | '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1)
791 | '@eslint-community/regexpp': 4.12.2
792 | '@eslint/config-array': 0.21.1
793 | '@eslint/config-helpers': 0.4.2
794 | '@eslint/core': 0.17.0
795 | '@eslint/eslintrc': 3.3.3
796 | '@eslint/js': 9.39.1
797 | '@eslint/plugin-kit': 0.4.1
798 | '@humanfs/node': 0.16.7
799 | '@humanwhocodes/module-importer': 1.0.1
800 | '@humanwhocodes/retry': 0.4.3
801 | '@types/estree': 1.0.8
802 | ajv: 6.12.6
803 | chalk: 4.1.2
804 | cross-spawn: 7.0.6
805 | debug: 4.4.3
806 | escape-string-regexp: 4.0.0
807 | eslint-scope: 8.4.0
808 | eslint-visitor-keys: 4.2.1
809 | espree: 10.4.0
810 | esquery: 1.6.0
811 | esutils: 2.0.3
812 | fast-deep-equal: 3.1.3
813 | file-entry-cache: 8.0.0
814 | find-up: 5.0.0
815 | glob-parent: 6.0.2
816 | ignore: 5.3.2
817 | imurmurhash: 0.1.4
818 | is-glob: 4.0.3
819 | json-stable-stringify-without-jsonify: 1.0.1
820 | lodash.merge: 4.6.2
821 | minimatch: 3.1.2
822 | natural-compare: 1.4.0
823 | optionator: 0.9.4
824 | transitivePeerDependencies:
825 | - supports-color
826 |
827 | espree@10.4.0:
828 | dependencies:
829 | acorn: 8.15.0
830 | acorn-jsx: 5.3.2(acorn@8.15.0)
831 | eslint-visitor-keys: 4.2.1
832 |
833 | esquery@1.6.0:
834 | dependencies:
835 | estraverse: 5.3.0
836 |
837 | esrecurse@4.3.0:
838 | dependencies:
839 | estraverse: 5.3.0
840 |
841 | estraverse@5.3.0: {}
842 |
843 | esutils@2.0.3: {}
844 |
845 | fast-deep-equal@3.1.3: {}
846 |
847 | fast-json-stable-stringify@2.1.0: {}
848 |
849 | fast-levenshtein@2.0.6: {}
850 |
851 | fdir@6.5.0(picomatch@4.0.3):
852 | optionalDependencies:
853 | picomatch: 4.0.3
854 |
855 | file-entry-cache@8.0.0:
856 | dependencies:
857 | flat-cache: 4.0.1
858 |
859 | filelist@1.0.4:
860 | dependencies:
861 | minimatch: 5.1.6
862 |
863 | find-up@5.0.0:
864 | dependencies:
865 | locate-path: 6.0.0
866 | path-exists: 4.0.0
867 |
868 | flat-cache@4.0.1:
869 | dependencies:
870 | flatted: 3.3.3
871 | keyv: 4.5.4
872 |
873 | flatted@3.3.3: {}
874 |
875 | glob-parent@6.0.2:
876 | dependencies:
877 | is-glob: 4.0.3
878 |
879 | globals@14.0.0: {}
880 |
881 | graphemer@1.4.0: {}
882 |
883 | has-flag@4.0.0: {}
884 |
885 | ignore@5.3.2: {}
886 |
887 | ignore@7.0.5: {}
888 |
889 | import-fresh@3.3.1:
890 | dependencies:
891 | parent-module: 1.0.1
892 | resolve-from: 4.0.0
893 |
894 | imurmurhash@0.1.4: {}
895 |
896 | is-extglob@2.1.1: {}
897 |
898 | is-glob@4.0.3:
899 | dependencies:
900 | is-extglob: 2.1.1
901 |
902 | isexe@2.0.0: {}
903 |
904 | jake@10.9.4:
905 | dependencies:
906 | async: 3.2.6
907 | filelist: 1.0.4
908 | picocolors: 1.1.1
909 |
910 | js-yaml@4.1.1:
911 | dependencies:
912 | argparse: 2.0.1
913 |
914 | json-buffer@3.0.1: {}
915 |
916 | json-schema-traverse@0.4.1: {}
917 |
918 | json-stable-stringify-without-jsonify@1.0.1: {}
919 |
920 | keyv@4.5.4:
921 | dependencies:
922 | json-buffer: 3.0.1
923 |
924 | kleur@3.0.3: {}
925 |
926 | kolorist@1.8.0: {}
927 |
928 | levn@0.4.1:
929 | dependencies:
930 | prelude-ls: 1.2.1
931 | type-check: 0.4.0
932 |
933 | locate-path@6.0.0:
934 | dependencies:
935 | p-locate: 5.0.0
936 |
937 | lodash.merge@4.6.2: {}
938 |
939 | minimatch@3.1.2:
940 | dependencies:
941 | brace-expansion: 1.1.12
942 |
943 | minimatch@5.1.6:
944 | dependencies:
945 | brace-expansion: 2.0.2
946 |
947 | minimatch@9.0.5:
948 | dependencies:
949 | brace-expansion: 2.0.2
950 |
951 | ms@2.1.3: {}
952 |
953 | natural-compare@1.4.0: {}
954 |
955 | optionator@0.9.4:
956 | dependencies:
957 | deep-is: 0.1.4
958 | fast-levenshtein: 2.0.6
959 | levn: 0.4.1
960 | prelude-ls: 1.2.1
961 | type-check: 0.4.0
962 | word-wrap: 1.2.5
963 |
964 | p-limit@3.1.0:
965 | dependencies:
966 | yocto-queue: 0.1.0
967 |
968 | p-locate@5.0.0:
969 | dependencies:
970 | p-limit: 3.1.0
971 |
972 | parent-module@1.0.1:
973 | dependencies:
974 | callsites: 3.1.0
975 |
976 | path-exists@4.0.0: {}
977 |
978 | path-key@3.1.1: {}
979 |
980 | picocolors@1.1.1: {}
981 |
982 | picomatch@4.0.3: {}
983 |
984 | prelude-ls@1.2.1: {}
985 |
986 | prettier@3.7.2: {}
987 |
988 | prompts@2.4.2:
989 | dependencies:
990 | kleur: 3.0.3
991 | sisteransi: 1.0.5
992 |
993 | punycode@2.3.1: {}
994 |
995 | resolve-from@4.0.0: {}
996 |
997 | semver@7.7.3: {}
998 |
999 | shebang-command@2.0.0:
1000 | dependencies:
1001 | shebang-regex: 3.0.0
1002 |
1003 | shebang-regex@3.0.0: {}
1004 |
1005 | sisteransi@1.0.5: {}
1006 |
1007 | strip-json-comments@3.1.1: {}
1008 |
1009 | supports-color@7.2.0:
1010 | dependencies:
1011 | has-flag: 4.0.0
1012 |
1013 | tinyglobby@0.2.15:
1014 | dependencies:
1015 | fdir: 6.5.0(picomatch@4.0.3)
1016 | picomatch: 4.0.3
1017 |
1018 | ts-api-utils@2.1.0(typescript@5.9.3):
1019 | dependencies:
1020 | typescript: 5.9.3
1021 |
1022 | type-check@0.4.0:
1023 | dependencies:
1024 | prelude-ls: 1.2.1
1025 |
1026 | typescript-eslint@8.48.0(eslint@9.39.1)(typescript@5.9.3):
1027 | dependencies:
1028 | '@typescript-eslint/eslint-plugin': 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)
1029 | '@typescript-eslint/parser': 8.48.0(eslint@9.39.1)(typescript@5.9.3)
1030 | '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3)
1031 | '@typescript-eslint/utils': 8.48.0(eslint@9.39.1)(typescript@5.9.3)
1032 | eslint: 9.39.1
1033 | typescript: 5.9.3
1034 | transitivePeerDependencies:
1035 | - supports-color
1036 |
1037 | typescript@5.9.3: {}
1038 |
1039 | undici-types@7.16.0: {}
1040 |
1041 | uri-js@4.4.1:
1042 | dependencies:
1043 | punycode: 2.3.1
1044 |
1045 | which@2.0.2:
1046 | dependencies:
1047 | isexe: 2.0.0
1048 |
1049 | word-wrap@1.2.5: {}
1050 |
1051 | yocto-queue@0.1.0: {}
1052 |
--------------------------------------------------------------------------------