@icebreakers/monorepo-templates 1.0.2 → 1.0.4

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 (57) hide show
  1. package/assets/.github/workflows/release.yml +42 -2
  2. package/assets/commitlint.config.ts +1 -3
  3. package/assets/eslint.config.js +2 -14
  4. package/assets/lint-staged.config.js +1 -3
  5. package/assets/package.json +8 -6
  6. package/assets/stylelint.config.js +1 -3
  7. package/assets/tsconfig.json +2 -1
  8. package/assets/vitest.config.ts +1 -3
  9. package/assets-data.mjs +0 -1
  10. package/dist/cli.d.mts +1 -0
  11. package/dist/cli.mjs +12 -0
  12. package/dist/index.mjs +1 -260
  13. package/dist/prepare-CtCifHGT.mjs +306 -0
  14. package/package.json +2 -2
  15. package/templates/client/package.json +2 -2
  16. package/templates/client/vite.config.ts +27 -21
  17. package/templates/vitepress/.vitepress/config.ts +152 -69
  18. package/templates/vitepress/en/index.md +63 -0
  19. package/templates/vitepress/en/knowledge/monorepo.md +37 -0
  20. package/templates/vitepress/en/repoctl/adopt-existing.md +131 -0
  21. package/templates/vitepress/en/repoctl/aliases.md +71 -0
  22. package/templates/vitepress/en/repoctl/commands.md +120 -0
  23. package/templates/vitepress/en/repoctl/config.md +69 -0
  24. package/templates/vitepress/en/repoctl/getting-started.md +116 -0
  25. package/templates/vitepress/en/repoctl/index.md +74 -0
  26. package/templates/vitepress/en/repoctl/scenarios.md +117 -0
  27. package/templates/vitepress/en/repoctl/templates.md +128 -0
  28. package/templates/vitepress/en/repoctl/troubleshooting.md +96 -0
  29. package/templates/vitepress/en/repoctl/workflows.md +89 -0
  30. package/templates/vitepress/getting-started.md +21 -224
  31. package/templates/vitepress/index.md +47 -176
  32. package/templates/vitepress/monorepo/commands.md +13 -283
  33. package/templates/vitepress/monorepo/manage.md +16 -3
  34. package/templates/vitepress/monorepo/publish.md +52 -6
  35. package/templates/vitepress/monorepo/templates.md +14 -60
  36. package/templates/vitepress/monorepo/troubleshooting.md +14 -220
  37. package/templates/vitepress/package.json +3 -2
  38. package/templates/vitepress/repoctl/adopt-existing.md +135 -0
  39. package/templates/vitepress/repoctl/aliases.md +71 -0
  40. package/templates/vitepress/repoctl/commands.md +154 -0
  41. package/templates/vitepress/repoctl/config.md +81 -0
  42. package/templates/vitepress/repoctl/getting-started.md +122 -0
  43. package/templates/vitepress/repoctl/index.md +74 -0
  44. package/templates/vitepress/repoctl/scenarios.md +119 -0
  45. package/templates/vitepress/repoctl/templates.md +156 -0
  46. package/templates/vitepress/repoctl/troubleshooting.md +98 -0
  47. package/templates/vitepress/repoctl/workflows.md +105 -0
  48. package/templates/vitepress/tools/changeset.md +11 -0
  49. package/templates/vitepress/tools/husky.md +17 -0
  50. package/templates/vitepress/tools/lint-staged.md +10 -0
  51. package/templates/vitepress/tools/llms-txt.md +29 -0
  52. package/templates/vitepress/tools/pnpm.md +26 -0
  53. package/templates/vitepress/tools/turborepo.md +17 -0
  54. package/templates/vitepress/why/examples/2.npm-basic-package/README.md +1 -1
  55. package/templates/vitepress/why/examples/3.npm-basic-package/README.md +1 -1
  56. package/templates/vitepress/wrangler.jsonc +5 -0
  57. package/templates/vue-lib/package.json +1 -1
@@ -4,6 +4,10 @@ on:
4
4
  push:
5
5
  branches:
6
6
  - main
7
+ - alpha
8
+ - beta
9
+ - rc
10
+ - next
7
11
  workflow_dispatch:
8
12
 
9
13
  concurrency: ${{ github.workflow }}-${{ github.ref }}
@@ -18,6 +22,7 @@ permissions:
18
22
 
19
23
  jobs:
20
24
  release:
25
+ if: github.ref_name == 'main'
21
26
  name: Release
22
27
  runs-on: ubuntu-latest
23
28
  steps:
@@ -35,12 +40,14 @@ jobs:
35
40
  - name: Install Dependencies
36
41
  run: pnpm i
37
42
 
43
+ - name: Build Release Tooling
44
+ run: pnpm run tooling:build
45
+
38
46
  - name: Create Release Pull Request or Publish to npm
39
47
  id: changesets
40
48
  uses: changesets/action@v1
41
49
  with:
42
- # This expects you to have a script called release which does a build for your packages and calls changeset publish
43
- publish: pnpm publish-packages
50
+ publish: pnpm exec repo release stable
44
51
  env:
45
52
  # this doesn't work but semantic-release works
46
53
  # see https://github.com/sonofmagic/npm-lib-rollup-template/blob/main/.github/workflows/release.yml#L46
@@ -55,3 +62,36 @@ jobs:
55
62
  uses: codecov/codecov-action@v6
56
63
  env:
57
64
  CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
65
+
66
+ prerelease:
67
+ if: github.ref_name != 'main'
68
+ name: Prerelease
69
+ runs-on: ubuntu-latest
70
+ steps:
71
+ - name: Checkout Repo
72
+ uses: actions/checkout@v6
73
+
74
+ - uses: pnpm/action-setup@v6
75
+
76
+ - name: Setup Node.js environment
77
+ uses: actions/setup-node@v6
78
+ with:
79
+ node-version: 24
80
+ cache: pnpm
81
+
82
+ - name: Install Dependencies
83
+ run: pnpm i
84
+
85
+ - name: Build Release Tooling
86
+ run: pnpm run tooling:build
87
+
88
+ - name: Configure Git
89
+ run: |
90
+ git config user.name "github-actions[bot]"
91
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
92
+
93
+ - name: Publish Prerelease
94
+ run: pnpm exec repo release pre publish
95
+ env:
96
+ npm_config_registry: https://registry.npmjs.org
97
+ NPM_CONFIG_PROVENANCE: true
@@ -1,5 +1,3 @@
1
- import { loadMonorepoToolingModule } from './tooling/load-tooling-module.mjs'
2
-
3
- const { defineCommitlintConfig } = await loadMonorepoToolingModule()
1
+ import { defineCommitlintConfig } from 'repoctl/tooling'
4
2
 
5
3
  export default await defineCommitlintConfig()
@@ -1,15 +1,3 @@
1
- import { loadMonorepoToolingModule } from './tooling/load-tooling-module.mjs'
1
+ import { defineEslintConfig } from 'repoctl/tooling'
2
2
 
3
- const { defineEslintConfig } = await loadMonorepoToolingModule()
4
-
5
- const config = await defineEslintConfig()
6
-
7
- export default [
8
- ...config,
9
- {
10
- ignores: [
11
- 'packages/monorepo/test/fixtures/demo/**',
12
- 'templates/vitepress/.vitepress/config.ts.timestamp-*.mjs',
13
- ],
14
- },
15
- ]
3
+ export default await defineEslintConfig()
@@ -1,5 +1,3 @@
1
- import { loadMonorepoToolingModule } from './tooling/load-tooling-module.mjs'
2
-
3
- const { defineLintStagedConfig } = await loadMonorepoToolingModule()
1
+ import { defineLintStagedConfig } from 'repoctl/tooling'
4
2
 
5
3
  export default await defineLintStagedConfig()
@@ -3,7 +3,7 @@
3
3
  "type": "module",
4
4
  "version": "0.0.0",
5
5
  "private": true,
6
- "packageManager": "pnpm@10.33.3",
6
+ "packageManager": "pnpm@10.33.4",
7
7
  "author": "ice breaker <hi@sonofmagic.top>",
8
8
  "repository": {
9
9
  "type": "git",
@@ -29,7 +29,8 @@
29
29
  "format": "eslint . --fix",
30
30
  "validate": "pnpm run build && pnpm run lint && pnpm run typecheck && pnpm run tsd && pnpm run test",
31
31
  "release": "changeset",
32
- "publish-packages": "pnpm run build && pnpm run lint && pnpm run test && changeset version && changeset publish",
32
+ "publish-packages": "repo release stable",
33
+ "release:pre": "repo release pre publish",
33
34
  "------": "--------------",
34
35
  "preinstall": "npx only-allow pnpm",
35
36
  "prepare": "husky",
@@ -44,10 +45,11 @@
44
45
  "clean:repo": "repo clean",
45
46
  "mirror": "repo mirror",
46
47
  "------simple": "--------------",
47
- "pr:alpha": "changeset pre enter alpha",
48
- "pr:beta": "changeset pre enter beta",
49
- "pr:rc": "changeset pre enter rc",
50
- "pr:exit": "changeset pre exit",
48
+ "pr:alpha": "repo release pre enter alpha",
49
+ "pr:beta": "repo release pre enter beta",
50
+ "pr:rc": "repo release pre enter rc",
51
+ "pr:next": "repo release pre enter next",
52
+ "pr:exit": "repo release pre exit",
51
53
  "--------": "----------------",
52
54
  "script:init": "repo init",
53
55
  "script:sync": "repo sync",
@@ -1,5 +1,3 @@
1
- import { loadMonorepoToolingModule } from './tooling/load-tooling-module.mjs'
2
-
3
- const { defineStylelintConfig } = await loadMonorepoToolingModule()
1
+ import { defineStylelintConfig } from 'repoctl/tooling'
4
2
 
5
3
  export default await defineStylelintConfig()
@@ -1,3 +1,4 @@
1
1
  {
2
- "extends": "repoctl/tsconfig"
2
+ "extends": "repoctl/tsconfig.json",
3
+ "files": []
3
4
  }
@@ -1,6 +1,4 @@
1
1
  import { defineConfig } from 'vitest/config'
2
- import { loadMonorepoToolingModule } from './tooling/load-tooling-module.mjs'
3
-
4
- const { defineVitestConfig } = await loadMonorepoToolingModule()
2
+ import { defineVitestConfig } from 'repoctl/tooling'
5
3
 
6
4
  export default defineConfig(async () => await defineVitestConfig())
package/assets-data.mjs CHANGED
@@ -15,7 +15,6 @@ const coreAssetTargets = [
15
15
  'AGENTS.md',
16
16
  // pnpm
17
17
  'pnpm-workspace.yaml',
18
- 'scripts',
19
18
  // base tsconfig
20
19
  'tsconfig.json',
21
20
  // turbo
package/dist/cli.d.mts ADDED
@@ -0,0 +1 @@
1
+ export { };
package/dist/cli.mjs ADDED
@@ -0,0 +1,12 @@
1
+ import { t as prepareAssets } from "./prepare-CtCifHGT.mjs";
2
+ import process from "node:process";
3
+ //#region src/cli.ts
4
+ async function main() {
5
+ await prepareAssets({ overwriteExisting: true });
6
+ }
7
+ main().catch((error) => {
8
+ console.error("[monorepo-templates]", error instanceof Error ? error.message : error);
9
+ process.exitCode = 1;
10
+ });
11
+ //#endregion
12
+ export {};
package/dist/index.mjs CHANGED
@@ -1,270 +1,11 @@
1
- import * as path$1 from "node:path";
1
+ import { a as toPublishGitignorePath, c as assetsDir, d as templatesDir, f as assetTargets$1, i as isGitignoreFile, l as packageDir, n as createTemplateCopyFilter, o as toWorkspaceGitignorePath, p as getAssetTargets$1, r as shouldSkipTemplatePath, s as templateChoices$1, t as prepareAssets, u as skeletonDir } from "./prepare-CtCifHGT.mjs";
2
2
  import path from "node:path";
3
- import { fileURLToPath } from "node:url";
4
3
  import fs, { access, open, rm } from "node:fs/promises";
5
4
  import exec from "nanoexec";
6
5
  import checkbox from "@inquirer/checkbox";
7
6
  import input from "@inquirer/input";
8
7
  import select from "@inquirer/select";
9
8
  import { Command, program } from "commander";
10
- //#region assets-data.mjs
11
- const coreAssetTargets = [
12
- ".changeset",
13
- ".husky",
14
- ".vscode",
15
- ".editorconfig",
16
- ".gitattributes",
17
- ".gitignore",
18
- ".npmrc",
19
- "commitlint.config.ts",
20
- "eslint.config.js",
21
- "lint-staged.config.js",
22
- "stylelint.config.js",
23
- "repoctl.config.ts",
24
- "package.json",
25
- "AGENTS.md",
26
- "pnpm-workspace.yaml",
27
- "scripts",
28
- "tsconfig.json",
29
- "turbo.json",
30
- "vitest.config.ts",
31
- "Dockerfile",
32
- ".dockerignore"
33
- ];
34
- const extraAssetTargets = [
35
- ".github",
36
- "LICENSE",
37
- "renovate.json",
38
- "SECURITY.md",
39
- "CODE_OF_CONDUCT.md",
40
- "CONTRIBUTING.md",
41
- "netlify.toml"
42
- ];
43
- const assetTargets$1 = [...coreAssetTargets, ...extraAssetTargets];
44
- function getAssetTargets$1(core = false) {
45
- return core ? [...coreAssetTargets] : [...assetTargets$1];
46
- }
47
- //#endregion
48
- //#region src/paths.ts
49
- const packageDir = path$1.resolve(fileURLToPath(new URL("../", import.meta.url)));
50
- const templatesDir = path$1.join(packageDir, "templates");
51
- const assetsDir = path$1.join(packageDir, "assets");
52
- const skeletonDir = assetsDir;
53
- //#endregion
54
- //#region template-data.mjs
55
- const templateChoices$1 = [
56
- {
57
- key: "tsdown",
58
- label: "tsdown 打包",
59
- source: "tsdown",
60
- target: "packages/tsdown",
61
- category: "library",
62
- description: "使用 tsdown 构建的 TypeScript 库包"
63
- },
64
- {
65
- key: "vue-lib",
66
- label: "vue 组件",
67
- source: "vue-lib",
68
- target: "packages/vue-lib",
69
- category: "library",
70
- description: "Vue 3 组件库模板,适合沉淀可复用 UI"
71
- },
72
- {
73
- key: "vue-hono",
74
- label: "vue hono 全栈",
75
- source: "client",
76
- target: "apps/client",
77
- category: "app",
78
- description: "Vue 3 + Hono 的前后端一体应用模板"
79
- },
80
- {
81
- key: "hono-server",
82
- label: "hono 模板",
83
- source: "server",
84
- target: "apps/server",
85
- category: "service",
86
- description: "Hono API 服务模板"
87
- },
88
- {
89
- key: "vitepress",
90
- label: "vitepress 文档",
91
- source: "vitepress",
92
- target: "apps/website",
93
- category: "docs",
94
- description: "VitePress 文档站模板"
95
- },
96
- {
97
- key: "cli",
98
- label: "cli 模板",
99
- source: "cli",
100
- target: "apps/cli",
101
- category: "tool",
102
- description: "TypeScript 命令行工具模板"
103
- }
104
- ];
105
- //#endregion
106
- //#region src/utils/gitignore.ts
107
- const publishBasename = "gitignore";
108
- const workspaceBasename = ".gitignore";
109
- const normalizedPathPattern = /[\\/]/;
110
- function detectSeparator(input) {
111
- if (input.includes("\\") && !input.includes("/")) return "\\";
112
- return "/";
113
- }
114
- function replaceBasename(input, from, to) {
115
- if (!input) return input;
116
- const separator = detectSeparator(input);
117
- const normalized = input.replace(normalizedPathPattern, separator);
118
- const hasTrailingSeparator = normalized.endsWith(separator);
119
- const segments = normalized.split(separator);
120
- if (hasTrailingSeparator && segments.at(-1) === "") segments.pop();
121
- const lastIndex = segments.length - 1;
122
- if (lastIndex >= 0 && segments[lastIndex] === from) {
123
- segments[lastIndex] = to;
124
- const rebuilt = segments.join(separator);
125
- return hasTrailingSeparator ? `${rebuilt}${separator}` : rebuilt;
126
- }
127
- return input;
128
- }
129
- function toPublishGitignorePath(input) {
130
- return replaceBasename(input, workspaceBasename, publishBasename);
131
- }
132
- function toWorkspaceGitignorePath(input) {
133
- return replaceBasename(input, publishBasename, workspaceBasename);
134
- }
135
- function isGitignoreFile(name) {
136
- return toPublishGitignorePath(name) !== name || toWorkspaceGitignorePath(name) !== name;
137
- }
138
- //#endregion
139
- //#region src/utils/template-filter.ts
140
- const skipDirs = new Set([
141
- "node_modules",
142
- "dist",
143
- ".turbo",
144
- ".cache",
145
- ".vite",
146
- ".tmp",
147
- ".vue-global-types",
148
- ".wrangler"
149
- ]);
150
- const skipFiles = new Set([
151
- ".DS_Store",
152
- "CHANGELOG.md",
153
- "route-map.d.ts"
154
- ]);
155
- function shouldSkipTemplatePath(rootDir, targetPath) {
156
- const basename = path.basename(targetPath);
157
- if (skipFiles.has(basename)) return true;
158
- if (basename.endsWith(".tsbuildinfo")) return true;
159
- if (/\.timestamp-\d+-[a-z0-9]+\.mjs$/i.test(basename)) return true;
160
- const relative = path.relative(rootDir, targetPath);
161
- if (!relative || relative.startsWith("..")) return false;
162
- const segments = relative.split(path.sep);
163
- if (segments.some((segment) => skipDirs.has(segment))) return true;
164
- for (let i = 0; i < segments.length - 1; i += 1) if (segments[i] === ".vitepress" && segments[i + 1] === "cache") return true;
165
- return false;
166
- }
167
- function createTemplateCopyFilter(rootDir) {
168
- return (src) => !shouldSkipTemplatePath(rootDir, src);
169
- }
170
- //#endregion
171
- //#region src/prepare.ts
172
- const huskySkippedEntryPattern = /[\\/]_$/;
173
- async function pathExists$1(targetPath) {
174
- try {
175
- await fs.access(targetPath);
176
- return true;
177
- } catch {
178
- return false;
179
- }
180
- }
181
- async function renameGitignoreFiles(targetDir) {
182
- let entries;
183
- try {
184
- entries = await fs.readdir(targetDir, { withFileTypes: true });
185
- } catch (error) {
186
- if (error.code === "ENOENT") return;
187
- throw error;
188
- }
189
- await Promise.all(entries.map(async (entry) => {
190
- const current = path$1.join(targetDir, entry.name);
191
- if (entry.isDirectory()) {
192
- await renameGitignoreFiles(current);
193
- return;
194
- }
195
- const renamed = toPublishGitignorePath(entry.name);
196
- if (renamed !== entry.name) await fs.rename(current, path$1.join(targetDir, renamed));
197
- }));
198
- }
199
- async function resetDir(targetDir, overwriteExisting) {
200
- if (!overwriteExisting && await pathExists$1(targetDir)) return;
201
- try {
202
- await fs.rm(targetDir, {
203
- recursive: true,
204
- force: true
205
- });
206
- } catch (error) {
207
- const err = error;
208
- if (err?.code !== "ENOTEMPTY" && err?.code !== "EBUSY" && err?.code !== "EPERM") throw error;
209
- }
210
- await fs.mkdir(targetDir, { recursive: true });
211
- }
212
- async function copyEntry(from, to, overwriteExisting, filter) {
213
- if (!overwriteExisting && await pathExists$1(to)) {
214
- const [fromStats, toStats] = await Promise.all([fs.stat(from), fs.stat(to)]);
215
- if (fromStats.isDirectory() && toStats.isDirectory()) await fs.cp(from, to, {
216
- recursive: true,
217
- force: false,
218
- errorOnExist: false,
219
- filter
220
- });
221
- return;
222
- }
223
- try {
224
- await fs.cp(from, to, {
225
- recursive: true,
226
- force: overwriteExisting,
227
- filter
228
- });
229
- } catch (error) {
230
- const err = error;
231
- if (!overwriteExisting && (err?.code === "EEXIST" || err?.code === "ENOTEMPTY")) return;
232
- throw error;
233
- }
234
- }
235
- async function copyAssets(repoRoot, overwriteExisting) {
236
- const monorepoAssetRoot = path$1.resolve(repoRoot, "packages/monorepo/assets");
237
- for (const target of assetTargets$1) {
238
- const packageAsset = path$1.join(monorepoAssetRoot, toPublishGitignorePath(target));
239
- const repoAsset = path$1.join(repoRoot, target);
240
- const from = await pathExists$1(repoAsset) ? repoAsset : packageAsset;
241
- if (!await pathExists$1(from)) continue;
242
- const to = path$1.join(assetsDir, toPublishGitignorePath(target));
243
- const stats = await fs.stat(from);
244
- await copyEntry(from, to, overwriteExisting, target === ".husky" ? (src) => !huskySkippedEntryPattern.test(src) : void 0);
245
- if (stats.isDirectory()) await renameGitignoreFiles(to);
246
- }
247
- }
248
- async function copyTemplates(repoRoot, overwriteExisting) {
249
- for (const template of templateChoices$1) {
250
- const from = path$1.join(repoRoot, "templates", template.source);
251
- if (!await pathExists$1(from)) continue;
252
- const to = path$1.join(templatesDir, template.source);
253
- const filter = (src) => !shouldSkipTemplatePath(from, src);
254
- await copyEntry(from, to, overwriteExisting, filter);
255
- await renameGitignoreFiles(to);
256
- }
257
- }
258
- async function prepareAssets(options = {}) {
259
- const overwriteExisting = options.overwriteExisting ?? true;
260
- const repoRoot = path$1.resolve(packageDir, "..", "..");
261
- if (!await pathExists$1(path$1.join(repoRoot, "templates"))) return;
262
- await resetDir(assetsDir, overwriteExisting);
263
- await resetDir(templatesDir, overwriteExisting);
264
- await copyAssets(repoRoot, overwriteExisting);
265
- await copyTemplates(repoRoot, overwriteExisting);
266
- }
267
- //#endregion
268
9
  //#region src/runtime-assets.ts
269
10
  const lockFileName = ".prepare-assets.lock";
270
11
  const lockPollIntervalMs = 200;