@qlover/create-app 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/bin/create-app.js +44 -4
  3. package/{templates/pack-app → configs/_common}/.env.template +8 -1
  4. package/{templates/pack-app → configs/_common}/.github/workflows/general-check.yml +9 -9
  5. package/{templates/pack-app → configs/_common}/.github/workflows/release.yml.template +18 -18
  6. package/configs/_common/.prettierrc.js +7 -0
  7. package/configs/_common/.release-it.json.template +42 -0
  8. package/configs/_common/.vscode/extensions.json +9 -0
  9. package/configs/_common/.vscode/react.code-snippets +19 -0
  10. package/configs/_common/.vscode/settings.json +11 -0
  11. package/configs/_common/package.json +61 -0
  12. package/configs/node-lib/eslint.config.js +50 -0
  13. package/configs/react-app/eslint.config.js +66 -0
  14. package/dist/cjs/index.d.ts +52 -37
  15. package/dist/cjs/index.js +1 -1
  16. package/dist/es/index.d.ts +52 -37
  17. package/dist/es/index.js +1 -1
  18. package/package.json +5 -2
  19. package/templates/node-lib/.release-it.json +42 -0
  20. package/templates/node-lib/__tests__/readJson.test.ts +1 -0
  21. package/templates/node-lib/bin/test.js +30 -0
  22. package/templates/node-lib/package.json +23 -6
  23. package/templates/node-lib/rollup.config.js +15 -24
  24. package/templates/node-lib/src/readJson.ts +9 -3
  25. package/templates/node-lib/tsconfig.json +19 -1
  26. package/templates/pack-app/eslint.config.js +81 -61
  27. package/templates/pack-app/fe-config.json +1 -5
  28. package/templates/pack-app/package.json +19 -11
  29. package/templates/pack-app/tsconfig.json +1 -1
  30. package/templates/pack-app/vite.config.ts +14 -0
  31. package/templates/react-app/README.md +177 -40
  32. package/templates/react-app/config/i18n.ts +1 -1
  33. package/templates/react-app/lib/fe-react-controller/FeController.ts +7 -3
  34. package/templates/react-app/lib/fe-react-theme/ThemeController.ts +1 -1
  35. package/templates/react-app/package.json +53 -8
  36. package/templates/react-app/src/App.tsx +4 -5
  37. package/templates/react-app/src/{services → base/apis}/feApi/FeApiMockPlugin.ts +1 -1
  38. package/templates/react-app/src/base/cases/UserToken.ts +47 -0
  39. package/templates/react-app/src/base/port/IOCInterface.ts +53 -0
  40. package/templates/react-app/src/base/port/StorageTokenInterface.ts +5 -0
  41. package/templates/react-app/src/{types → base/port}/UIDependenciesInterface.ts +6 -0
  42. package/templates/react-app/src/{types → base/types}/global.d.ts +1 -1
  43. package/templates/react-app/src/components/ThemeSwitcher.tsx +3 -2
  44. package/templates/react-app/src/core/bootstrap.ts +21 -0
  45. package/templates/react-app/src/core/feIOC/FeIOC.ts +32 -0
  46. package/templates/react-app/src/core/feIOC/RegisterApi.ts +41 -0
  47. package/templates/react-app/src/core/feIOC/RegisterCommon.ts +20 -0
  48. package/templates/react-app/src/core/feIOC/RegisterControllers.ts +53 -0
  49. package/templates/react-app/src/core/index.ts +31 -0
  50. package/templates/react-app/src/main.tsx +8 -10
  51. package/templates/react-app/src/pages/404.tsx +2 -2
  52. package/templates/react-app/src/pages/500.tsx +1 -1
  53. package/templates/react-app/src/pages/auth/Layout.tsx +3 -2
  54. package/templates/react-app/src/pages/auth/Login.tsx +6 -4
  55. package/templates/react-app/src/pages/base/About.tsx +1 -1
  56. package/templates/react-app/src/pages/base/Executor.tsx +8 -4
  57. package/templates/react-app/src/pages/base/Home.tsx +1 -1
  58. package/templates/react-app/src/pages/base/JSONStorage.tsx +6 -4
  59. package/templates/react-app/src/pages/base/Layout.tsx +1 -1
  60. package/templates/react-app/src/pages/base/RedirectPathname.tsx +1 -1
  61. package/templates/react-app/src/pages/base/Request.tsx +8 -3
  62. package/templates/react-app/src/pages/index.tsx +7 -2
  63. package/templates/react-app/src/services/{pageProcesser/PageProcesser.ts → processer/ProcesserService.ts} +3 -3
  64. package/templates/react-app/src/{containers/context → uikit/contexts}/BaseRouteContext.ts +4 -4
  65. package/templates/react-app/src/{services → uikit}/controllers/ExecutorController.ts +5 -5
  66. package/templates/react-app/src/{services → uikit}/controllers/JSONStorageController.ts +2 -2
  67. package/templates/react-app/src/{services → uikit}/controllers/RequestController.ts +3 -3
  68. package/templates/react-app/src/{services → uikit}/controllers/RouterController.ts +2 -2
  69. package/templates/react-app/src/{services → uikit}/controllers/UserController.ts +25 -51
  70. package/templates/react-app/src/{containers/context → uikit/providers}/BaseRouteProvider.tsx +2 -2
  71. package/templates/react-app/src/{components → uikit/providers}/ProcessProvider.tsx +13 -7
  72. package/templates/react-app/tsconfig.json +27 -5
  73. package/templates/react-app/tsconfig.node.json +3 -15
  74. package/templates/react-app/vite.config.ts +17 -14
  75. package/templates/pack-app/.env +0 -5
  76. package/templates/pack-app/.gitignore.template +0 -50
  77. package/templates/pack-app/.prettierrc.js +0 -3
  78. package/templates/pack-app/CHANGELOG.md +0 -0
  79. package/templates/pack-app/jest.config.js +0 -31
  80. package/templates/react-app/eslint.config.js +0 -31
  81. package/templates/react-app/src/containers/index.ts +0 -71
  82. package/templates/react-app/src/services/pageProcesser/index.ts +0 -1
  83. package/templates/react-app/tsconfig.app.json +0 -29
  84. package/templates/react-vite-lib/.gitignore.template +0 -27
  85. package/templates/react-vite-lib/README.md +0 -50
  86. package/templates/react-vite-lib/__tests__/Sum.test.ts +0 -9
  87. package/templates/react-vite-lib/__tests__/Text.test.tsx +0 -11
  88. package/templates/react-vite-lib/eslint.config.js +0 -28
  89. package/templates/react-vite-lib/index.html +0 -13
  90. package/templates/react-vite-lib/package.json +0 -30
  91. package/templates/react-vite-lib/public/vite.svg +0 -1
  92. package/templates/react-vite-lib/src/calc.ts +0 -3
  93. package/templates/react-vite-lib/src/commponents/Text.tsx +0 -7
  94. package/templates/react-vite-lib/src/index.ts +0 -2
  95. package/templates/react-vite-lib/src/vite-env.d.ts +0 -1
  96. package/templates/react-vite-lib/tsconfig.json +0 -25
  97. package/templates/react-vite-lib/vite.config.ts +0 -24
  98. /package/{templates/pack-app → configs/_common}/.editorconfig +0 -0
  99. /package/{templates/pack-app → configs/_common}/.gitattributes +0 -0
  100. /package/{templates/react-app → configs/_common}/.gitignore.template +0 -0
  101. /package/{templates/pack-app → configs/_common}/.prettierignore +0 -0
  102. /package/templates/react-app/src/{services → base/apis}/feApi/FeApi.ts +0 -0
  103. /package/templates/react-app/src/{services → base/apis}/feApi/FeApiType.ts +0 -0
  104. /package/templates/react-app/src/{services → base/apis}/feApi/index.ts +0 -0
  105. /package/templates/react-app/src/{types → base/types}/Page.ts +0 -0
  106. /package/templates/react-app/src/{containers → core}/globals.ts +0 -0
  107. /package/templates/react-app/src/{hooks → uikit/hooks}/useLanguageGuard.ts +0 -0
  108. /package/templates/react-app/src/{hooks → uikit/hooks}/useStrictEffect.ts +0 -0
  109. /package/templates/react-app/src/{styles → uikit/styles}/css/index.css +0 -0
  110. /package/templates/react-app/src/{styles → uikit/styles}/css/page.css +0 -0
  111. /package/templates/react-app/src/{styles → uikit/styles}/css/tailwind.css +0 -0
  112. /package/templates/react-app/src/{utils → uikit/utils}/RequestLogger.ts +0 -0
  113. /package/templates/react-app/src/{utils → uikit/utils}/datetime.ts +0 -0
  114. /package/templates/react-app/src/{utils → uikit/utils}/thread.ts +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
 
2
2
 
3
+ ## [0.1.5](https://github.com/qlover/fe-base/compare/create-app-v0.1.4...create-app-v0.1.5) (2025-02-13)
4
+
5
+ ## [0.1.4](https://github.com/qlover/fe-base/compare/create-app-v0.1.3...create-app-v0.1.4) (2025-01-20)
6
+
3
7
  ## [0.1.3](https://github.com/qlover/fe-base/compare/create-app-v0.1.2...create-app-v0.1.3) (2025-01-17)
4
8
 
5
9
  ## [0.1.2](https://github.com/qlover/fe-base/compare/create-app-v0.1.1...create-app-v0.1.2) (2025-01-17)
package/bin/create-app.js CHANGED
@@ -3,24 +3,64 @@
3
3
  import { fileURLToPath } from 'url';
4
4
  import { dirname, join } from 'path';
5
5
  import { Generator } from '../dist/es/index.js';
6
- import { existsSync } from 'fs';
6
+ import { existsSync, readFileSync } from 'fs';
7
+ import { Command } from 'commander';
8
+
9
+ const __dirname = dirname(fileURLToPath(import.meta.url));
10
+ const pkg = JSON.parse(
11
+ readFileSync(join(__dirname, '../package.json'), 'utf-8')
12
+ );
13
+
14
+ function programArgs() {
15
+ const program = new Command();
16
+
17
+ program.version(pkg.version, '-v, --version', 'Show version');
18
+
19
+ program
20
+ .option(
21
+ '-d, --dry-run',
22
+ 'Do not touch or write anything, but show the commands'
23
+ )
24
+ .option('-V, --verbose', 'Show more information')
25
+ .option('--config', 'Copy config files (default: true)', true)
26
+ .option('--no-config', 'Do not copy config files');
27
+
28
+ // parse arguments
29
+ program.parse();
30
+
31
+ return program.opts();
32
+ }
7
33
 
8
34
  async function main() {
9
- const __dirname = dirname(fileURLToPath(import.meta.url));
35
+ const { dryRun, verbose, ...commandOptions } = programArgs();
36
+
10
37
  const templateRootPath = join(__dirname, '../templates');
38
+ const configsRootPath = join(__dirname, '../configs');
11
39
 
12
40
  if (!existsSync(templateRootPath)) {
13
41
  console.error('Template is empty!');
14
42
  process.exit(1);
15
43
  }
16
44
 
45
+ if (!existsSync(configsRootPath)) {
46
+ console.error('Configs is empty!');
47
+ process.exit(1);
48
+ }
49
+
17
50
  const generator = new Generator({
51
+ dryRun,
52
+ verbose,
18
53
  options: {
19
- templateRootPath
54
+ ...commandOptions,
55
+ templateRootPath,
56
+ configsRootPath
20
57
  }
21
58
  });
22
59
 
23
60
  await generator.generate();
24
61
  }
25
62
 
26
- main();
63
+ main().catch((err) => {
64
+ console.error(err);
65
+ process.exit(1);
66
+ });
@@ -1,6 +1,13 @@
1
1
  NODE_ENV=production
2
+
3
+ # ci
2
4
  NPM_TOKEN=
3
5
  GITHUB_TOKEN=
6
+
7
+ # fe-scripts
4
8
  FE_RELEASE_BRANCH=master
5
9
  FE_RELEASE=false
6
- FE_RELEASE_ENV=production
10
+ FE_RELEASE_ENV=production
11
+
12
+ # vite
13
+ VITE_PUBLIC_PATH=
@@ -26,19 +26,19 @@ jobs:
26
26
  with:
27
27
  node-version: '18.19.0'
28
28
 
29
- - name: Install dependencies
29
+ - name: Install Pnpm
30
30
  run: |
31
- npm install -g yarn
32
- yarn
31
+ npm install -g pnpm
32
+ pnpm -v
33
33
 
34
- - name: Lint
35
- run: yarn lint
34
+ - name: Pnpm Lint
35
+ run: pnpm lint
36
36
 
37
- - name: Test
38
- run: yarn test
37
+ - name: Pnpm Test
38
+ run: pnpm test
39
39
 
40
- - name: Build dist
41
- run: yarn build
40
+ - name: Pnpm Build
41
+ run: pnpm build
42
42
 
43
43
  # check packages
44
44
  # - name: Check packages
@@ -35,19 +35,19 @@ jobs:
35
35
  with:
36
36
  node-version: '18.19.0'
37
37
 
38
- - name: Install dependencies
38
+ - name: Install Pnpm
39
39
  run: |
40
- npm install -g yarn
41
- yarn
40
+ npm install -g pnpm
41
+ pnpm -v
42
42
 
43
- - name: Lint
44
- run: yarn lint
43
+ - name: Pnpm Lint
44
+ run: pnpm lint
45
45
 
46
- - name: Test
47
- run: yarn test
46
+ - name: Pnpm Test
47
+ run: pnpm test
48
48
 
49
- - name: Build dist
50
- run: yarn build
49
+ - name: Pnpm Build
50
+ run: pnpm build
51
51
 
52
52
  - name: Create release PR
53
53
  run: npm run release-pr:[PATH_NAMES]
@@ -82,19 +82,19 @@ jobs:
82
82
  with:
83
83
  node-version: '18.19.0'
84
84
 
85
- - name: Install dependencies
85
+ - name: Install Pnpm
86
86
  run: |
87
- npm install -g yarn
88
- yarn
87
+ npm install -g pnpm
88
+ pnpm -v
89
89
 
90
- - name: Lint
91
- run: yarn lint
90
+ - name: Pnpm Lint
91
+ run: pnpm lint
92
92
 
93
- - name: Test
94
- run: yarn test
93
+ - name: Pnpm Test
94
+ run: pnpm test
95
95
 
96
- - name: Build dist
97
- run: yarn build
96
+ - name: Pnpm Build
97
+ run: pnpm build
98
98
 
99
99
  - name: Create tag and publish
100
100
  run: npm run release:[PATH_NAMES]
@@ -0,0 +1,7 @@
1
+ /** @type {import('prettier').Config} */
2
+ export default {
3
+ semi: true,
4
+ singleQuote: true,
5
+ trailingComma: 'none',
6
+ endOfLine: 'lf'
7
+ };
@@ -0,0 +1,42 @@
1
+ {
2
+ "git": {
3
+ "commitMessage": "chore(tag): [PKG_NAME] v${version}",
4
+ "tagName": "[PKG_NAME]-v${version}",
5
+ "tagMatch": "[PKG_NAME]-v*",
6
+ "tagAnnotation": "chore(tag): [PKG_NAME] v${version}",
7
+ "push": true,
8
+ "pushArgs": ["--follow-tags"]
9
+ },
10
+ "npm": {
11
+ "publishPath": "",
12
+ "versionArgs": ["--allow-same-version", "--workspaces-update=false"]
13
+ },
14
+ "github": {
15
+ "release": true,
16
+ "releaseName": "chore(tag): [PKG_NAME] v${version}"
17
+ },
18
+
19
+ "plugins": {
20
+ "@release-it/conventional-changelog": {
21
+ "infile": "CHANGELOG.md",
22
+ "preset": {
23
+ "name": "conventionalcommits",
24
+ "types": [
25
+ { "type": "feat", "section": "Features" },
26
+ { "type": "fix", "section": "Bug Fixes" },
27
+ { "type": "revert", "section": "Reverts" },
28
+ { "type": "build", "hidden": true, "section": "Build System" },
29
+ { "type": "chore", "hidden": true },
30
+ { "type": "docs", "section": "Documentation" },
31
+ { "type": "style", "hidden": true },
32
+ { "type": "refactor", "hidden": true },
33
+ { "type": "perf", "hidden": true },
34
+ { "type": "test", "hidden": true }
35
+ ]
36
+ },
37
+ "gitRawCommitsOpts": {
38
+ "path": "."
39
+ }
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "recommendations": [
3
+ "dbaeumer.vscode-eslint", // ESLint
4
+ "esbenp.prettier-vscode", // Prettier
5
+ "bradlc.vscode-tailwindcss", // Tailwind CSS
6
+ "wayou.vscode-todo-highlight", // Mark Highlight(TODO, FIXME, etc.),
7
+ "vitest.explorer" // Vitest
8
+ ]
9
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "react-component": {
3
+ "prefix": "react-component",
4
+ "scope": "typescriptreact",
5
+ "body": [
6
+ "import clsx from 'clsx';",
7
+ "",
8
+ "export type $1Props = {",
9
+ " $2",
10
+ " className?: string;",
11
+ "}",
12
+ "",
13
+ "export function $1({ $2, className }: $1Props) {",
14
+ " return <div data-testid=\"$1\" className={clsx('$3', className)}>$3</div>;",
15
+ "}"
16
+ ],
17
+ "description": "创建一个 React 组件"
18
+ }
19
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "eslint.enable": true,
3
+ "eslint.format.enable": false,
4
+ "files.eol": "\n",
5
+ "editor.tabSize": 2,
6
+ "jest.runMode": "on-demand",
7
+ "tailwindCSS.rootFontSize": 10,
8
+ "editor.snippetSuggestions": "top",
9
+ "vitest.autoRun": false,
10
+ "workbench.view.alwaysShowHeaderActions": true
11
+ }
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "pkg-name",
3
+ "description": "A pkg-name description",
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "private": true,
7
+ "homepage": "",
8
+ "author": "",
9
+ "license": "ISC",
10
+ "main": "./dist/es/index.js",
11
+ "module": "./dist/es/index.js",
12
+ "types": "./dist/es/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/es/index.d.ts",
16
+ "import": "./dist/es/index.js",
17
+ "require": "./dist/cjs/index.js"
18
+ },
19
+ "./cjs/*": "./dist/cjs/*",
20
+ "./es/*": "./dist/es/*",
21
+ "./package.json": "./package.json"
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "",
26
+ "directory": ""
27
+ },
28
+ "files": [
29
+ "bin",
30
+ "dist",
31
+ "package.json",
32
+ "README.md"
33
+ ],
34
+ "keywords": [
35
+ "lib",
36
+ "node lib"
37
+ ],
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
41
+ "bin": {},
42
+ "scripts": {
43
+ "build": "pnpm build",
44
+ "test": "vitest run",
45
+ "prettier": "prettier --ignore-path .prettierignore **/*.{js,ts,json,cjs,mjs} --write",
46
+ "lint": "eslint . --fix",
47
+ "clean": "fe-clean",
48
+ "check-packages": "fe-check-packages",
49
+ "commit": "fe-commit",
50
+ "clean-branch": "fe-clean-branch"
51
+ },
52
+ "devDependencies": {
53
+ "@qlover/env-loader": "latest",
54
+ "@qlover/fe-standard": "latest",
55
+ "@qlover/fe-scripts": "latest",
56
+ "@qlover/scripts-context": "latest"
57
+ },
58
+ "dependencies": {
59
+ "@qlover/fe-utils": "latest"
60
+ }
61
+ }
@@ -0,0 +1,50 @@
1
+ import js from '@eslint/js';
2
+ import globals from 'globals';
3
+ import prettierConfig from '../../packages/node-lib/.prettierrc.js';
4
+ import prettier from 'eslint-plugin-prettier';
5
+ import tseslint from '@typescript-eslint/eslint-plugin';
6
+ import tsparser from '@typescript-eslint/parser';
7
+ import * as feDev from '@qlover/eslint-plugin-fe-dev';
8
+
9
+ export default [
10
+ {
11
+ ignores: ['dist', 'node_modules']
12
+ },
13
+ {
14
+ files: ['src/**/*.{js,jsx,ts,tsx}'],
15
+ languageOptions: {
16
+ parser: tsparser,
17
+ ecmaVersion: 2020,
18
+ globals: {
19
+ ...globals.browser,
20
+ ...globals.node
21
+ },
22
+ parserOptions: {
23
+ ecmaVersion: 'latest',
24
+ ecmaFeatures: { jsx: true },
25
+ sourceType: 'module',
26
+ project: './tsconfig.json'
27
+ }
28
+ },
29
+ plugins: {
30
+ prettier,
31
+ '@typescript-eslint': tseslint,
32
+ 'fe-dev': feDev
33
+ },
34
+ rules: {
35
+ ...js.configs.recommended.rules,
36
+ ...tseslint.configs.recommended.rules,
37
+ '@typescript-eslint/no-explicit-any': 'error',
38
+ 'prettier/prettier': ['error', prettierConfig],
39
+ '@typescript-eslint/ban-ts-comment': [
40
+ 'off',
41
+ {
42
+ 'ts-expect-error': {
43
+ descriptionFormat: '^.*$'
44
+ }
45
+ }
46
+ ],
47
+ 'fe-dev/ts-class-method-return': 'error'
48
+ }
49
+ }
50
+ ];
@@ -0,0 +1,66 @@
1
+ import js from '@eslint/js';
2
+ import globals from 'globals';
3
+ import react from 'eslint-plugin-react';
4
+ import reactHooks from 'eslint-plugin-react-hooks';
5
+ import reactRefresh from 'eslint-plugin-react-refresh';
6
+ import tseslint from 'typescript-eslint';
7
+ import tsparser from '@typescript-eslint/parser';
8
+ import * as feDev from '@qlover/eslint-plugin-fe-dev';
9
+ import prettier from 'eslint-plugin-prettier';
10
+ import prettierConfig from './.prettierrc.js';
11
+
12
+ export default tseslint.config(
13
+ { ignores: ['dist', 'node_modules'] },
14
+ {
15
+ extends: [js.configs.recommended, ...tseslint.configs.recommended],
16
+ files: ['src/**/*.{ts,tsx}'],
17
+ languageOptions: {
18
+ parser: tsparser,
19
+ ecmaVersion: 2020,
20
+ globals: {
21
+ ...globals.browser,
22
+ ...globals.node
23
+ },
24
+ parserOptions: {
25
+ ecmaVersion: 'latest',
26
+ ecmaFeatures: { jsx: true },
27
+ sourceType: 'module',
28
+ project: './tsconfig.json'
29
+ }
30
+ },
31
+ settings: { react: { version: '18.3' } },
32
+ plugins: {
33
+ react,
34
+ 'react-hooks': reactHooks,
35
+ 'react-refresh': reactRefresh,
36
+ prettier,
37
+ '@typescript-eslint': tseslint,
38
+ 'fe-dev': feDev
39
+ },
40
+ rules: {
41
+ ...js.configs.recommended.rules,
42
+ ...react.configs.recommended.rules,
43
+ ...react.configs['jsx-runtime'].rules,
44
+ ...reactHooks.configs.recommended.rules,
45
+ ...tseslint.configs.recommended.rules,
46
+ 'react/jsx-no-target-blank': 'off',
47
+ 'react/prefer-stateless-function': 'error',
48
+ 'react-refresh/only-export-components': [
49
+ 'warn',
50
+ { allowConstantExport: true }
51
+ ],
52
+ '@typescript-eslint/no-explicit-any': 'error',
53
+ 'prettier/prettier': ['error', prettierConfig],
54
+ '@typescript-eslint/ban-ts-comment': [
55
+ 'off',
56
+ {
57
+ 'ts-expect-error': {
58
+ descriptionFormat: '^.*$'
59
+ }
60
+ }
61
+ ],
62
+ 'react-hooks/exhaustive-deps': 'off',
63
+ 'fe-dev/ts-class-method-return': 'error'
64
+ }
65
+ }
66
+ );
@@ -1,4 +1,4 @@
1
- import { FeScriptContext } from '@qlover/fe-scripts';
1
+ import { FeScriptContext } from '@qlover/scripts-context';
2
2
  import { Logger } from '@qlover/fe-utils';
3
3
  import { DistinctQuestion } from 'inquirer';
4
4
  import ignore from 'ignore';
@@ -6,21 +6,49 @@ import ignore from 'ignore';
6
6
  type GeneratorPrompt = DistinctQuestion;
7
7
  type GeneratorOptions = {
8
8
  prompts?: GeneratorPrompt[];
9
+ /**
10
+ * template root path
11
+ */
9
12
  templateRootPath: string;
13
+ /**
14
+ * configs root path
15
+ */
16
+ configsRootPath: string;
17
+ /**
18
+ * whether to copy config files
19
+ */
20
+ config?: boolean;
10
21
  };
11
- interface GeneratorResult extends GeneratorOptions {
22
+ interface GeneratorRuntimes extends GeneratorOptions {
23
+ /**
24
+ * project name
25
+ */
12
26
  name: string;
27
+ /**
28
+ * choose template name
29
+ *
30
+ * mayby is pack-app
31
+ */
13
32
  template: string;
33
+ /**
34
+ * choose sub packages
35
+ *
36
+ * mayby is ['node-lib', 'react-app']
37
+ */
14
38
  subPackages?: string[];
15
39
  /**
16
40
  * @default `packages`
17
41
  */
18
42
  packagesNames?: string;
43
+ /**
44
+ * Generated project path
45
+ * @default `./`
46
+ */
19
47
  targetPath?: string;
20
48
  }
21
49
  type TaskOptions = {
22
50
  templateFiles: TemplateFile[];
23
- result: GeneratorResult;
51
+ result: GeneratorRuntimes;
24
52
  };
25
53
  type TemplateFile = {
26
54
  path: string;
@@ -30,41 +58,34 @@ type TemplateFile = {
30
58
  declare class Generator {
31
59
  private ora;
32
60
  protected context: FeScriptContext<GeneratorOptions>;
61
+ private subPackages;
62
+ private copyer;
33
63
  constructor(context: Partial<FeScriptContext<GeneratorOptions>>);
34
64
  get logger(): Logger;
35
- steps(prompts: GeneratorPrompt[]): Promise<GeneratorResult>;
65
+ steps(prompts: GeneratorPrompt[]): Promise<GeneratorRuntimes>;
36
66
  action({ label, task }: {
37
67
  label: string;
38
68
  task: (() => Promise<unknown>) | (() => unknown);
39
69
  }): Promise<unknown>;
40
- /**
41
- * Creates files and directories based on the provided template files.
42
- *
43
- * This method iterates through the template files and writes their content
44
- * to the file system. It handles both files and directories, ensuring that
45
- * the directory structure is preserved.
46
- *
47
- * @param result - The result object containing the name and template name.
48
- *
49
- * @returns A promise that resolves when all files have been created.
50
- *
51
- * @example
52
- * const result = { name: 'my-app', template: 'react-app' };
53
- * await this.create(result);
54
- */
55
- create(result: GeneratorResult): Promise<void>;
56
70
  private isPackageTemplate;
57
- getGeneratorResult(): Promise<GeneratorResult>;
71
+ private getGeneratorResult;
72
+ private copyConfigs;
58
73
  generate(): Promise<void>;
74
+ private generateTemplateDir;
75
+ private generateSubPackages;
59
76
  }
60
77
 
61
78
  declare const validRequiredString: (value: string, key: string) => string | true;
62
- declare const defaultPrompts: GeneratorPrompt[];
63
- declare const packagePrompts: GeneratorPrompt[];
79
+ declare function createDefaultPrompts(templates: string[], packages: string[]): GeneratorPrompt[];
80
+ declare function createPackagePrompts(templates: string[]): GeneratorPrompt[];
64
81
 
82
+ type CopyCallback = (sourceFilePath: string, targetFilePath: string) => boolean | Promise<boolean>;
65
83
  declare class Copyer {
84
+ private readonly ignoreTargetPath;
85
+ private readonly ignoreFile;
66
86
  static IGNORE_FILE: string;
67
- getIg(targetDir: string): ignore.Ignore | undefined;
87
+ constructor(ignoreTargetPath: string, ignoreFile?: string);
88
+ getIg(targetDir?: string): ignore.Ignore | undefined;
68
89
  ensureDir(dir: string): void;
69
90
  /**
70
91
  * Asynchronously copy files from source to target directory.
@@ -75,18 +96,12 @@ declare class Copyer {
75
96
  * @example
76
97
  * await copyer.copyFilesPromise('src', 'dest', ignoreInstance);
77
98
  */
78
- copyFilesPromise(sourcePath: string, targetDir: string, ig?: ignore.Ignore): Promise<void>;
79
- /**
80
- * copy templates recursively
81
- * @param {string} sourePath - source directory
82
- * @param {string} targetDir - target directory
83
- * @param {ignore.Ignore} ig - ignore rules
84
- */
85
- copyFilesSync(sourePath: string, targetDir: string, ig?: ignore.Ignore): void;
86
- create(result: GeneratorResult): void;
87
- createPromise(result: GeneratorResult): Promise<void>;
88
- createPath(result: GeneratorResult): void;
89
- createPathPromise(result: GeneratorResult): Promise<void>;
99
+ copyFiles(sourcePath: string, targetDir: string, ig?: ignore.Ignore, copyCallback?: CopyCallback): Promise<void>;
100
+ copyPaths({ sourcePath, targetPath, copyCallback }: {
101
+ sourcePath: string;
102
+ targetPath: string;
103
+ copyCallback?: CopyCallback;
104
+ }): Promise<void>;
90
105
  }
91
106
 
92
- export { Copyer, Generator, type GeneratorOptions, type GeneratorPrompt, type GeneratorResult, type TaskOptions, type TemplateFile, defaultPrompts, packagePrompts, validRequiredString };
107
+ export { type CopyCallback, Copyer, Generator, type GeneratorOptions, type GeneratorPrompt, type GeneratorRuntimes, type TaskOptions, type TemplateFile, createDefaultPrompts, createPackagePrompts, validRequiredString };
package/dist/cjs/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";var t=require("@qlover/fe-scripts"),e=require("inquirer"),a=require("path"),r=require("ora"),s=require("fs"),i=require("ignore");const o=(t,e)=>"string"==typeof t&&""!==t.trim()||`${e} is required`,n=["node-lib","react-app","react-vite-lib"],c=[{type:"input",name:"name",message:"Project name",validate:t=>o(t,"Project name")},{type:"list",name:"template",message:"Template name",choices:[...n,"pack-app"]}],p=[{type:"checkbox",name:"subPackages",message:"Sub package names",choices:n}],{copyFile:h,stat:m}=s.promises;class l{static IGNORE_FILE=".gitignore.template";getIg(t){const e=a.join(t,l.IGNORE_FILE);if(!s.existsSync(e))return;const r=s.readFileSync(e,"utf8").split("\n").map((t=>t.trim())).filter((t=>t&&!t.startsWith("#")));return i().add(r)}ensureDir(t){s.existsSync(t)||s.mkdirSync(t,{recursive:!0})}async copyFilesPromise(t,e,r){const i=await s.promises.readdir(t);await Promise.all(i.map((async s=>{const i=a.join(t,s),o=a.join(e,s);if(r&&r.ignores(s))return;this.ensureDir(a.dirname(o));(await m(i)).isDirectory()?await this.copyFilesPromise(i,o,r):await h(i,o)})))}copyFilesSync(t,e,r){const i=s.readdirSync(t);for(const o of i){const i=a.join(t,o),n=a.join(e,o);r&&r.ignores(o)||(this.ensureDir(a.dirname(n)),s.statSync(i).isDirectory()?this.copyFilesSync(i,n,r):s.copyFileSync(i,n))}}create(t){const{targetPath:e,templateRootPath:r,subPackages:s,packagesNames:i="packages"}=t;if(!e||!r)throw new Error("targetPath and templatePath are required");if(this.createPath(t),s)for(const r of s){const s=a.join(e,i,r);this.createPath({...t,targetPath:s,template:r})}}async createPromise(t){const{targetPath:e,templateRootPath:r,subPackages:s,packagesNames:i="packages"}=t;if(!e||!r)throw new Error("targetPath and templatePath are required");if(await this.createPathPromise(t),s)for(const r of s){const s=a.join(e,i,r);await this.createPathPromise({...t,targetPath:s,template:r})}}createPath(t){const{targetPath:e="",templateRootPath:r,template:s}=t;this.ensureDir(e);const i=a.join(r,s),o=this.getIg(e);this.copyFilesSync(i,e,o)}createPathPromise(t){const{targetPath:e="",templateRootPath:r,template:s}=t;this.ensureDir(e);const i=a.join(r,s),o=this.getIg(e);return this.copyFilesPromise(i,e,o)}}exports.Copyer=l,exports.Generator=class{ora;context;constructor(e){const a=e.options?.templateRootPath;if(!a)throw new Error("template path not exit");if(!s.existsSync(a))throw new Error("template path not exit");this.ora=r.oraPromise,this.context=new t.FeScriptContext(e)}get logger(){return this.context.logger}async steps(t){try{return await e.prompt(t)}catch(t){throw this.logger.error(t),t}}async action({label:t,task:e}){let a=e();a instanceof Promise||(a=Promise.resolve(a));const r=t;return this.ora(a,r),a}async create(t){const e=a.join(process.cwd(),t.name),r=new l,s={...t,targetPath:e,templateRootPath:this.context.options.templateRootPath};return this.logger.debug(s),r.createPromise(s)}isPackageTemplate(t){return"pack-app"===t}async getGeneratorResult(){const t=await this.steps(c);if(this.isPackageTemplate(t.template)){const e=await this.steps(p);Object.assign(t,e)}return t}async generate(){const t=await this.getGeneratorResult();await this.action({label:"Creating project",task:()=>this.create(t)})}},exports.defaultPrompts=c,exports.packagePrompts=p,exports.validRequiredString=o;
1
+ "use strict";var t=require("@qlover/scripts-context"),e=require("inquirer"),a=require("path"),s=require("ora"),i=require("fs"),r=require("ignore");const o=(t,e)=>"string"==typeof t&&""!==t.trim()||`${e} is required`;function n(t,e){return[{type:"input",name:"name",message:"Project name",validate:t=>o(t,"Project name")},{type:"list",name:"template",message:"Template name",choices:[...t,...e]}]}function c(t){return[{type:"checkbox",name:"subPackages",message:"Sub package names",choices:t}]}const{copyFile:g,stat:p}=i.promises;class h{ignoreTargetPath;ignoreFile;static IGNORE_FILE=".gitignore.template";constructor(t,e=h.IGNORE_FILE){this.ignoreTargetPath=t,this.ignoreFile=e}getIg(t=this.ignoreTargetPath){const e=a.join(t,this.ignoreFile);if(!i.existsSync(e))return;const s=i.readFileSync(e,"utf8").split("\n").map((t=>t.trim())).filter((t=>t&&!t.startsWith("#")));return r().add(s)}ensureDir(t){i.existsSync(t)||i.mkdirSync(t,{recursive:!0})}async copyFiles(t,e,s,r){const o=await i.promises.readdir(t);await Promise.all(o.map((async i=>{const o=a.join(t,i),n=a.join(e,i);if(s&&s.ignores(i))return;this.ensureDir(a.dirname(n));if((await p(o)).isDirectory())await this.copyFiles(o,n,s);else{if(r&&await r(o,n))return;await g(o,n)}})))}copyPaths({sourcePath:t,targetPath:e,copyCallback:a}){this.ensureDir(e);const s=this.getIg();return this.copyFiles(t,e,s,a)}}const l=["pack-app"];exports.Copyer=h,exports.Generator=class{ora;context;subPackages;copyer;constructor(e){const r=e.options?.templateRootPath;if(!r)throw new Error("template path not exit");if(!i.existsSync(r))throw new Error("template path not exit");this.ora=s.oraPromise,this.context=new t.FeScriptContext(e),this.subPackages=["node-lib","react-app"],this.copyer=new h(a.join(this.context.options.configsRootPath,"_common"))}get logger(){return this.context.logger}async steps(t){try{return await e.prompt(t)}catch(t){throw this.logger.error(t),t}}async action({label:t,task:e}){let a=e();a instanceof Promise||(a=Promise.resolve(a));const s=t;return this.ora(a,s),a}isPackageTemplate(t){return l.includes(t)}async getGeneratorResult(){const t=n(this.subPackages,l),e=await this.steps(t);if(this.isPackageTemplate(e.template)){const t=c(this.subPackages),a=await this.steps(t);Object.assign(e,a)}return e}async copyConfigs(t,e){const{configsRootPath:s,config:i}=this.context.options;i?await this.copyer.copyPaths({sourcePath:a.join(s,e),targetPath:t,copyCallback:(t,e)=>(this.logger.debug("copyCallback",t,e),!1)}):this.logger.debug("no copy config files")}async generate(){const t=await this.getGeneratorResult();t.targetPath=a.join(process.cwd(),t.name),this.logger.debug("result is:",t,this.context.options.templateRootPath),t.subPackages?await this.action({label:"Generate Directories(subPackages)",task:async()=>{await this.generateTemplateDir(t),await this.generateSubPackages(t),await this.copyConfigs(t.targetPath,"_common")}}):await this.action({label:"Generate Directory",task:async()=>{await this.generateTemplateDir(t),await this.copyConfigs(t.targetPath,"_common"),await this.copyConfigs(t.targetPath,t.template)}})}generateTemplateDir(t){return this.copyer.copyPaths({sourcePath:a.join(this.context.options.templateRootPath,t.template),targetPath:t.targetPath})}async generateSubPackages(t){const{packagesNames:e="packages",subPackages:s=[],targetPath:i=""}=t,{templateRootPath:r}=this.context.options;for(const t of s){const s=a.join(r,t),o=a.join(i,e,t);this.logger.debug("copy sub package",s,o),await this.copyer.copyPaths({sourcePath:s,targetPath:o})}}},exports.createDefaultPrompts=n,exports.createPackagePrompts=c,exports.validRequiredString=o;