Skip to content

Commit 403e513

Browse files
committed
chore: bump version
1 parent 8258df9 commit 403e513

File tree

16 files changed

+241
-316
lines changed

16 files changed

+241
-316
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@icebreakers/monorepo-templates": patch
3+
"@icebreakers/monorepo": patch
4+
"create-icebreaker": patch
5+
---
6+
7+
refactor scaffolding to share template copy utilities

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

Lines changed: 0 additions & 65 deletions
This file was deleted.

packages/create-icebreaker/src/index.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import path from 'node:path'
22
import process from 'node:process'
33
import { Command } from '@icebreakers/monorepo-templates'
44
import { DEFAULT_TARGET } from './constants'
5-
import { prepareTarget } from './fs-utils'
65
import { updateRootPackageJson } from './package-json'
76
import { promptTargetDir, promptTemplates } from './prompts'
87
import { scaffoldFromNpm } from './source-npm'
@@ -48,8 +47,7 @@ async function runCreate(targetDirInput: string, options: CreateOptions) {
4847
const targetDir = path.resolve(process.cwd(), targetInput)
4948
const projectName = path.basename(targetDir) || targetInput
5049

51-
await prepareTarget(targetDir, Boolean(options.force))
52-
await scaffoldFromNpm(targetDir, selectedTemplates)
50+
await scaffoldFromNpm(targetDir, selectedTemplates, Boolean(options.force))
5351
await updateRootPackageJson(targetDir, projectName)
5452
printNextSteps(targetDir)
5553
}
Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,10 @@
1-
import path from 'node:path'
2-
import { assetsDir, templatesDir } from '@icebreakers/monorepo-templates'
3-
import { copyDirContents } from './fs-utils'
4-
import { templateChoices } from './templates'
1+
import { scaffoldWorkspace } from '@icebreakers/monorepo-templates'
52

6-
async function copySelectedTemplates(targetDir: string, selectedTemplates: string[]) {
7-
if (!selectedTemplates.length) {
8-
return
9-
}
10-
const selected = new Set(selectedTemplates)
11-
for (const template of templateChoices) {
12-
if (!selected.has(template.key)) {
13-
continue
14-
}
15-
const from = path.join(templatesDir, template.source)
16-
const to = path.join(targetDir, template.target)
17-
await copyDirContents(from, to)
18-
}
19-
}
20-
21-
export async function scaffoldFromNpm(targetDir: string, selectedTemplates: string[]) {
22-
await copyDirContents(assetsDir, targetDir)
23-
await copySelectedTemplates(targetDir, selectedTemplates)
3+
export async function scaffoldFromNpm(targetDir: string, selectedTemplates: string[], force = false) {
4+
await scaffoldWorkspace({
5+
targetDir,
6+
templateKeys: selectedTemplates,
7+
targetMode: 'prepare',
8+
force,
9+
})
2410
}

packages/monorepo-templates/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@
4242
"dev": "tsdown --watch --sourcemap",
4343
"build": "tsdown",
4444
"typecheck": "tsc -p tsconfig.json",
45-
"sync:assets": "node scripts/sync-assets.mjs",
46-
"prepack": "node scripts/sync-assets.mjs",
45+
"sync:assets": "pnpm run build && node scripts/sync-assets.mjs",
46+
"prepack": "pnpm run build && node scripts/sync-assets.mjs",
4747
"lint": "eslint ."
4848
},
4949
"dependencies": {

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

Lines changed: 3 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -1,149 +1,9 @@
1-
import fs from 'node:fs/promises'
2-
import path from 'node:path'
31
import process from 'node:process'
4-
import { fileURLToPath } from 'node:url'
5-
import { assetTargets } from '../assets-data.mjs'
6-
import { templateChoices } from '../template-data.mjs'
7-
8-
const scriptDir = path.dirname(fileURLToPath(import.meta.url))
9-
const packageDir = path.resolve(scriptDir, '..')
10-
const repoRoot = path.resolve(packageDir, '..', '..')
11-
const templatesDir = path.join(packageDir, 'templates')
12-
const assetsDir = path.join(packageDir, 'assets')
13-
const templateSkipDirs = new Set([
14-
'node_modules',
15-
'dist',
16-
'.turbo',
17-
'.cache',
18-
'.vite',
19-
'.tmp',
20-
'.vue-global-types',
21-
'.wrangler',
22-
])
23-
const skipFiles = new Set([
24-
'.DS_Store',
25-
'typed-router.d.ts',
26-
'worker-configuration.d.ts',
27-
])
28-
29-
const publishBasename = 'gitignore'
30-
const workspaceBasename = '.gitignore'
31-
32-
function detectSeparator(input) {
33-
if (input.includes('\\') && !input.includes('/')) {
34-
return '\\'
35-
}
36-
return '/'
37-
}
38-
39-
function replaceBasename(input, from, to) {
40-
if (!input) {
41-
return input
42-
}
43-
const separator = detectSeparator(input)
44-
const normalized = input.replace(/[\\/]/g, separator)
45-
const hasTrailingSeparator = normalized.endsWith(separator)
46-
const segments = normalized.split(separator)
47-
if (hasTrailingSeparator && segments[segments.length - 1] === '') {
48-
segments.pop()
49-
}
50-
const lastIndex = segments.length - 1
51-
if (lastIndex >= 0 && segments[lastIndex] === from) {
52-
segments[lastIndex] = to
53-
const rebuilt = segments.join(separator)
54-
return hasTrailingSeparator ? `${rebuilt}${separator}` : rebuilt
55-
}
56-
return input
57-
}
58-
59-
function toPublishGitignorePath(input) {
60-
return replaceBasename(input, workspaceBasename, publishBasename)
61-
}
62-
63-
function shouldSkipTemplatePath(rootDir, targetPath) {
64-
const relative = path.relative(rootDir, targetPath)
65-
if (!relative || relative.startsWith('..')) {
66-
return false
67-
}
68-
const segments = relative.split(path.sep)
69-
if (segments.some(segment => templateSkipDirs.has(segment))) {
70-
return true
71-
}
72-
for (let i = 0; i < segments.length - 1; i += 1) {
73-
if (segments[i] === '.vitepress' && segments[i + 1] === 'cache') {
74-
return true
75-
}
76-
}
77-
const basename = path.basename(targetPath)
78-
if (skipFiles.has(basename)) {
79-
return true
80-
}
81-
if (basename.endsWith('.tsbuildinfo')) {
82-
return true
83-
}
84-
return false
85-
}
86-
87-
async function renameGitignoreFiles(targetDir) {
88-
const entries = await fs.readdir(targetDir, { withFileTypes: true })
89-
await Promise.all(entries.map(async (entry) => {
90-
const current = path.join(targetDir, entry.name)
91-
if (entry.isDirectory()) {
92-
await renameGitignoreFiles(current)
93-
return
94-
}
95-
if (entry.name === workspaceBasename) {
96-
const renamed = path.join(targetDir, publishBasename)
97-
await fs.rename(current, renamed)
98-
}
99-
}))
100-
}
101-
102-
async function resetDir(targetDir) {
103-
await fs.rm(targetDir, { recursive: true, force: true })
104-
await fs.mkdir(targetDir, { recursive: true })
105-
}
106-
107-
async function copyAssets() {
108-
for (const target of assetTargets) {
109-
const from = path.join(repoRoot, target)
110-
const to = path.join(assetsDir, toPublishGitignorePath(target))
111-
const stats = await fs.stat(from)
112-
const copyOptions = { recursive: true }
113-
if (target === '.husky') {
114-
await fs.cp(from, to, {
115-
...copyOptions,
116-
filter(src) {
117-
return !/[\\/]_$/.test(src)
118-
},
119-
})
120-
continue
121-
}
122-
await fs.cp(from, to, copyOptions)
123-
if (stats.isDirectory()) {
124-
await renameGitignoreFiles(to)
125-
}
126-
}
127-
}
128-
129-
async function copyTemplates() {
130-
for (const template of templateChoices) {
131-
const from = path.join(repoRoot, 'templates', template.source)
132-
const to = path.join(templatesDir, template.source)
133-
await fs.mkdir(path.dirname(to), { recursive: true })
134-
await fs.cp(from, to, {
135-
recursive: true,
136-
filter: src => !shouldSkipTemplatePath(from, src),
137-
})
138-
await renameGitignoreFiles(to)
139-
}
140-
}
1412

1423
async function main() {
143-
await resetDir(assetsDir)
144-
await resetDir(templatesDir)
145-
await copyAssets()
146-
await copyTemplates()
4+
const entryUrl = new URL('../dist/index.mjs', import.meta.url)
5+
const { prepareAssets } = await import(entryUrl.href)
6+
await prepareAssets({ overwriteExisting: true })
1477
}
1488

1499
main().catch((error) => {

packages/monorepo-templates/src/index.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
1+
import type { TemplateChoice, TemplateDefinition } from './types'
12
import { assetTargets as rawAssetTargets, getAssetTargets as rawGetAssetTargets } from '../assets-data.mjs'
23
import { templateChoices as rawTemplateChoices } from '../template-data.mjs'
34
import { assetsDir, packageDir, skeletonDir, templatesDir } from './paths'
45
import { prepareAssets } from './prepare'
6+
import { scaffoldTemplate, scaffoldWorkspace } from './scaffold'
57
import { runCommand } from './utils/command'
68
import { isGitignoreFile, toPublishGitignorePath, toWorkspaceGitignorePath } from './utils/gitignore'
79
import { createTemplateCopyFilter, shouldSkipTemplatePath } from './utils/template-filter'
810

9-
export interface TemplateChoice {
10-
key: string
11-
label: string
12-
source: string
13-
target: string
14-
}
15-
1611
export const templateChoices = rawTemplateChoices as TemplateChoice[]
1712
export const assetTargets = rawAssetTargets as string[]
1813
export const getAssetTargets = rawGetAssetTargets as (core?: boolean) => string[]
@@ -30,6 +25,7 @@ export const templateTargetMap = Object.fromEntries(
3025
export const templateMap = templateSourceMap
3126

3227
export { prepareAssets }
28+
export { scaffoldTemplate, scaffoldWorkspace }
3329
export {
3430
createTemplateCopyFilter,
3531
isGitignoreFile,
@@ -38,6 +34,7 @@ export {
3834
toPublishGitignorePath,
3935
toWorkspaceGitignorePath,
4036
}
37+
export type { TemplateChoice, TemplateDefinition }
4138
export { default as checkbox } from '@inquirer/checkbox'
4239
export { default as input } from '@inquirer/input'
4340
export { default as select } from '@inquirer/select'

0 commit comments

Comments
 (0)