@icebreakers/monorepo-templates 0.1.16 → 1.0.0
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.
- package/README.md +12 -0
- package/assets/.changeset/config.json +7 -2
- package/assets/.github/workflows/ci.yml +8 -2
- package/assets/.github/workflows/release.yml +2 -2
- package/assets/.husky/commit-msg +1 -1
- package/assets/.husky/pre-commit +1 -1
- package/assets/.husky/pre-push +5 -0
- package/assets/AGENTS.md +8 -7
- package/assets/commitlint.config.ts +2 -2
- package/assets/eslint.config.js +2 -6
- package/assets/lint-staged.config.js +3 -0
- package/assets/package.json +39 -28
- package/assets/repoctl.config.ts +68 -0
- package/assets/stylelint.config.js +2 -2
- package/assets/tooling/ensure-tooling-built.mjs +24 -0
- package/assets/tooling/load-tooling-module.mjs +71 -0
- package/assets/tsconfig.json +1 -49
- package/assets/turbo.json +17 -6
- package/assets/vitest.config.ts +2 -125
- package/assets-data.mjs +4 -2
- package/dist/index.d.mts +22 -1
- package/dist/index.mjs +114 -30
- package/package.json +12 -8
- package/template-data.mjs +48 -8
- package/templates/client/eslint.config.js +6 -4
- package/templates/client/package.json +22 -22
- package/templates/client/vite.config.ts +4 -3
- package/templates/client/wrangler.jsonc +1 -6
- package/templates/server/package.json +4 -4
- package/templates/server/src/app.ts +4 -4
- package/templates/server/tsconfig.json +1 -2
- package/templates/server/vitest.config.ts +6 -5
- package/templates/server/wrangler.jsonc +1 -6
- package/templates/tsdown/package.json +2 -1
- package/templates/tsdown/test-d/index.test-d.ts +5 -0
- package/templates/tsdown/tsconfig.json +1 -2
- package/templates/tsdown/vitest.config.ts +6 -5
- package/templates/vitepress/.vitepress/config.ts +34 -36
- package/templates/vitepress/getting-started.md +243 -0
- package/templates/vitepress/gitignore +2 -1
- package/templates/vitepress/index.md +144 -79
- package/templates/vitepress/monorepo/commands.md +281 -0
- package/templates/vitepress/monorepo/index.md +103 -34
- package/templates/vitepress/monorepo/manage.md +181 -80
- package/templates/vitepress/monorepo/publish.md +128 -57
- package/templates/vitepress/monorepo/templates.md +67 -0
- package/templates/vitepress/monorepo/troubleshooting.md +207 -0
- package/templates/vitepress/package.json +5 -5
- package/templates/vitepress/thinking.md +1 -1
- package/templates/vitepress/tools/husky.md +7 -2
- package/templates/vitepress/tools/lint-staged.md +15 -1
- package/templates/vitepress/why/examples/usage-cjs/index.js +2 -6
- package/templates/vitepress/why/examples/usage-cjs/package-lock.json +7 -13
- package/templates/vitepress/why/examples/usage-cjs/package.json +2 -2
- package/templates/vitepress/why/examples/usage-esm/index.js +2 -2
- package/templates/vitepress/why/examples/usage-esm/package-lock.json +7 -13
- package/templates/vitepress/why/examples/usage-esm/package.json +2 -2
- package/templates/vitepress/why/modern/bundlers.md +8 -46
- package/templates/vue-lib/eslint.config.js +6 -4
- package/templates/vue-lib/package.json +17 -12
- package/templates/vue-lib/test-d/index.test-d.ts +6 -0
- package/templates/vue-lib/tsconfig.test.json +1 -1
- package/templates/vue-lib/vitest.config.ts +8 -5
- package/assets/monorepo.config.ts +0 -22
- package/assets/nano-staged.js +0 -18
- package/templates/tsup/build.config.ts +0 -24
- package/templates/tsup/package.json +0 -49
- package/templates/tsup/src/index.ts +0 -12
- package/templates/tsup/test/index.test.ts +0 -18
- package/templates/tsup/tsconfig.json +0 -15
- package/templates/tsup/tsup.config.ts +0 -18
- package/templates/tsup/vitest.config.ts +0 -15
- package/templates/unbuild/build.config.ts +0 -24
- package/templates/unbuild/package.json +0 -49
- package/templates/unbuild/src/index.ts +0 -9
- package/templates/unbuild/src/utils.ts +0 -5
- package/templates/unbuild/test/index.test.ts +0 -18
- package/templates/unbuild/tsconfig.json +0 -15
- package/templates/unbuild/vitest.config.ts +0 -15
package/assets/vitest.config.ts
CHANGED
|
@@ -1,127 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
import { fileURLToPath } from 'node:url'
|
|
1
|
+
import { defineVitestConfig } from 'repoctl/tooling'
|
|
4
2
|
import { defineConfig } from 'vitest/config'
|
|
5
|
-
import YAML from 'yaml'
|
|
6
3
|
|
|
7
|
-
|
|
8
|
-
const WORKSPACE_FILE = path.resolve(ROOT_DIR, 'pnpm-workspace.yaml')
|
|
9
|
-
const CONFIG_FILENAMES = [
|
|
10
|
-
'vitest.config.ts',
|
|
11
|
-
'vitest.config.mts',
|
|
12
|
-
'vitest.config.cts',
|
|
13
|
-
'vitest.config.js',
|
|
14
|
-
'vitest.config.cjs',
|
|
15
|
-
'vitest.config.mjs',
|
|
16
|
-
] as const
|
|
17
|
-
const WINDOWS_PATH_SEPARATOR_RE = /\\/g
|
|
18
|
-
const RELATIVE_CURRENT_DIR_RE = /^\.\//
|
|
19
|
-
const GLOB_TOKEN_RE = /[*?[{]/
|
|
20
|
-
const TRAILING_SLASH_RE = /\/+$/
|
|
21
|
-
|
|
22
|
-
function extractBaseDirFromGlob(pattern: string): string | null {
|
|
23
|
-
if (!pattern) {
|
|
24
|
-
return null
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const normalized = pattern
|
|
28
|
-
.replace(WINDOWS_PATH_SEPARATOR_RE, '/')
|
|
29
|
-
.replace(RELATIVE_CURRENT_DIR_RE, '')
|
|
30
|
-
const globIndex = normalized.search(GLOB_TOKEN_RE)
|
|
31
|
-
const base = globIndex === -1
|
|
32
|
-
? normalized
|
|
33
|
-
: normalized.slice(0, globIndex)
|
|
34
|
-
|
|
35
|
-
const cleaned = base.replace(TRAILING_SLASH_RE, '')
|
|
36
|
-
return cleaned || null
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function loadProjectRootsFromWorkspace(): string[] {
|
|
40
|
-
if (!fs.existsSync(WORKSPACE_FILE)) {
|
|
41
|
-
return []
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
try {
|
|
45
|
-
const workspaceContent = fs.readFileSync(WORKSPACE_FILE, 'utf8')
|
|
46
|
-
const workspace = YAML.parse(workspaceContent) ?? {}
|
|
47
|
-
const packages: unknown[] = Array.isArray(workspace.packages) ? workspace.packages : []
|
|
48
|
-
const roots = packages
|
|
49
|
-
.map(entry => typeof entry === 'string' ? entry.trim() : '')
|
|
50
|
-
.filter(entry => entry && !entry.startsWith('!'))
|
|
51
|
-
.map(extractBaseDirFromGlob)
|
|
52
|
-
.filter((entry): entry is string => Boolean(entry))
|
|
53
|
-
|
|
54
|
-
return roots.length ? [...new Set(roots)] : []
|
|
55
|
-
}
|
|
56
|
-
catch (error) {
|
|
57
|
-
console.warn('[vitest] Failed to parse pnpm-workspace.yaml, no project roots will be used.', error)
|
|
58
|
-
return []
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const PROJECT_ROOTS = loadProjectRootsFromWorkspace()
|
|
63
|
-
|
|
64
|
-
if (!PROJECT_ROOTS.length) {
|
|
65
|
-
console.warn('[vitest] No project roots detected. Check pnpm-workspace.yaml to define workspace packages.')
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function findConfig(basePath: string): string | null {
|
|
69
|
-
for (const filename of CONFIG_FILENAMES) {
|
|
70
|
-
const candidate = path.join(basePath, filename)
|
|
71
|
-
if (fs.existsSync(candidate)) {
|
|
72
|
-
return candidate
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return null
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function resolveProjects(): string[] {
|
|
79
|
-
const projects: string[] = []
|
|
80
|
-
|
|
81
|
-
for (const folder of PROJECT_ROOTS) {
|
|
82
|
-
const rootPath = path.resolve(ROOT_DIR, folder)
|
|
83
|
-
if (!fs.existsSync(rootPath)) {
|
|
84
|
-
continue
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const rootConfig = findConfig(rootPath)
|
|
88
|
-
if (rootConfig) {
|
|
89
|
-
projects.push(rootConfig)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const entries = fs.readdirSync(rootPath, { withFileTypes: true })
|
|
93
|
-
for (const entry of entries) {
|
|
94
|
-
if (!entry.isDirectory()) {
|
|
95
|
-
continue
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const projectDir = path.join(rootPath, entry.name)
|
|
99
|
-
const configPath = findConfig(projectDir)
|
|
100
|
-
if (configPath) {
|
|
101
|
-
projects.push(configPath)
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return projects
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const projects = resolveProjects()
|
|
110
|
-
|
|
111
|
-
export default defineConfig(() => {
|
|
112
|
-
return {
|
|
113
|
-
test: {
|
|
114
|
-
projects,
|
|
115
|
-
coverage: {
|
|
116
|
-
enabled: true,
|
|
117
|
-
skipFull: true,
|
|
118
|
-
exclude: [
|
|
119
|
-
'**/dist/**',
|
|
120
|
-
],
|
|
121
|
-
},
|
|
122
|
-
forceRerunTriggers: [
|
|
123
|
-
'**/{vitest,vite}.config.*/**',
|
|
124
|
-
],
|
|
125
|
-
},
|
|
126
|
-
}
|
|
127
|
-
})
|
|
4
|
+
export default defineConfig(async () => await defineVitestConfig())
|
package/assets-data.mjs
CHANGED
|
@@ -8,13 +8,15 @@ const coreAssetTargets = [
|
|
|
8
8
|
'.npmrc',
|
|
9
9
|
'commitlint.config.ts',
|
|
10
10
|
'eslint.config.js',
|
|
11
|
-
'
|
|
11
|
+
'lint-staged.config.js',
|
|
12
12
|
'stylelint.config.js',
|
|
13
|
-
'
|
|
13
|
+
'repoctl.config.ts',
|
|
14
14
|
'package.json',
|
|
15
15
|
'AGENTS.md',
|
|
16
16
|
// pnpm
|
|
17
17
|
'pnpm-workspace.yaml',
|
|
18
|
+
'scripts',
|
|
19
|
+
'tooling',
|
|
18
20
|
// base tsconfig
|
|
19
21
|
'tsconfig.json',
|
|
20
22
|
// turbo
|
package/dist/index.d.mts
CHANGED
|
@@ -4,16 +4,25 @@ import select from "@inquirer/select";
|
|
|
4
4
|
import { Command, program } from "commander";
|
|
5
5
|
|
|
6
6
|
//#region src/types.d.ts
|
|
7
|
+
type TemplateCategory = 'app' | 'docs' | 'library' | 'service' | 'tool';
|
|
7
8
|
interface TemplateChoice {
|
|
8
9
|
key: string;
|
|
9
10
|
label: string;
|
|
10
11
|
source: string;
|
|
11
12
|
target: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
category?: TemplateCategory;
|
|
12
15
|
}
|
|
13
16
|
interface TemplateDefinition {
|
|
14
17
|
source: string;
|
|
15
18
|
target: string;
|
|
16
19
|
}
|
|
20
|
+
interface GetTemplateChoicesOptions {
|
|
21
|
+
category?: TemplateCategory;
|
|
22
|
+
}
|
|
23
|
+
interface SuggestTemplateKeyOptions extends GetTemplateChoicesOptions {
|
|
24
|
+
keys?: readonly string[];
|
|
25
|
+
}
|
|
17
26
|
//#endregion
|
|
18
27
|
//#region src/paths.d.ts
|
|
19
28
|
declare const packageDir: string;
|
|
@@ -74,6 +83,18 @@ declare function isGitignoreFile(name: string): boolean;
|
|
|
74
83
|
declare function shouldSkipTemplatePath(rootDir: string, targetPath: string): boolean;
|
|
75
84
|
declare function createTemplateCopyFilter(rootDir: string): (src: string) => boolean;
|
|
76
85
|
//#endregion
|
|
86
|
+
//#region src/templates.d.ts
|
|
87
|
+
declare const templateCategories: readonly ["app", "docs", "library", "service", "tool"];
|
|
88
|
+
declare function isTemplateCategory(value: string): value is TemplateCategory;
|
|
89
|
+
declare function getTemplateChoices(options?: GetTemplateChoicesOptions): TemplateChoice[];
|
|
90
|
+
declare function getTemplateKeys(options?: GetTemplateChoicesOptions): string[];
|
|
91
|
+
declare function getTemplateChoice(key: string): TemplateChoice | undefined;
|
|
92
|
+
declare function isTemplateKey(key: string): boolean;
|
|
93
|
+
declare function getTemplateDefinition(key: string): TemplateDefinition | undefined;
|
|
94
|
+
declare function getTemplateSource(key: string): string | undefined;
|
|
95
|
+
declare function getTemplateTarget(key: string): string | undefined;
|
|
96
|
+
declare function suggestTemplateKey(key: string, options?: SuggestTemplateKeyOptions): string | undefined;
|
|
97
|
+
//#endregion
|
|
77
98
|
//#region src/index.d.ts
|
|
78
99
|
declare const templateChoices: TemplateChoice[];
|
|
79
100
|
declare const assetTargets: string[];
|
|
@@ -82,4 +103,4 @@ declare const templateSourceMap: Record<string, string>;
|
|
|
82
103
|
declare const templateTargetMap: Record<string, string>;
|
|
83
104
|
declare const templateMap: Record<string, string>;
|
|
84
105
|
//#endregion
|
|
85
|
-
export { Command, type TemplateChoice, type TemplateDefinition, assetTargets, assetsDir, checkbox, createTemplateCopyFilter, ensureTemplateAssetsPrepared, execaCommand, getAssetTargets, input, isGitignoreFile, packageDir, prepareAssets, program, runCommand, scaffoldTemplate, scaffoldWorkspace, select, shouldSkipTemplatePath, skeletonDir, templateChoices, templateMap, templateSourceMap, templateTargetMap, templatesDir, toPublishGitignorePath, toWorkspaceGitignorePath };
|
|
106
|
+
export { Command, type GetTemplateChoicesOptions, type SuggestTemplateKeyOptions, type TemplateCategory, type TemplateChoice, type TemplateDefinition, assetTargets, assetsDir, checkbox, createTemplateCopyFilter, ensureTemplateAssetsPrepared, execaCommand, getAssetTargets, getTemplateChoice, getTemplateChoices, getTemplateDefinition, getTemplateKeys, getTemplateSource, getTemplateTarget, input, isGitignoreFile, isTemplateCategory, isTemplateKey, packageDir, prepareAssets, program, runCommand, scaffoldTemplate, scaffoldWorkspace, select, shouldSkipTemplatePath, skeletonDir, suggestTemplateKey, templateCategories, templateChoices, templateMap, templateSourceMap, templateTargetMap, templatesDir, toPublishGitignorePath, toWorkspaceGitignorePath };
|
package/dist/index.mjs
CHANGED
|
@@ -18,12 +18,14 @@ const coreAssetTargets = [
|
|
|
18
18
|
".npmrc",
|
|
19
19
|
"commitlint.config.ts",
|
|
20
20
|
"eslint.config.js",
|
|
21
|
-
"
|
|
21
|
+
"lint-staged.config.js",
|
|
22
22
|
"stylelint.config.js",
|
|
23
|
-
"
|
|
23
|
+
"repoctl.config.ts",
|
|
24
24
|
"package.json",
|
|
25
25
|
"AGENTS.md",
|
|
26
26
|
"pnpm-workspace.yaml",
|
|
27
|
+
"scripts",
|
|
28
|
+
"tooling",
|
|
27
29
|
"tsconfig.json",
|
|
28
30
|
"turbo.json",
|
|
29
31
|
"vitest.config.ts",
|
|
@@ -44,64 +46,64 @@ function getAssetTargets$1(core = false) {
|
|
|
44
46
|
return core ? [...coreAssetTargets] : [...assetTargets$1];
|
|
45
47
|
}
|
|
46
48
|
//#endregion
|
|
49
|
+
//#region src/paths.ts
|
|
50
|
+
const packageDir = path$1.resolve(fileURLToPath(new URL("../", import.meta.url)));
|
|
51
|
+
const templatesDir = path$1.join(packageDir, "templates");
|
|
52
|
+
const assetsDir = path$1.join(packageDir, "assets");
|
|
53
|
+
const skeletonDir = assetsDir;
|
|
54
|
+
//#endregion
|
|
47
55
|
//#region template-data.mjs
|
|
48
56
|
const templateChoices$1 = [
|
|
49
|
-
{
|
|
50
|
-
key: "unbuild",
|
|
51
|
-
label: "unbuild 打包",
|
|
52
|
-
source: "unbuild",
|
|
53
|
-
target: "packages/unbuild"
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
key: "tsup",
|
|
57
|
-
label: "tsup 打包",
|
|
58
|
-
source: "tsup",
|
|
59
|
-
target: "packages/tsup"
|
|
60
|
-
},
|
|
61
57
|
{
|
|
62
58
|
key: "tsdown",
|
|
63
59
|
label: "tsdown 打包",
|
|
64
60
|
source: "tsdown",
|
|
65
|
-
target: "packages/tsdown"
|
|
61
|
+
target: "packages/tsdown",
|
|
62
|
+
category: "library",
|
|
63
|
+
description: "使用 tsdown 构建的 TypeScript 库包"
|
|
66
64
|
},
|
|
67
65
|
{
|
|
68
66
|
key: "vue-lib",
|
|
69
67
|
label: "vue 组件",
|
|
70
68
|
source: "vue-lib",
|
|
71
|
-
target: "packages/vue-lib"
|
|
69
|
+
target: "packages/vue-lib",
|
|
70
|
+
category: "library",
|
|
71
|
+
description: "Vue 3 组件库模板,适合沉淀可复用 UI"
|
|
72
72
|
},
|
|
73
73
|
{
|
|
74
74
|
key: "vue-hono",
|
|
75
75
|
label: "vue hono 全栈",
|
|
76
76
|
source: "client",
|
|
77
|
-
target: "apps/client"
|
|
77
|
+
target: "apps/client",
|
|
78
|
+
category: "app",
|
|
79
|
+
description: "Vue 3 + Hono 的前后端一体应用模板"
|
|
78
80
|
},
|
|
79
81
|
{
|
|
80
82
|
key: "hono-server",
|
|
81
83
|
label: "hono 模板",
|
|
82
84
|
source: "server",
|
|
83
|
-
target: "apps/server"
|
|
85
|
+
target: "apps/server",
|
|
86
|
+
category: "service",
|
|
87
|
+
description: "Hono API 服务模板"
|
|
84
88
|
},
|
|
85
89
|
{
|
|
86
90
|
key: "vitepress",
|
|
87
91
|
label: "vitepress 文档",
|
|
88
92
|
source: "vitepress",
|
|
89
|
-
target: "apps/website"
|
|
93
|
+
target: "apps/website",
|
|
94
|
+
category: "docs",
|
|
95
|
+
description: "VitePress 文档站模板"
|
|
90
96
|
},
|
|
91
97
|
{
|
|
92
98
|
key: "cli",
|
|
93
99
|
label: "cli 模板",
|
|
94
100
|
source: "cli",
|
|
95
|
-
target: "apps/cli"
|
|
101
|
+
target: "apps/cli",
|
|
102
|
+
category: "tool",
|
|
103
|
+
description: "TypeScript 命令行工具模板"
|
|
96
104
|
}
|
|
97
105
|
];
|
|
98
106
|
//#endregion
|
|
99
|
-
//#region src/paths.ts
|
|
100
|
-
const packageDir = path$1.resolve(fileURLToPath(new URL("../", import.meta.url)));
|
|
101
|
-
const templatesDir = path$1.join(packageDir, "templates");
|
|
102
|
-
const assetsDir = path$1.join(packageDir, "assets");
|
|
103
|
-
const skeletonDir = assetsDir;
|
|
104
|
-
//#endregion
|
|
105
107
|
//#region src/utils/gitignore.ts
|
|
106
108
|
const publishBasename = "gitignore";
|
|
107
109
|
const workspaceBasename = ".gitignore";
|
|
@@ -156,6 +158,7 @@ function shouldSkipTemplatePath(rootDir, targetPath) {
|
|
|
156
158
|
const basename = path.basename(targetPath);
|
|
157
159
|
if (skipFiles.has(basename)) return true;
|
|
158
160
|
if (basename.endsWith(".tsbuildinfo")) return true;
|
|
161
|
+
if (/\.timestamp-\d+-[a-z0-9]+\.mjs$/i.test(basename)) return true;
|
|
159
162
|
const relative = path.relative(rootDir, targetPath);
|
|
160
163
|
if (!relative || relative.startsWith("..")) return false;
|
|
161
164
|
const segments = relative.split(path.sep);
|
|
@@ -223,8 +226,11 @@ async function copyEntry(from, to, overwriteExisting, filter) {
|
|
|
223
226
|
}
|
|
224
227
|
}
|
|
225
228
|
async function copyAssets(repoRoot, overwriteExisting) {
|
|
229
|
+
const monorepoAssetRoot = path$1.resolve(repoRoot, "packages/monorepo/assets");
|
|
226
230
|
for (const target of assetTargets$1) {
|
|
227
|
-
const
|
|
231
|
+
const packageAsset = path$1.join(monorepoAssetRoot, toPublishGitignorePath(target));
|
|
232
|
+
const repoAsset = path$1.join(repoRoot, target);
|
|
233
|
+
const from = await pathExists$1(packageAsset) ? packageAsset : repoAsset;
|
|
228
234
|
if (!await pathExists$1(from)) continue;
|
|
229
235
|
const to = path$1.join(assetsDir, toPublishGitignorePath(target));
|
|
230
236
|
const stats = await fs.stat(from);
|
|
@@ -277,7 +283,7 @@ async function isPrepared() {
|
|
|
277
283
|
const checks = [
|
|
278
284
|
path.join(assetsDir, "AGENTS.md"),
|
|
279
285
|
path.join(assetsDir, "LICENSE"),
|
|
280
|
-
path.join(templatesDir, "
|
|
286
|
+
path.join(templatesDir, "tsdown")
|
|
281
287
|
];
|
|
282
288
|
return (await Promise.all(checks.map(pathExists))).every(Boolean);
|
|
283
289
|
}
|
|
@@ -399,6 +405,84 @@ async function scaffoldWorkspace(options) {
|
|
|
399
405
|
}
|
|
400
406
|
}
|
|
401
407
|
//#endregion
|
|
408
|
+
//#region src/templates.ts
|
|
409
|
+
const templateCategories = [
|
|
410
|
+
"app",
|
|
411
|
+
"docs",
|
|
412
|
+
"library",
|
|
413
|
+
"service",
|
|
414
|
+
"tool"
|
|
415
|
+
];
|
|
416
|
+
const choices = templateChoices$1;
|
|
417
|
+
const categorySet = new Set(templateCategories);
|
|
418
|
+
function cloneTemplateChoice(choice) {
|
|
419
|
+
return { ...choice };
|
|
420
|
+
}
|
|
421
|
+
function isTemplateCategory(value) {
|
|
422
|
+
return categorySet.has(value);
|
|
423
|
+
}
|
|
424
|
+
function getTemplateChoices(options = {}) {
|
|
425
|
+
const { category } = options;
|
|
426
|
+
return (category ? choices.filter((choice) => choice.category === category) : choices).map(cloneTemplateChoice);
|
|
427
|
+
}
|
|
428
|
+
function getTemplateKeys(options = {}) {
|
|
429
|
+
return getTemplateChoices(options).map((choice) => choice.key);
|
|
430
|
+
}
|
|
431
|
+
function getTemplateChoice(key) {
|
|
432
|
+
const choice = choices.find((item) => item.key === key);
|
|
433
|
+
return choice ? cloneTemplateChoice(choice) : void 0;
|
|
434
|
+
}
|
|
435
|
+
function isTemplateKey(key) {
|
|
436
|
+
return choices.some((choice) => choice.key === key);
|
|
437
|
+
}
|
|
438
|
+
function getTemplateDefinition(key) {
|
|
439
|
+
const choice = getTemplateChoice(key);
|
|
440
|
+
if (!choice) return;
|
|
441
|
+
return {
|
|
442
|
+
source: choice.source,
|
|
443
|
+
target: choice.target
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
function getTemplateSource(key) {
|
|
447
|
+
return getTemplateChoice(key)?.source;
|
|
448
|
+
}
|
|
449
|
+
function getTemplateTarget(key) {
|
|
450
|
+
return getTemplateChoice(key)?.target;
|
|
451
|
+
}
|
|
452
|
+
function getEditDistance(left, right) {
|
|
453
|
+
const previous = Array.from({ length: right.length + 1 }, (_, index) => index);
|
|
454
|
+
for (let leftIndex = 1; leftIndex <= left.length; leftIndex += 1) {
|
|
455
|
+
const current = [leftIndex];
|
|
456
|
+
for (let rightIndex = 1; rightIndex <= right.length; rightIndex += 1) {
|
|
457
|
+
const substitutionCost = left[leftIndex - 1] === right[rightIndex - 1] ? 0 : 1;
|
|
458
|
+
current[rightIndex] = Math.min((current[rightIndex - 1] ?? 0) + 1, (previous[rightIndex] ?? 0) + 1, (previous[rightIndex - 1] ?? 0) + substitutionCost);
|
|
459
|
+
}
|
|
460
|
+
previous.splice(0, previous.length, ...current);
|
|
461
|
+
}
|
|
462
|
+
return previous[right.length] ?? 0;
|
|
463
|
+
}
|
|
464
|
+
function getTemplateSuggestionThreshold(value) {
|
|
465
|
+
if (value.length <= 4) return 1;
|
|
466
|
+
if (value.length <= 8) return 2;
|
|
467
|
+
return 3;
|
|
468
|
+
}
|
|
469
|
+
function suggestTemplateKey(key, options = {}) {
|
|
470
|
+
const normalizedKey = key.trim().toLowerCase();
|
|
471
|
+
if (!normalizedKey) return;
|
|
472
|
+
const keys = options.keys ? [...options.keys] : getTemplateKeys(options);
|
|
473
|
+
const prefixMatch = keys.find((candidate) => {
|
|
474
|
+
const normalizedCandidate = candidate.toLowerCase();
|
|
475
|
+
return normalizedCandidate.startsWith(normalizedKey) || normalizedKey.startsWith(normalizedCandidate);
|
|
476
|
+
});
|
|
477
|
+
if (prefixMatch) return prefixMatch;
|
|
478
|
+
const [best] = keys.map((candidate) => ({
|
|
479
|
+
key: candidate,
|
|
480
|
+
distance: getEditDistance(normalizedKey, candidate.toLowerCase())
|
|
481
|
+
})).sort((left, right) => left.distance - right.distance || left.key.localeCompare(right.key));
|
|
482
|
+
if (!best || best.distance > getTemplateSuggestionThreshold(normalizedKey)) return;
|
|
483
|
+
return best.key;
|
|
484
|
+
}
|
|
485
|
+
//#endregion
|
|
402
486
|
//#region src/utils/command.ts
|
|
403
487
|
async function runCommand(command, args, options = {}) {
|
|
404
488
|
const result = await exec(command, args, {
|
|
@@ -419,11 +503,11 @@ async function execaCommand(command, options = {}) {
|
|
|
419
503
|
}
|
|
420
504
|
//#endregion
|
|
421
505
|
//#region src/index.ts
|
|
422
|
-
const templateChoices =
|
|
506
|
+
const templateChoices = getTemplateChoices();
|
|
423
507
|
const assetTargets = assetTargets$1;
|
|
424
508
|
const getAssetTargets = getAssetTargets$1;
|
|
425
509
|
const templateSourceMap = Object.fromEntries(templateChoices.map((item) => [item.key, item.source]));
|
|
426
510
|
const templateTargetMap = Object.fromEntries(templateChoices.map((item) => [item.key, item.target]));
|
|
427
511
|
const templateMap = templateSourceMap;
|
|
428
512
|
//#endregion
|
|
429
|
-
export { Command, assetTargets, assetsDir, checkbox, createTemplateCopyFilter, ensureTemplateAssetsPrepared, execaCommand, getAssetTargets, input, isGitignoreFile, packageDir, prepareAssets, program, runCommand, scaffoldTemplate, scaffoldWorkspace, select, shouldSkipTemplatePath, skeletonDir, templateChoices, templateMap, templateSourceMap, templateTargetMap, templatesDir, toPublishGitignorePath, toWorkspaceGitignorePath };
|
|
513
|
+
export { Command, assetTargets, assetsDir, checkbox, createTemplateCopyFilter, ensureTemplateAssetsPrepared, execaCommand, getAssetTargets, getTemplateChoice, getTemplateChoices, getTemplateDefinition, getTemplateKeys, getTemplateSource, getTemplateTarget, input, isGitignoreFile, isTemplateCategory, isTemplateKey, packageDir, prepareAssets, program, runCommand, scaffoldTemplate, scaffoldWorkspace, select, shouldSkipTemplatePath, skeletonDir, suggestTemplateKey, templateCategories, templateChoices, templateMap, templateSourceMap, templateTargetMap, templatesDir, toPublishGitignorePath, toWorkspaceGitignorePath };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@icebreakers/monorepo-templates",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "1.0.0",
|
|
5
5
|
"description": "Template assets for icebreaker monorepo scaffolding",
|
|
6
6
|
"author": "ice breaker <hi@sonofmagic.top>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -21,14 +21,17 @@
|
|
|
21
21
|
"sideEffects": false,
|
|
22
22
|
"exports": {
|
|
23
23
|
".": {
|
|
24
|
-
"types": "./dist/index.d.
|
|
25
|
-
"import":
|
|
24
|
+
"types": "./dist/index.d.mts",
|
|
25
|
+
"import": {
|
|
26
|
+
"types": "./dist/index.d.mts",
|
|
27
|
+
"default": "./dist/index.mjs"
|
|
28
|
+
},
|
|
26
29
|
"default": "./dist/index.mjs"
|
|
27
30
|
},
|
|
28
31
|
"./package.json": "./package.json"
|
|
29
32
|
},
|
|
30
33
|
"main": "./dist/index.mjs",
|
|
31
|
-
"types": "./dist/index.d.
|
|
34
|
+
"types": "./dist/index.d.mts",
|
|
32
35
|
"files": [
|
|
33
36
|
"assets",
|
|
34
37
|
"assets-data.mjs",
|
|
@@ -40,9 +43,9 @@
|
|
|
40
43
|
"node": ">=18.0.0"
|
|
41
44
|
},
|
|
42
45
|
"dependencies": {
|
|
43
|
-
"@inquirer/checkbox": "^5.1.
|
|
44
|
-
"@inquirer/input": "^5.0.
|
|
45
|
-
"@inquirer/select": "^5.1.
|
|
46
|
+
"@inquirer/checkbox": "^5.1.4",
|
|
47
|
+
"@inquirer/input": "^5.0.12",
|
|
48
|
+
"@inquirer/select": "^5.1.4",
|
|
46
49
|
"commander": "^14.0.3",
|
|
47
50
|
"nanoexec": "^1.1.0"
|
|
48
51
|
},
|
|
@@ -52,7 +55,8 @@
|
|
|
52
55
|
"scripts": {
|
|
53
56
|
"dev": "tsdown --watch --sourcemap",
|
|
54
57
|
"build": "tsdown",
|
|
55
|
-
"typecheck": "tsc -p tsconfig.json",
|
|
58
|
+
"typecheck": "node ../../node_modules/typescript/bin/tsc -p tsconfig.json",
|
|
59
|
+
"tsd": "pnpm build && tsd --files test-d/**/*.test-d.ts",
|
|
56
60
|
"sync:assets": "pnpm run build && node scripts/sync-assets.mjs",
|
|
57
61
|
"lint": "eslint ."
|
|
58
62
|
}
|
package/template-data.mjs
CHANGED
|
@@ -1,10 +1,50 @@
|
|
|
1
1
|
export const templateChoices = [
|
|
2
|
-
{
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
{
|
|
3
|
+
key: 'tsdown',
|
|
4
|
+
label: 'tsdown 打包',
|
|
5
|
+
source: 'tsdown',
|
|
6
|
+
target: 'packages/tsdown',
|
|
7
|
+
category: 'library',
|
|
8
|
+
description: '使用 tsdown 构建的 TypeScript 库包',
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
key: 'vue-lib',
|
|
12
|
+
label: 'vue 组件',
|
|
13
|
+
source: 'vue-lib',
|
|
14
|
+
target: 'packages/vue-lib',
|
|
15
|
+
category: 'library',
|
|
16
|
+
description: 'Vue 3 组件库模板,适合沉淀可复用 UI',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
key: 'vue-hono',
|
|
20
|
+
label: 'vue hono 全栈',
|
|
21
|
+
source: 'client',
|
|
22
|
+
target: 'apps/client',
|
|
23
|
+
category: 'app',
|
|
24
|
+
description: 'Vue 3 + Hono 的前后端一体应用模板',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
key: 'hono-server',
|
|
28
|
+
label: 'hono 模板',
|
|
29
|
+
source: 'server',
|
|
30
|
+
target: 'apps/server',
|
|
31
|
+
category: 'service',
|
|
32
|
+
description: 'Hono API 服务模板',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
key: 'vitepress',
|
|
36
|
+
label: 'vitepress 文档',
|
|
37
|
+
source: 'vitepress',
|
|
38
|
+
target: 'apps/website',
|
|
39
|
+
category: 'docs',
|
|
40
|
+
description: 'VitePress 文档站模板',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
key: 'cli',
|
|
44
|
+
label: 'cli 模板',
|
|
45
|
+
source: 'cli',
|
|
46
|
+
target: 'apps/cli',
|
|
47
|
+
category: 'tool',
|
|
48
|
+
description: 'TypeScript 命令行工具模板',
|
|
49
|
+
},
|
|
10
50
|
]
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { fileURLToPath } from 'node:url'
|
|
2
|
-
import {
|
|
2
|
+
import { loadRepoctlToolingModule } from '../../tooling/load-tooling-module.mjs'
|
|
3
|
+
|
|
4
|
+
const { defineEslintConfig } = await loadRepoctlToolingModule()
|
|
3
5
|
|
|
4
6
|
const tailwindEntryPoint = fileURLToPath(new URL('./src/style.css', import.meta.url))
|
|
5
7
|
|
|
6
|
-
export default
|
|
7
|
-
{
|
|
8
|
+
export default await defineEslintConfig({
|
|
9
|
+
options: {
|
|
8
10
|
vue: true,
|
|
9
11
|
typescript: true,
|
|
10
12
|
tailwindcss: {
|
|
@@ -12,4 +14,4 @@ export default icebreaker(
|
|
|
12
14
|
},
|
|
13
15
|
ignores: ['**/fixtures/**'],
|
|
14
16
|
},
|
|
15
|
-
)
|
|
17
|
+
})
|
|
@@ -15,38 +15,38 @@
|
|
|
15
15
|
"typecheck": "vue-tsc -b"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@faker-js/faker": "^10.
|
|
19
|
-
"@tanstack/vue-query": "^5.
|
|
20
|
-
"@tanstack/vue-query-devtools": "^6.1.
|
|
18
|
+
"@faker-js/faker": "^10.4.0",
|
|
19
|
+
"@tanstack/vue-query": "^5.100.8",
|
|
20
|
+
"@tanstack/vue-query-devtools": "^6.1.27",
|
|
21
21
|
"@tanstack/vue-table": "^8.21.3",
|
|
22
|
-
"@tanstack/vue-virtual": "^3.13.
|
|
23
|
-
"@trpc/client": "^11.
|
|
22
|
+
"@tanstack/vue-virtual": "^3.13.24",
|
|
23
|
+
"@trpc/client": "^11.17.0",
|
|
24
24
|
"clsx": "^2.1.1",
|
|
25
25
|
"pinia": "^3.0.4",
|
|
26
26
|
"tailwind-merge": "^3.5.0",
|
|
27
27
|
"tailwind-variants": "^3.2.2",
|
|
28
|
-
"vue": "^3.5.
|
|
29
|
-
"vue-i18n": "^11.
|
|
30
|
-
"vue-router": "^5.0.
|
|
28
|
+
"vue": "^3.5.33",
|
|
29
|
+
"vue-i18n": "^11.4.0",
|
|
30
|
+
"vue-router": "^5.0.6"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@cloudflare/vite-plugin": "^1.
|
|
34
|
-
"@hono/node-server": "^
|
|
33
|
+
"@cloudflare/vite-plugin": "^1.35.0",
|
|
34
|
+
"@hono/node-server": "^2.0.1",
|
|
35
35
|
"@hono/trpc-server": "^0.4.2",
|
|
36
|
-
"@tailwindcss/vite": "^4.2.
|
|
37
|
-
"@trpc/server": "^11.
|
|
38
|
-
"@vitejs/plugin-vue": "^6.0.
|
|
36
|
+
"@tailwindcss/vite": "^4.2.4",
|
|
37
|
+
"@trpc/server": "^11.17.0",
|
|
38
|
+
"@vitejs/plugin-vue": "^6.0.6",
|
|
39
39
|
"@vitejs/plugin-vue-jsx": "^5.1.5",
|
|
40
|
-
"@vue/tsconfig": "^0.9.
|
|
40
|
+
"@vue/tsconfig": "^0.9.1",
|
|
41
41
|
"consola": "^3.4.2",
|
|
42
|
-
"hono": "^4.12.
|
|
43
|
-
"tailwindcss": "^4.2.
|
|
44
|
-
"typescript": "~
|
|
45
|
-
"vite": "^8.0.
|
|
46
|
-
"vite-plugin-vue-devtools": "^8.1.
|
|
42
|
+
"hono": "^4.12.16",
|
|
43
|
+
"tailwindcss": "^4.2.4",
|
|
44
|
+
"typescript": "~6.0.3",
|
|
45
|
+
"vite": "^8.0.10",
|
|
46
|
+
"vite-plugin-vue-devtools": "^8.1.1",
|
|
47
47
|
"vite-tsconfig-paths": "^6.1.1",
|
|
48
|
-
"vue-tsc": "3.2.
|
|
49
|
-
"wrangler": "^4.
|
|
50
|
-
"zod": "^4.
|
|
48
|
+
"vue-tsc": "3.2.7",
|
|
49
|
+
"wrangler": "^4.87.0",
|
|
50
|
+
"zod": "^4.4.2"
|
|
51
51
|
}
|
|
52
52
|
}
|
|
@@ -8,7 +8,7 @@ import VueDevTools from 'vite-plugin-vue-devtools'
|
|
|
8
8
|
import VueRouter from 'vue-router/vite'
|
|
9
9
|
|
|
10
10
|
// https://vite.dev/config/
|
|
11
|
-
export default defineConfig({
|
|
11
|
+
export default defineConfig(({ command }) => ({
|
|
12
12
|
build: {
|
|
13
13
|
target: 'baseline-widely-available',
|
|
14
14
|
},
|
|
@@ -22,12 +22,13 @@ export default defineConfig({
|
|
|
22
22
|
VueRouter(
|
|
23
23
|
{
|
|
24
24
|
dts: path.resolve(import.meta.dirname, 'src/route-map.d.ts'),
|
|
25
|
+
watch: command === 'serve',
|
|
25
26
|
},
|
|
26
27
|
),
|
|
27
28
|
Vue(),
|
|
28
29
|
VueJsx(),
|
|
29
30
|
Tailwindcss(),
|
|
30
31
|
cloudflare(),
|
|
31
|
-
VueDevTools(),
|
|
32
|
+
command === 'serve' ? VueDevTools() : null,
|
|
32
33
|
],
|
|
33
|
-
})
|
|
34
|
+
}))
|