Skip to content

Commit 2c9bab4

Browse files
committed
chore: update
1 parent b07899f commit 2c9bab4

File tree

8 files changed

+126
-188
lines changed

8 files changed

+126
-188
lines changed

packages/create-icebreaker/src/fs-utils.ts

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,6 @@
11
import fs from 'node:fs/promises'
22
import path from 'node:path'
3-
4-
const skipDirs = new Set([
5-
'node_modules',
6-
'dist',
7-
'.turbo',
8-
'.cache',
9-
'.vite',
10-
'.tmp',
11-
'.vue-global-types',
12-
])
13-
14-
function shouldSkipEntry(entryName: string) {
15-
if (skipDirs.has(entryName)) {
16-
return true
17-
}
18-
if (entryName.endsWith('.tsbuildinfo')) {
19-
return true
20-
}
21-
if (entryName === 'typed-router.d.ts') {
22-
return true
23-
}
24-
return false
25-
}
3+
import { shouldSkipTemplatePath, toWorkspaceGitignorePath } from '@icebreakers/monorepo-templates'
264

275
export async function pathExists(targetPath: string) {
286
try {
@@ -63,18 +41,18 @@ export async function prepareTarget(dir: string, force: boolean) {
6341
await fs.mkdir(dir, { recursive: true })
6442
}
6543

66-
export async function copyDirContents(sourceDir: string, targetDir: string) {
44+
export async function copyDirContents(sourceDir: string, targetDir: string, rootDir = sourceDir) {
6745
await fs.mkdir(targetDir, { recursive: true })
6846
const entries = await fs.readdir(sourceDir, { withFileTypes: true })
6947
for (const entry of entries) {
7048
const from = path.join(sourceDir, entry.name)
71-
const targetName = entry.name === 'gitignore' ? '.gitignore' : entry.name
72-
if (shouldSkipEntry(entry.name)) {
49+
if (shouldSkipTemplatePath(rootDir, from)) {
7350
continue
7451
}
52+
const targetName = toWorkspaceGitignorePath(entry.name)
7553
const to = path.join(targetDir, targetName)
7654
if (entry.isDirectory()) {
77-
await copyDirContents(from, to)
55+
await copyDirContents(from, to, rootDir)
7856
continue
7957
}
8058
if (entry.isSymbolicLink()) {

packages/monorepo-templates/scripts/sync-assets.mjs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ const templateSkipDirs = new Set([
1919
'.vite',
2020
'.tmp',
2121
'.vue-global-types',
22+
'.wrangler',
23+
])
24+
const skipFiles = new Set([
25+
'.DS_Store',
26+
'typed-router.d.ts',
27+
'worker-configuration.d.ts',
2228
])
2329

2430
const publishBasename = 'gitignore'
@@ -64,11 +70,16 @@ function shouldSkipTemplatePath(rootDir, targetPath) {
6470
if (segments.some(segment => templateSkipDirs.has(segment))) {
6571
return true
6672
}
73+
for (let i = 0; i < segments.length - 1; i += 1) {
74+
if (segments[i] === '.vitepress' && segments[i + 1] === 'cache') {
75+
return true
76+
}
77+
}
6778
const basename = path.basename(targetPath)
68-
if (basename.endsWith('.tsbuildinfo')) {
79+
if (skipFiles.has(basename)) {
6980
return true
7081
}
71-
if (basename === 'typed-router.d.ts' && segments.includes('types')) {
82+
if (basename.endsWith('.tsbuildinfo')) {
7283
return true
7384
}
7485
return false

packages/monorepo-templates/src/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { assetTargets as rawAssetTargets, getAssetTargets as rawGetAssetTargets
22
import { templateChoices as rawTemplateChoices } from '../template-data.mjs'
33
import { assetsDir, packageDir, skeletonDir, templatesDir } from './paths'
44
import { prepareAssets } from './prepare'
5+
import { isGitignoreFile, toPublishGitignorePath, toWorkspaceGitignorePath } from './utils/gitignore'
6+
import { createTemplateCopyFilter, shouldSkipTemplatePath } from './utils/template-filter'
57

68
export interface TemplateChoice {
79
key: string
@@ -27,3 +29,10 @@ export const templateTargetMap = Object.fromEntries(
2729
export const templateMap = templateSourceMap
2830

2931
export { prepareAssets }
32+
export {
33+
createTemplateCopyFilter,
34+
isGitignoreFile,
35+
shouldSkipTemplatePath,
36+
toPublishGitignorePath,
37+
toWorkspaceGitignorePath,
38+
}

packages/monorepo-templates/src/prepare.ts

Lines changed: 5 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import * as path from 'node:path'
44
import { assetTargets } from '../assets-data.mjs'
55
import { templateChoices } from '../template-data.mjs'
66
import { assetsDir, packageDir, skeletonDir, templatesDir } from './paths'
7+
import { toPublishGitignorePath } from './utils/gitignore'
8+
import { shouldSkipTemplatePath } from './utils/template-filter'
79

810
export interface PrepareAssetsOptions {
911
overwriteExisting?: boolean
@@ -27,77 +29,6 @@ const skeletonFiles = [
2729
'LICENSE',
2830
]
2931

30-
const publishBasename = 'gitignore'
31-
const workspaceBasename = '.gitignore'
32-
const templateSkipDirs = new Set([
33-
'node_modules',
34-
'dist',
35-
'.turbo',
36-
'.cache',
37-
'.vite',
38-
'.tmp',
39-
'.vue-global-types',
40-
'.wrangler',
41-
])
42-
43-
function detectSeparator(input: string) {
44-
if (input.includes('\\') && !input.includes('/')) {
45-
return '\\'
46-
}
47-
return '/'
48-
}
49-
50-
function replaceBasename(input: string, from: string, to: string) {
51-
if (!input) {
52-
return input
53-
}
54-
const separator = detectSeparator(input)
55-
const normalized = input.replace(/[\\/]/g, separator)
56-
const hasTrailingSeparator = normalized.endsWith(separator)
57-
const segments = normalized.split(separator)
58-
if (hasTrailingSeparator && segments[segments.length - 1] === '') {
59-
segments.pop()
60-
}
61-
const lastIndex = segments.length - 1
62-
if (lastIndex >= 0 && segments[lastIndex] === from) {
63-
segments[lastIndex] = to
64-
const rebuilt = segments.join(separator)
65-
return hasTrailingSeparator ? `${rebuilt}${separator}` : rebuilt
66-
}
67-
return input
68-
}
69-
70-
function toPublishGitignorePath(input: string) {
71-
return replaceBasename(input, workspaceBasename, publishBasename)
72-
}
73-
74-
function shouldSkipTemplatePath(rootDir: string, targetPath: string) {
75-
const relative = path.relative(rootDir, targetPath)
76-
if (!relative || relative.startsWith('..')) {
77-
return false
78-
}
79-
const segments = relative.split(path.sep)
80-
if (segments.some(segment => templateSkipDirs.has(segment))) {
81-
return true
82-
}
83-
for (let i = 0; i < segments.length - 1; i += 1) {
84-
if (segments[i] === '.vitepress' && segments[i + 1] === 'cache') {
85-
return true
86-
}
87-
}
88-
const basename = path.basename(targetPath)
89-
if (basename.endsWith('.tsbuildinfo')) {
90-
return true
91-
}
92-
if (basename === 'typed-router.d.ts' && segments.includes('types')) {
93-
return true
94-
}
95-
if (basename === 'worker-configuration.d.ts') {
96-
return true
97-
}
98-
return false
99-
}
100-
10132
async function pathExists(targetPath: string) {
10233
try {
10334
await fs.access(targetPath)
@@ -125,8 +56,9 @@ async function renameGitignoreFiles(targetDir: string) {
12556
await renameGitignoreFiles(current)
12657
return
12758
}
128-
if (entry.name === workspaceBasename) {
129-
await fs.rename(current, path.join(targetDir, publishBasename))
59+
const renamed = toPublishGitignorePath(entry.name)
60+
if (renamed !== entry.name) {
61+
await fs.rename(current, path.join(targetDir, renamed))
13062
}
13163
}))
13264
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
const publishBasename = 'gitignore'
2+
const workspaceBasename = '.gitignore'
3+
4+
function detectSeparator(input: string) {
5+
if (input.includes('\\') && !input.includes('/')) {
6+
return '\\'
7+
}
8+
return '/'
9+
}
10+
11+
function replaceBasename(input: string, from: string, to: string) {
12+
if (!input) {
13+
return input
14+
}
15+
const separator = detectSeparator(input)
16+
const normalized = input.replace(/[\\/]/g, separator)
17+
const hasTrailingSeparator = normalized.endsWith(separator)
18+
const segments = normalized.split(separator)
19+
if (hasTrailingSeparator && segments[segments.length - 1] === '') {
20+
segments.pop()
21+
}
22+
const lastIndex = segments.length - 1
23+
if (lastIndex >= 0 && segments[lastIndex] === from) {
24+
segments[lastIndex] = to
25+
const rebuilt = segments.join(separator)
26+
return hasTrailingSeparator ? `${rebuilt}${separator}` : rebuilt
27+
}
28+
return input
29+
}
30+
31+
export function toPublishGitignorePath(input: string) {
32+
return replaceBasename(input, workspaceBasename, publishBasename)
33+
}
34+
35+
export function toWorkspaceGitignorePath(input: string) {
36+
return replaceBasename(input, publishBasename, workspaceBasename)
37+
}
38+
39+
export function isGitignoreFile(name: string) {
40+
return toPublishGitignorePath(name) !== name || toWorkspaceGitignorePath(name) !== name
41+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import path from 'node:path'
2+
3+
const skipDirs = new Set([
4+
'node_modules',
5+
'dist',
6+
'.turbo',
7+
'.cache',
8+
'.vite',
9+
'.tmp',
10+
'.vue-global-types',
11+
'.wrangler',
12+
])
13+
14+
const skipFiles = new Set([
15+
'.DS_Store',
16+
'typed-router.d.ts',
17+
'worker-configuration.d.ts',
18+
])
19+
20+
export function shouldSkipTemplatePath(rootDir: string, targetPath: string) {
21+
const basename = path.basename(targetPath)
22+
if (skipFiles.has(basename)) {
23+
return true
24+
}
25+
if (basename.endsWith('.tsbuildinfo')) {
26+
return true
27+
}
28+
const relative = path.relative(rootDir, targetPath)
29+
if (!relative || relative.startsWith('..')) {
30+
return false
31+
}
32+
const segments = relative.split(path.sep)
33+
if (segments.some(segment => skipDirs.has(segment))) {
34+
return true
35+
}
36+
for (let i = 0; i < segments.length - 1; i += 1) {
37+
if (segments[i] === '.vitepress' && segments[i + 1] === 'cache') {
38+
return true
39+
}
40+
}
41+
return false
42+
}
43+
44+
export function createTemplateCopyFilter(rootDir: string) {
45+
return (src: string) => !shouldSkipTemplatePath(rootDir, src)
46+
}

packages/monorepo/src/commands/create.ts

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { CreateChoiceOption, PackageJson } from '@/types'
22
import process from 'node:process'
3+
import { shouldSkipTemplatePath } from '@icebreakers/monorepo-templates'
34
import fs from 'fs-extra'
45
import path from 'pathe'
56
import pc from 'picocolors'
@@ -158,36 +159,7 @@ export async function createNewProject(options?: CreateNewProjectOptions) {
158159
await fs.ensureDir(to)
159160

160161
const filelist = await fs.readdir(from)
161-
// 跳过 macOS 生成的临时文件,避免污染模板。
162-
const shouldSkip = (src: string) => {
163-
if (path.basename(src) === '.DS_Store') {
164-
return true
165-
}
166-
const relative = path.relative(from, src)
167-
if (!relative || relative.startsWith('..')) {
168-
return false
169-
}
170-
const segments = relative.split(path.sep)
171-
const skipDirs = new Set(['node_modules', 'dist', '.turbo', '.cache', '.vite', '.tmp', '.vue-global-types', '.wrangler'])
172-
if (segments.some(segment => skipDirs.has(segment))) {
173-
return true
174-
}
175-
for (let i = 0; i < segments.length - 1; i += 1) {
176-
if (segments[i] === '.vitepress' && segments[i + 1] === 'cache') {
177-
return true
178-
}
179-
}
180-
if (relative.split(path.sep).some(segment => segment.endsWith('.tsbuildinfo'))) {
181-
return true
182-
}
183-
if (segments.includes('types') && path.basename(src) === 'typed-router.d.ts') {
184-
return true
185-
}
186-
if (path.basename(src) === 'worker-configuration.d.ts') {
187-
return true
188-
}
189-
return false
190-
}
162+
const shouldSkip = (src: string) => shouldSkipTemplatePath(from, src)
191163
const copyTasks = filelist
192164
.filter(filename => filename !== 'package.json')
193165
.map(async (filename) => {
Lines changed: 5 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,5 @@
1-
/**
2-
* Utilities to handle renaming `.gitignore` files when packaging templates.
3-
* pnpm publish strips `.gitignore`, so we temporarily rename them to `gitignore`
4-
* and convert them back when writing into workspaces.
5-
*/
6-
const publishBasename = 'gitignore'
7-
const workspaceBasename = '.gitignore'
8-
9-
function detectSeparator(input: string) {
10-
if (input.includes('\\') && !input.includes('/')) {
11-
return '\\'
12-
}
13-
return '/'
14-
}
15-
16-
function replaceBasename(input: string, from: string, to: string) {
17-
if (!input) {
18-
return input
19-
}
20-
const separator = detectSeparator(input)
21-
const normalized = input.replace(/[\\/]/g, separator)
22-
const hasTrailingSeparator = normalized.endsWith(separator)
23-
const segments = normalized.split(separator)
24-
if (hasTrailingSeparator && segments[segments.length - 1] === '') {
25-
segments.pop()
26-
}
27-
const lastIndex = segments.length - 1
28-
if (lastIndex >= 0 && segments[lastIndex] === from) {
29-
segments[lastIndex] = to
30-
const rebuilt = segments.join(separator)
31-
return hasTrailingSeparator ? `${rebuilt}${separator}` : rebuilt
32-
}
33-
return input
34-
}
35-
36-
/**
37-
* Map a workspace path (containing `.gitignore`) to its packaged variant.
38-
*/
39-
export function toPublishGitignorePath(input: string) {
40-
return replaceBasename(input, workspaceBasename, publishBasename)
41-
}
42-
43-
/**
44-
* Map a packaged path (containing `gitignore`) back to the workspace form.
45-
*/
46-
export function toWorkspaceGitignorePath(input: string) {
47-
return replaceBasename(input, publishBasename, workspaceBasename)
48-
}
49-
50-
/**
51-
* Convenient helper to check whether a filename (with or without dot prefix)
52-
* should be treated as a gitignore file.
53-
*/
54-
export function isGitignoreFile(name: string) {
55-
return toPublishGitignorePath(name) !== name || toWorkspaceGitignorePath(name) !== name
56-
}
1+
export {
2+
isGitignoreFile,
3+
toPublishGitignorePath,
4+
toWorkspaceGitignorePath,
5+
} from '@icebreakers/monorepo-templates'

0 commit comments

Comments
 (0)