@bagelink/workspace 1.7.4 ā 1.9.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 +132 -1
- package/bin/bgl.ts +51 -4
- package/dist/bin/bgl.cjs +44 -5
- package/dist/bin/bgl.mjs +44 -5
- package/dist/index.cjs +14 -10
- package/dist/index.d.cts +19 -1
- package/dist/index.d.mts +19 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.mjs +2 -2
- package/dist/shared/workspace.CCUm_5GG.cjs +746 -0
- package/dist/shared/workspace.cX7U2RUq.mjs +730 -0
- package/package.json +9 -4
- package/src/index.ts +3 -0
- package/src/lint.ts +235 -0
- package/src/workspace.ts +432 -0
- package/dist/shared/workspace.R3ocIOTb.mjs +0 -234
- package/dist/shared/workspace.hk0HFYa9.cjs +0 -246
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bagelink/workspace",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.9.0",
|
|
5
5
|
"description": "Monorepo workspace tooling for Bagel projects with proxy and config management",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Bagel Studio",
|
|
@@ -52,6 +52,14 @@
|
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"prompts": "^2.4.2"
|
|
54
54
|
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"vite": ">=5.0.0"
|
|
57
|
+
},
|
|
58
|
+
"peerDependenciesMeta": {
|
|
59
|
+
"@bagelink/lint-config": {
|
|
60
|
+
"optional": true
|
|
61
|
+
}
|
|
62
|
+
},
|
|
55
63
|
"devDependencies": {
|
|
56
64
|
"@types/node": "^24.0.0",
|
|
57
65
|
"@types/prompts": "^2.4.9",
|
|
@@ -59,9 +67,6 @@
|
|
|
59
67
|
"typescript": "^5.8.3",
|
|
60
68
|
"unbuild": "^3.5.0"
|
|
61
69
|
},
|
|
62
|
-
"peerDependencies": {
|
|
63
|
-
"vite": ">=5.0.0"
|
|
64
|
-
},
|
|
65
70
|
"scripts": {
|
|
66
71
|
"dev": "unbuild --stub",
|
|
67
72
|
"build": "unbuild",
|
package/src/index.ts
CHANGED
package/src/lint.ts
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { existsSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import { resolve } from 'node:path'
|
|
3
|
+
import process from 'node:process'
|
|
4
|
+
import prompts from 'prompts'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Set up linting in a project
|
|
8
|
+
*/
|
|
9
|
+
export async function setupLint(
|
|
10
|
+
root: string = process.cwd(),
|
|
11
|
+
isWorkspace: boolean = false,
|
|
12
|
+
): Promise<void> {
|
|
13
|
+
console.log('\nš Setting up linting...\n')
|
|
14
|
+
|
|
15
|
+
const response = await prompts([
|
|
16
|
+
{
|
|
17
|
+
type: 'multiselect',
|
|
18
|
+
name: 'configs',
|
|
19
|
+
message: 'Select configurations to set up:',
|
|
20
|
+
choices: [
|
|
21
|
+
{ title: 'ESLint', value: 'eslint', selected: true },
|
|
22
|
+
{ title: 'Prettier', value: 'prettier', selected: true },
|
|
23
|
+
{ title: 'EditorConfig', value: 'editorconfig', selected: true },
|
|
24
|
+
{ title: 'Git Hooks', value: 'githooks', selected: false },
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
type: 'confirm',
|
|
29
|
+
name: 'installDeps',
|
|
30
|
+
message: 'Install dependencies?',
|
|
31
|
+
initial: true,
|
|
32
|
+
},
|
|
33
|
+
])
|
|
34
|
+
|
|
35
|
+
if (!response || !response.configs) {
|
|
36
|
+
console.log('\nā Setup cancelled.\n')
|
|
37
|
+
process.exit(1)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const { configs, installDeps } = response
|
|
41
|
+
|
|
42
|
+
// Create config files
|
|
43
|
+
if (configs.includes('eslint')) {
|
|
44
|
+
createEslintConfig(root, isWorkspace)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (configs.includes('prettier')) {
|
|
48
|
+
createPrettierConfig(root)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (configs.includes('editorconfig')) {
|
|
52
|
+
createEditorConfig(root)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (configs.includes('githooks')) {
|
|
56
|
+
createGitHooks(root)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Update package.json
|
|
60
|
+
updatePackageJsonLint(root, configs)
|
|
61
|
+
|
|
62
|
+
if (installDeps) {
|
|
63
|
+
console.log('\nš¦ Installing dependencies...')
|
|
64
|
+
console.log('Run: bun add -D @bagelink/lint-config eslint prettier typescript')
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
console.log('\nā
Linting setup complete!')
|
|
68
|
+
console.log('\nAvailable commands:')
|
|
69
|
+
console.log(' bun run lint - Run linter')
|
|
70
|
+
console.log(' bun run lint:fix - Fix linting issues')
|
|
71
|
+
console.log(' bun run format - Format code with Prettier')
|
|
72
|
+
console.log('')
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Create ESLint config
|
|
77
|
+
*/
|
|
78
|
+
function createEslintConfig(root: string, isWorkspace: boolean): void {
|
|
79
|
+
const configPath = resolve(root, 'eslint.config.js')
|
|
80
|
+
|
|
81
|
+
const config = isWorkspace
|
|
82
|
+
? `import { defineConfig } from '@bagelink/lint-config/eslint'
|
|
83
|
+
|
|
84
|
+
export default defineConfig({
|
|
85
|
+
// Workspace-level ESLint config
|
|
86
|
+
ignores: ['**/dist/**', '**/node_modules/**', '**/.bun-cache/**'],
|
|
87
|
+
})
|
|
88
|
+
`
|
|
89
|
+
: `import vue3Config from '@bagelink/lint-config/eslint/vue3'
|
|
90
|
+
|
|
91
|
+
export default vue3Config
|
|
92
|
+
`
|
|
93
|
+
|
|
94
|
+
writeFileSync(configPath, config)
|
|
95
|
+
console.log('ā
Created eslint.config.js')
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Create Prettier config
|
|
100
|
+
*/
|
|
101
|
+
function createPrettierConfig(root: string): void {
|
|
102
|
+
const configPath = resolve(root, '.prettierrc')
|
|
103
|
+
|
|
104
|
+
const config = {
|
|
105
|
+
semi: false,
|
|
106
|
+
singleQuote: true,
|
|
107
|
+
tabWidth: 2,
|
|
108
|
+
useTabs: true,
|
|
109
|
+
trailingComma: 'all',
|
|
110
|
+
printWidth: 100,
|
|
111
|
+
arrowParens: 'avoid',
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`)
|
|
115
|
+
console.log('ā
Created .prettierrc')
|
|
116
|
+
|
|
117
|
+
// .prettierignore
|
|
118
|
+
const ignorePath = resolve(root, '.prettierignore')
|
|
119
|
+
const ignore = `dist
|
|
120
|
+
node_modules
|
|
121
|
+
.bun-cache
|
|
122
|
+
*.min.js
|
|
123
|
+
*.min.css
|
|
124
|
+
`
|
|
125
|
+
|
|
126
|
+
writeFileSync(ignorePath, ignore)
|
|
127
|
+
console.log('ā
Created .prettierignore')
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Create EditorConfig
|
|
132
|
+
*/
|
|
133
|
+
function createEditorConfig(root: string): void {
|
|
134
|
+
const configPath = resolve(root, '.editorconfig')
|
|
135
|
+
|
|
136
|
+
const config = `root = true
|
|
137
|
+
|
|
138
|
+
[*]
|
|
139
|
+
charset = utf-8
|
|
140
|
+
indent_style = tab
|
|
141
|
+
indent_size = 2
|
|
142
|
+
end_of_line = lf
|
|
143
|
+
insert_final_newline = true
|
|
144
|
+
trim_trailing_whitespace = true
|
|
145
|
+
|
|
146
|
+
[*.md]
|
|
147
|
+
trim_trailing_whitespace = false
|
|
148
|
+
|
|
149
|
+
[*.{json,yml,yaml}]
|
|
150
|
+
indent_style = space
|
|
151
|
+
indent_size = 2
|
|
152
|
+
`
|
|
153
|
+
|
|
154
|
+
writeFileSync(configPath, config)
|
|
155
|
+
console.log('ā
Created .editorconfig')
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Create Git Hooks
|
|
160
|
+
*/
|
|
161
|
+
function createGitHooks(root: string): void {
|
|
162
|
+
const packageJsonPath = resolve(root, 'package.json')
|
|
163
|
+
|
|
164
|
+
if (!existsSync(packageJsonPath)) {
|
|
165
|
+
console.warn('ā ļø No package.json found, skipping git hooks')
|
|
166
|
+
return
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// .lintstagedrc
|
|
170
|
+
const lintStagedConfig = {
|
|
171
|
+
'*.{js,jsx,ts,tsx,vue}': ['eslint --fix'],
|
|
172
|
+
'*.{json,md,yml,yaml}': ['prettier --write'],
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
writeFileSync(
|
|
176
|
+
resolve(root, '.lintstagedrc'),
|
|
177
|
+
`${JSON.stringify(lintStagedConfig, null, 2)}\n`,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
console.log('ā
Created .lintstagedrc')
|
|
181
|
+
console.log('ā¹ļø Add simple-git-hooks and lint-staged to devDependencies')
|
|
182
|
+
console.log(' Then run: npx simple-git-hooks')
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Update package.json with lint scripts
|
|
187
|
+
*/
|
|
188
|
+
function updatePackageJsonLint(root: string, configs: string[]): void {
|
|
189
|
+
const packageJsonPath = resolve(root, 'package.json')
|
|
190
|
+
|
|
191
|
+
if (!existsSync(packageJsonPath)) {
|
|
192
|
+
console.warn('ā ļø No package.json found')
|
|
193
|
+
return
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
const packageJson = JSON.parse(
|
|
198
|
+
require('fs').readFileSync(packageJsonPath, 'utf-8'),
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
if (!packageJson.scripts) {
|
|
202
|
+
packageJson.scripts = {}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Add lint scripts
|
|
206
|
+
if (configs.includes('eslint')) {
|
|
207
|
+
if (!packageJson.scripts.lint) {
|
|
208
|
+
packageJson.scripts.lint = 'eslint .'
|
|
209
|
+
}
|
|
210
|
+
if (!packageJson.scripts['lint:fix']) {
|
|
211
|
+
packageJson.scripts['lint:fix'] = 'eslint . --fix'
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Add format scripts
|
|
216
|
+
if (configs.includes('prettier')) {
|
|
217
|
+
if (!packageJson.scripts.format) {
|
|
218
|
+
packageJson.scripts.format = 'prettier --write .'
|
|
219
|
+
}
|
|
220
|
+
if (!packageJson.scripts['format:check']) {
|
|
221
|
+
packageJson.scripts['format:check'] = 'prettier --check .'
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
writeFileSync(
|
|
226
|
+
packageJsonPath,
|
|
227
|
+
`${JSON.stringify(packageJson, null, 2)}\n`,
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
console.log('ā
Updated package.json with lint scripts')
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
console.error('ā Failed to update package.json:', error)
|
|
234
|
+
}
|
|
235
|
+
}
|
package/src/workspace.ts
ADDED
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import { resolve } from 'node:path'
|
|
3
|
+
import process from 'node:process'
|
|
4
|
+
import prompts from 'prompts'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Initialize a new workspace with flat structure
|
|
8
|
+
*/
|
|
9
|
+
export async function initWorkspace(root: string = process.cwd()): Promise<void> {
|
|
10
|
+
console.log('\nš Creating Bagel workspace...\n')
|
|
11
|
+
|
|
12
|
+
const response = await prompts([
|
|
13
|
+
{
|
|
14
|
+
type: 'text',
|
|
15
|
+
name: 'workspaceName',
|
|
16
|
+
message: 'Workspace name:',
|
|
17
|
+
initial: 'my-workspace',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
type: 'text',
|
|
21
|
+
name: 'projectId',
|
|
22
|
+
message: 'Bagel project ID:',
|
|
23
|
+
initial: 'my-project',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
type: 'confirm',
|
|
27
|
+
name: 'createFirstProject',
|
|
28
|
+
message: 'Create first project?',
|
|
29
|
+
initial: true,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
type: (prev: boolean) => (prev ? 'text' : null),
|
|
33
|
+
name: 'firstProjectName',
|
|
34
|
+
message: 'First project name:',
|
|
35
|
+
initial: 'web',
|
|
36
|
+
},
|
|
37
|
+
])
|
|
38
|
+
|
|
39
|
+
if (!response || !response.workspaceName) {
|
|
40
|
+
console.log('\nā Workspace creation cancelled.\n')
|
|
41
|
+
process.exit(1)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const { workspaceName, projectId, createFirstProject, firstProjectName } = response
|
|
45
|
+
|
|
46
|
+
// Create workspace structure
|
|
47
|
+
createWorkspaceRoot(root, workspaceName, projectId)
|
|
48
|
+
|
|
49
|
+
// Create shared package
|
|
50
|
+
createSharedPackage(root)
|
|
51
|
+
|
|
52
|
+
if (createFirstProject && firstProjectName) {
|
|
53
|
+
await addProject(firstProjectName, root)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
console.log('\nā
Workspace created successfully!')
|
|
57
|
+
console.log('\nNext steps:')
|
|
58
|
+
console.log(` cd ${workspaceName}`)
|
|
59
|
+
console.log(' bun install')
|
|
60
|
+
if (createFirstProject) {
|
|
61
|
+
console.log(` bun run dev:${firstProjectName}`)
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
console.log(' bgl add <project-name> # Add a project')
|
|
65
|
+
}
|
|
66
|
+
console.log('')
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Create workspace root files
|
|
71
|
+
*/
|
|
72
|
+
function createWorkspaceRoot(root: string, name: string, projectId: string): void {
|
|
73
|
+
const workspaceDir = resolve(root, name)
|
|
74
|
+
|
|
75
|
+
if (existsSync(workspaceDir)) {
|
|
76
|
+
console.error(`ā Directory ${name} already exists`)
|
|
77
|
+
process.exit(1)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
mkdirSync(workspaceDir, { recursive: true })
|
|
81
|
+
|
|
82
|
+
// package.json
|
|
83
|
+
const packageJson = {
|
|
84
|
+
name,
|
|
85
|
+
private: true,
|
|
86
|
+
workspaces: ['*', '!node_modules'],
|
|
87
|
+
scripts: {
|
|
88
|
+
dev: 'bun run --filter \'./[!shared]*\' dev',
|
|
89
|
+
build: 'bun run --filter \'./[!shared]*\' build',
|
|
90
|
+
typecheck: 'tsc --noEmit',
|
|
91
|
+
},
|
|
92
|
+
devDependencies: {
|
|
93
|
+
'@bagelink/workspace': 'latest',
|
|
94
|
+
typescript: '^5.0.0',
|
|
95
|
+
vite: 'latest',
|
|
96
|
+
},
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
writeFileSync(
|
|
100
|
+
resolve(workspaceDir, 'package.json'),
|
|
101
|
+
`${JSON.stringify(packageJson, null, 2)}\n`,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
// bgl.config.ts (shared)
|
|
105
|
+
const bglConfig = `import { defineWorkspace } from '@bagelink/workspace'
|
|
106
|
+
|
|
107
|
+
export default defineWorkspace({
|
|
108
|
+
localhost: {
|
|
109
|
+
host: 'http://localhost:8000',
|
|
110
|
+
proxy: '/api',
|
|
111
|
+
openapi_url: 'http://localhost:8000/openapi.json',
|
|
112
|
+
},
|
|
113
|
+
development: {
|
|
114
|
+
host: 'https://${projectId}.bagel.to',
|
|
115
|
+
proxy: '/api',
|
|
116
|
+
openapi_url: 'https://${projectId}.bagel.to/openapi.json',
|
|
117
|
+
},
|
|
118
|
+
production: {
|
|
119
|
+
host: 'https://${projectId}.bagel.to',
|
|
120
|
+
proxy: '/api',
|
|
121
|
+
openapi_url: 'https://${projectId}.bagel.to/openapi.json',
|
|
122
|
+
},
|
|
123
|
+
})
|
|
124
|
+
`
|
|
125
|
+
|
|
126
|
+
writeFileSync(resolve(workspaceDir, 'bgl.config.ts'), bglConfig)
|
|
127
|
+
|
|
128
|
+
// tsconfig.json
|
|
129
|
+
const tsConfig = {
|
|
130
|
+
compilerOptions: {
|
|
131
|
+
target: 'ES2020',
|
|
132
|
+
useDefineForClassFields: true,
|
|
133
|
+
module: 'ESNext',
|
|
134
|
+
lib: ['ES2020', 'DOM', 'DOM.Iterable'],
|
|
135
|
+
skipLibCheck: true,
|
|
136
|
+
moduleResolution: 'bundler',
|
|
137
|
+
allowImportingTsExtensions: true,
|
|
138
|
+
resolveJsonModule: true,
|
|
139
|
+
isolatedModules: true,
|
|
140
|
+
noEmit: true,
|
|
141
|
+
jsx: 'preserve',
|
|
142
|
+
strict: true,
|
|
143
|
+
noUnusedLocals: true,
|
|
144
|
+
noUnusedParameters: true,
|
|
145
|
+
noFallthroughCasesInSwitch: true,
|
|
146
|
+
baseUrl: '.',
|
|
147
|
+
paths: {
|
|
148
|
+
'shared/*': ['./shared/*'],
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
writeFileSync(
|
|
154
|
+
resolve(workspaceDir, 'tsconfig.json'),
|
|
155
|
+
`${JSON.stringify(tsConfig, null, 2)}\n`,
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
// .gitignore
|
|
159
|
+
const gitignore = `node_modules
|
|
160
|
+
dist
|
|
161
|
+
.DS_Store
|
|
162
|
+
*.local
|
|
163
|
+
.env.local
|
|
164
|
+
.vite
|
|
165
|
+
`
|
|
166
|
+
|
|
167
|
+
writeFileSync(resolve(workspaceDir, '.gitignore'), gitignore)
|
|
168
|
+
|
|
169
|
+
console.log(`ā
Created workspace: ${name}`)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Create shared package
|
|
174
|
+
*/
|
|
175
|
+
function createSharedPackage(root: string): void {
|
|
176
|
+
const sharedDir = resolve(root, 'shared')
|
|
177
|
+
mkdirSync(sharedDir, { recursive: true })
|
|
178
|
+
|
|
179
|
+
// package.json
|
|
180
|
+
const packageJson = {
|
|
181
|
+
name: 'shared',
|
|
182
|
+
version: '1.0.0',
|
|
183
|
+
type: 'module',
|
|
184
|
+
exports: {
|
|
185
|
+
'.': './index.ts',
|
|
186
|
+
'./utils': './utils/index.ts',
|
|
187
|
+
'./types': './types/index.ts',
|
|
188
|
+
},
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
writeFileSync(
|
|
192
|
+
resolve(sharedDir, 'package.json'),
|
|
193
|
+
`${JSON.stringify(packageJson, null, 2)}\n`,
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
// index.ts
|
|
197
|
+
writeFileSync(
|
|
198
|
+
resolve(sharedDir, 'index.ts'),
|
|
199
|
+
'// Shared utilities and exports\nexport * from \'./utils\'\n',
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
// utils/index.ts
|
|
203
|
+
mkdirSync(resolve(sharedDir, 'utils'), { recursive: true })
|
|
204
|
+
writeFileSync(
|
|
205
|
+
resolve(sharedDir, 'utils', 'index.ts'),
|
|
206
|
+
'// Shared utility functions\nexport function formatDate(date: Date): string {\n return date.toISOString()\n}\n',
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
// types/index.ts
|
|
210
|
+
mkdirSync(resolve(sharedDir, 'types'), { recursive: true })
|
|
211
|
+
writeFileSync(
|
|
212
|
+
resolve(sharedDir, 'types', 'index.ts'),
|
|
213
|
+
'// Shared types\nexport interface User {\n id: string\n name: string\n}\n',
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
console.log('ā
Created shared package')
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Add a new project to the workspace
|
|
221
|
+
*/
|
|
222
|
+
export async function addProject(
|
|
223
|
+
name: string,
|
|
224
|
+
root: string = process.cwd(),
|
|
225
|
+
): Promise<void> {
|
|
226
|
+
const projectDir = resolve(root, name)
|
|
227
|
+
|
|
228
|
+
if (existsSync(projectDir)) {
|
|
229
|
+
console.error(`ā Project ${name} already exists`)
|
|
230
|
+
process.exit(1)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
console.log(`\nš¦ Creating project: ${name}\n`)
|
|
234
|
+
|
|
235
|
+
mkdirSync(projectDir, { recursive: true })
|
|
236
|
+
|
|
237
|
+
// Determine if this is part of a workspace
|
|
238
|
+
const isWorkspace = existsSync(resolve(root, 'bgl.config.ts'))
|
|
239
|
+
|
|
240
|
+
// package.json
|
|
241
|
+
const packageJson: Record<string, unknown> = {
|
|
242
|
+
name,
|
|
243
|
+
type: 'module',
|
|
244
|
+
scripts: {
|
|
245
|
+
dev: 'vite',
|
|
246
|
+
build: 'vite build',
|
|
247
|
+
preview: 'vite preview',
|
|
248
|
+
},
|
|
249
|
+
dependencies: {} as Record<string, string>,
|
|
250
|
+
devDependencies: {
|
|
251
|
+
'@vitejs/plugin-vue': 'latest',
|
|
252
|
+
vite: 'latest',
|
|
253
|
+
vue: 'latest',
|
|
254
|
+
},
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Add shared dependency if in workspace
|
|
258
|
+
if (isWorkspace) {
|
|
259
|
+
(packageJson.dependencies as Record<string, string>).shared = 'workspace:*'
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
writeFileSync(
|
|
263
|
+
resolve(projectDir, 'package.json'),
|
|
264
|
+
`${JSON.stringify(packageJson, null, 2)}\n`,
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
// bgl.config.ts
|
|
268
|
+
const bglConfigContent = isWorkspace
|
|
269
|
+
? `import { defineWorkspace } from '@bagelink/workspace'
|
|
270
|
+
import rootWorkspace from '../bgl.config'
|
|
271
|
+
|
|
272
|
+
export default defineWorkspace({
|
|
273
|
+
localhost: rootWorkspace('localhost'),
|
|
274
|
+
development: rootWorkspace('development'),
|
|
275
|
+
production: rootWorkspace('production'),
|
|
276
|
+
})
|
|
277
|
+
`
|
|
278
|
+
: `import { defineWorkspace } from '@bagelink/workspace'
|
|
279
|
+
|
|
280
|
+
export default defineWorkspace({
|
|
281
|
+
localhost: {
|
|
282
|
+
host: 'http://localhost:8000',
|
|
283
|
+
proxy: '/api',
|
|
284
|
+
},
|
|
285
|
+
development: {
|
|
286
|
+
host: 'https://my-project.bagel.to',
|
|
287
|
+
proxy: '/api',
|
|
288
|
+
},
|
|
289
|
+
production: {
|
|
290
|
+
host: 'https://my-project.bagel.to',
|
|
291
|
+
proxy: '/api',
|
|
292
|
+
},
|
|
293
|
+
})
|
|
294
|
+
`
|
|
295
|
+
|
|
296
|
+
writeFileSync(resolve(projectDir, 'bgl.config.ts'), bglConfigContent)
|
|
297
|
+
|
|
298
|
+
// vite.config.ts
|
|
299
|
+
const viteConfig = `import { defineConfig } from 'vite'
|
|
300
|
+
import vue from '@vitejs/plugin-vue'
|
|
301
|
+
import { createViteProxy } from '@bagelink/workspace'
|
|
302
|
+
import workspace from './bgl.config'
|
|
303
|
+
|
|
304
|
+
export default defineConfig(({ mode }) => {
|
|
305
|
+
const config = workspace(mode as 'localhost' | 'development' | 'production')
|
|
306
|
+
|
|
307
|
+
return {
|
|
308
|
+
plugins: [vue()],
|
|
309
|
+
server: {
|
|
310
|
+
proxy: createViteProxy(config),
|
|
311
|
+
},
|
|
312
|
+
}
|
|
313
|
+
})
|
|
314
|
+
`
|
|
315
|
+
|
|
316
|
+
writeFileSync(resolve(projectDir, 'vite.config.ts'), viteConfig)
|
|
317
|
+
|
|
318
|
+
// Create basic src structure
|
|
319
|
+
const srcDir = resolve(projectDir, 'src')
|
|
320
|
+
mkdirSync(srcDir, { recursive: true })
|
|
321
|
+
|
|
322
|
+
// index.html
|
|
323
|
+
const indexHtml = `<!DOCTYPE html>
|
|
324
|
+
<html lang="en">
|
|
325
|
+
<head>
|
|
326
|
+
<meta charset="UTF-8">
|
|
327
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
328
|
+
<title>${name}</title>
|
|
329
|
+
</head>
|
|
330
|
+
<body>
|
|
331
|
+
<div id="app"></div>
|
|
332
|
+
<script type="module" src="/src/main.ts"></script>
|
|
333
|
+
</body>
|
|
334
|
+
</html>
|
|
335
|
+
`
|
|
336
|
+
|
|
337
|
+
writeFileSync(resolve(projectDir, 'index.html'), indexHtml)
|
|
338
|
+
|
|
339
|
+
// main.ts
|
|
340
|
+
const mainTs = `import { createApp } from 'vue'
|
|
341
|
+
import App from './App.vue'
|
|
342
|
+
|
|
343
|
+
createApp(App).mount('#app')
|
|
344
|
+
`
|
|
345
|
+
|
|
346
|
+
writeFileSync(resolve(srcDir, 'main.ts'), mainTs)
|
|
347
|
+
|
|
348
|
+
// App.vue
|
|
349
|
+
const appVue = `<script setup lang="ts">
|
|
350
|
+
import { ref } from 'vue'
|
|
351
|
+
${isWorkspace ? 'import { formatDate } from \'shared/utils\'\n' : ''}
|
|
352
|
+
const count = ref(0)
|
|
353
|
+
</script>
|
|
354
|
+
|
|
355
|
+
<template>
|
|
356
|
+
<div>
|
|
357
|
+
<h1>${name}</h1>
|
|
358
|
+
<button @click="count++">Count: {{ count }}</button>
|
|
359
|
+
${isWorkspace ? '<p>{{ formatDate(new Date()) }}</p>' : ''}
|
|
360
|
+
</div>
|
|
361
|
+
</template>
|
|
362
|
+
`
|
|
363
|
+
|
|
364
|
+
writeFileSync(resolve(srcDir, 'App.vue'), appVue)
|
|
365
|
+
|
|
366
|
+
console.log(`ā
Created project: ${name}`)
|
|
367
|
+
|
|
368
|
+
// Update workspace package.json if needed
|
|
369
|
+
if (isWorkspace) {
|
|
370
|
+
updateWorkspaceScripts(root, name)
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
console.log('\nNext steps:')
|
|
374
|
+
console.log(` cd ${name}`)
|
|
375
|
+
console.log(' bun install')
|
|
376
|
+
console.log(' bun run dev')
|
|
377
|
+
console.log('')
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Update workspace root package.json with new project scripts
|
|
382
|
+
*/
|
|
383
|
+
function updateWorkspaceScripts(root: string, projectName: string): void {
|
|
384
|
+
const packageJsonPath = resolve(root, 'package.json')
|
|
385
|
+
if (!existsSync(packageJsonPath)) return
|
|
386
|
+
|
|
387
|
+
try {
|
|
388
|
+
const packageJson = JSON.parse(
|
|
389
|
+
require('fs').readFileSync(packageJsonPath, 'utf-8'),
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
if (!packageJson.scripts) {
|
|
393
|
+
packageJson.scripts = {}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Add project-specific scripts
|
|
397
|
+
packageJson.scripts[`dev:${projectName}`] = `bun --filter ${projectName} dev`
|
|
398
|
+
packageJson.scripts[`build:${projectName}`] = `bun --filter ${projectName} build`
|
|
399
|
+
|
|
400
|
+
writeFileSync(
|
|
401
|
+
packageJsonPath,
|
|
402
|
+
`${JSON.stringify(packageJson, null, 2)}\n`,
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
console.log(`ā
Added scripts: dev:${projectName}, build:${projectName}`)
|
|
406
|
+
}
|
|
407
|
+
catch (error) {
|
|
408
|
+
console.warn('ā ļø Could not update workspace scripts')
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* List all projects in workspace
|
|
414
|
+
*/
|
|
415
|
+
export function listProjects(root: string = process.cwd()): string[] {
|
|
416
|
+
try {
|
|
417
|
+
const items = readdirSync(root, { withFileTypes: true })
|
|
418
|
+
return items
|
|
419
|
+
.filter(
|
|
420
|
+
item =>
|
|
421
|
+
item.isDirectory()
|
|
422
|
+
&& item.name !== 'node_modules'
|
|
423
|
+
&& item.name !== 'shared'
|
|
424
|
+
&& item.name !== '.git'
|
|
425
|
+
&& !item.name.startsWith('.'),
|
|
426
|
+
)
|
|
427
|
+
.map(item => item.name)
|
|
428
|
+
}
|
|
429
|
+
catch {
|
|
430
|
+
return []
|
|
431
|
+
}
|
|
432
|
+
}
|