preskok-ui 0.0.5 → 0.0.6
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 +2 -1
- package/bin/preskok-ui.mjs +246 -25
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
Thin CLI wrapper around shadcn with Preskok registry wiring.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
+
npx preskok-ui@latest init
|
|
6
7
|
npx preskok-ui@latest init button
|
|
7
8
|
```
|
|
8
9
|
|
|
9
|
-
The CLI delegates to `shadcn@latest`. `init` installs the Preskok base and optional components in one pass
|
|
10
|
+
The CLI delegates to `shadcn@latest`. `init` installs the Preskok base for new projects, only registers the Preskok namespace in projects that already have `components.json`, and can add optional components in one pass. `add` resolves bare component names through the Preskok registry.
|
|
10
11
|
|
|
11
12
|
```bash
|
|
12
13
|
npx preskok-ui@latest registry
|
package/bin/preskok-ui.mjs
CHANGED
|
@@ -1,12 +1,44 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawnSync } from "node:child_process"
|
|
3
|
+
import { existsSync, readFileSync, unlinkSync, writeFileSync } from "node:fs"
|
|
4
|
+
import path from "node:path"
|
|
3
5
|
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
+
const REGISTRY_BASE_URL = (
|
|
7
|
+
process.env.PRESKOK_REGISTRY_URL ?? "https://ui-three-mu.vercel.app"
|
|
8
|
+
).replace(/\/$/, "")
|
|
9
|
+
const REGISTRY = `@preskok=${REGISTRY_BASE_URL}/r/{name}.json`
|
|
10
|
+
const DEFAULT_REGISTRY_ITEM = `${REGISTRY_BASE_URL}/r/default.json`
|
|
6
11
|
const CWD_OPTION_VALUES = new Set(["-c", "--cwd"])
|
|
12
|
+
const ADD_OPTION_VALUES = new Set(["-c", "--cwd", "-p", "--path", "--diff"])
|
|
13
|
+
const DEPENDENCY_SECTIONS = [
|
|
14
|
+
"dependencies",
|
|
15
|
+
"devDependencies",
|
|
16
|
+
"optionalDependencies",
|
|
17
|
+
"peerDependencies",
|
|
18
|
+
]
|
|
19
|
+
const INIT_OPTION_VALUES = new Set([
|
|
20
|
+
"-t",
|
|
21
|
+
"--template",
|
|
22
|
+
"-b",
|
|
23
|
+
"--base",
|
|
24
|
+
"-p",
|
|
25
|
+
"--preset",
|
|
26
|
+
"-c",
|
|
27
|
+
"--cwd",
|
|
28
|
+
"-n",
|
|
29
|
+
"--name",
|
|
30
|
+
])
|
|
7
31
|
|
|
8
32
|
const args = process.argv.slice(2)
|
|
9
33
|
const [command, ...commandArgs] = args
|
|
34
|
+
const LOCKFILES = [
|
|
35
|
+
"package-lock.json",
|
|
36
|
+
"npm-shrinkwrap.json",
|
|
37
|
+
"pnpm-lock.yaml",
|
|
38
|
+
"yarn.lock",
|
|
39
|
+
"bun.lock",
|
|
40
|
+
"bun.lockb",
|
|
41
|
+
]
|
|
10
42
|
|
|
11
43
|
if (!command || command === "-h" || command === "--help") {
|
|
12
44
|
printHelp()
|
|
@@ -14,20 +46,54 @@ if (!command || command === "-h" || command === "--help") {
|
|
|
14
46
|
}
|
|
15
47
|
|
|
16
48
|
if (command === "add") {
|
|
17
|
-
const registryStatus = runShadcn([
|
|
49
|
+
const registryStatus = runShadcn([
|
|
50
|
+
"registry",
|
|
51
|
+
"add",
|
|
52
|
+
REGISTRY,
|
|
53
|
+
...getCommandOptions(commandArgs, CWD_OPTION_VALUES),
|
|
54
|
+
])
|
|
18
55
|
|
|
19
56
|
if (registryStatus !== 0) {
|
|
20
57
|
process.exit(registryStatus)
|
|
21
58
|
}
|
|
22
59
|
|
|
23
60
|
process.exit(
|
|
24
|
-
|
|
61
|
+
runPreskokAdd(toPreskokCommandItems(commandArgs, ADD_OPTION_VALUES))
|
|
25
62
|
)
|
|
26
63
|
}
|
|
27
64
|
|
|
28
65
|
if (command === "init") {
|
|
66
|
+
const { initArgs, items } = splitInitArgs(commandArgs)
|
|
67
|
+
const cwd = getCwd(initArgs)
|
|
68
|
+
|
|
69
|
+
if (!existsSync(path.join(cwd, "components.json"))) {
|
|
70
|
+
const initStatus = runShadcn(["init", DEFAULT_REGISTRY_ITEM, ...initArgs])
|
|
71
|
+
|
|
72
|
+
if (initStatus !== 0) {
|
|
73
|
+
process.exit(initStatus)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const registryStatus = runShadcn([
|
|
78
|
+
"registry",
|
|
79
|
+
"add",
|
|
80
|
+
REGISTRY,
|
|
81
|
+
...getCommandOptions(initArgs, CWD_OPTION_VALUES),
|
|
82
|
+
])
|
|
83
|
+
|
|
84
|
+
if (registryStatus !== 0) {
|
|
85
|
+
process.exit(registryStatus)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (items.length === 0) {
|
|
89
|
+
process.exit(0)
|
|
90
|
+
}
|
|
91
|
+
|
|
29
92
|
process.exit(
|
|
30
|
-
|
|
93
|
+
runPreskokAdd([
|
|
94
|
+
...getCommandOptions(initArgs, CWD_OPTION_VALUES),
|
|
95
|
+
...toPreskokItems(items),
|
|
96
|
+
])
|
|
31
97
|
)
|
|
32
98
|
}
|
|
33
99
|
|
|
@@ -39,7 +105,10 @@ if (command === "registry") {
|
|
|
39
105
|
|
|
40
106
|
if (command === "view") {
|
|
41
107
|
process.exit(
|
|
42
|
-
runShadcn([
|
|
108
|
+
runShadcn([
|
|
109
|
+
"view",
|
|
110
|
+
...toPreskokCommandItems(commandArgs, CWD_OPTION_VALUES),
|
|
111
|
+
])
|
|
43
112
|
)
|
|
44
113
|
}
|
|
45
114
|
|
|
@@ -76,6 +145,14 @@ function runShadcn(shadcnArgs) {
|
|
|
76
145
|
return result.status ?? 1
|
|
77
146
|
}
|
|
78
147
|
|
|
148
|
+
function runPreskokAdd(addArgs) {
|
|
149
|
+
const packageState = capturePackageState(addArgs)
|
|
150
|
+
const status = runShadcn(["add", "--yes", ...addArgs])
|
|
151
|
+
restorePackageState(packageState)
|
|
152
|
+
|
|
153
|
+
return status
|
|
154
|
+
}
|
|
155
|
+
|
|
79
156
|
function toPreskokItems(values) {
|
|
80
157
|
return values.map(toPreskokItem)
|
|
81
158
|
}
|
|
@@ -106,46 +183,190 @@ function toPreskokCommandItems(values, optionsWithValues) {
|
|
|
106
183
|
})
|
|
107
184
|
}
|
|
108
185
|
|
|
109
|
-
function
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
"--template",
|
|
113
|
-
"-b",
|
|
114
|
-
"--base",
|
|
115
|
-
"-p",
|
|
116
|
-
"--preset",
|
|
117
|
-
"-c",
|
|
118
|
-
"--cwd",
|
|
119
|
-
"-n",
|
|
120
|
-
"--name",
|
|
121
|
-
])
|
|
186
|
+
function getCommandOptions(values, optionsWithValues) {
|
|
187
|
+
let skipNext = false
|
|
188
|
+
const options = []
|
|
122
189
|
|
|
190
|
+
for (const value of values) {
|
|
191
|
+
if (skipNext) {
|
|
192
|
+
skipNext = false
|
|
193
|
+
options.push(value)
|
|
194
|
+
continue
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (optionsWithValues.has(value)) {
|
|
198
|
+
skipNext = true
|
|
199
|
+
options.push(value)
|
|
200
|
+
continue
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (hasInlineOptionValue(value, optionsWithValues)) {
|
|
204
|
+
options.push(value)
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return options
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function splitInitArgs(values) {
|
|
123
212
|
let skipNext = false
|
|
213
|
+
const initArgs = []
|
|
214
|
+
const items = []
|
|
124
215
|
|
|
125
|
-
|
|
216
|
+
for (const value of values) {
|
|
126
217
|
if (skipNext) {
|
|
127
218
|
skipNext = false
|
|
128
|
-
|
|
219
|
+
initArgs.push(value)
|
|
220
|
+
continue
|
|
129
221
|
}
|
|
130
222
|
|
|
131
|
-
if (
|
|
223
|
+
if (INIT_OPTION_VALUES.has(value)) {
|
|
132
224
|
skipNext = true
|
|
133
|
-
|
|
225
|
+
initArgs.push(value)
|
|
226
|
+
continue
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (
|
|
230
|
+
hasInlineOptionValue(value, INIT_OPTION_VALUES) ||
|
|
231
|
+
value.startsWith("-")
|
|
232
|
+
) {
|
|
233
|
+
initArgs.push(value)
|
|
234
|
+
continue
|
|
134
235
|
}
|
|
135
236
|
|
|
136
|
-
|
|
237
|
+
items.push(value)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return { initArgs, items }
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function getCwd(values) {
|
|
244
|
+
for (let index = 0; index < values.length; index++) {
|
|
245
|
+
const value = values[index]
|
|
246
|
+
|
|
247
|
+
if (value === "-c" || value === "--cwd") {
|
|
248
|
+
return path.resolve(values[index + 1] ?? process.cwd())
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (value.startsWith("--cwd=")) {
|
|
252
|
+
return path.resolve(value.slice("--cwd=".length))
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return process.cwd()
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function hasInlineOptionValue(value, options) {
|
|
260
|
+
return [...options].some((option) => value.startsWith(`${option}=`))
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function capturePackageState(values) {
|
|
264
|
+
const cwd = getCwd(values)
|
|
265
|
+
const packageJsonPath = path.join(cwd, "package.json")
|
|
266
|
+
|
|
267
|
+
if (!existsSync(packageJsonPath)) {
|
|
268
|
+
return null
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const packageJsonContent = readFileSync(packageJsonPath, "utf8")
|
|
272
|
+
const packageJson = JSON.parse(packageJsonContent)
|
|
273
|
+
const lockfiles = new Map()
|
|
274
|
+
|
|
275
|
+
for (const lockfile of LOCKFILES) {
|
|
276
|
+
const lockfilePath = path.join(cwd, lockfile)
|
|
277
|
+
|
|
278
|
+
if (existsSync(lockfilePath)) {
|
|
279
|
+
lockfiles.set(lockfile, readFileSync(lockfilePath))
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return {
|
|
284
|
+
cwd,
|
|
285
|
+
lockfiles,
|
|
286
|
+
packageJson,
|
|
287
|
+
packageJsonContent,
|
|
288
|
+
packageJsonPath,
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function restorePackageState(packageState) {
|
|
293
|
+
if (!packageState || !existsSync(packageState.packageJsonPath)) {
|
|
294
|
+
return
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const packageJson = JSON.parse(
|
|
298
|
+
readFileSync(packageState.packageJsonPath, "utf8")
|
|
299
|
+
)
|
|
300
|
+
const beforeDependencyNames = getDependencyNames(packageState.packageJson)
|
|
301
|
+
const afterDependencyNames = getDependencyNames(packageJson)
|
|
302
|
+
const hasNewDependencies = [...afterDependencyNames].some((dependency) => {
|
|
303
|
+
return !beforeDependencyNames.has(dependency)
|
|
137
304
|
})
|
|
305
|
+
|
|
306
|
+
if (!hasNewDependencies) {
|
|
307
|
+
writeFileSync(packageState.packageJsonPath, packageState.packageJsonContent)
|
|
308
|
+
restoreLockfiles(packageState)
|
|
309
|
+
return
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
restoreExistingDependencySpecs(packageState.packageJson, packageJson)
|
|
313
|
+
writeFileSync(
|
|
314
|
+
packageState.packageJsonPath,
|
|
315
|
+
`${JSON.stringify(packageJson, null, 2)}\n`
|
|
316
|
+
)
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function getDependencyNames(packageJson) {
|
|
320
|
+
const names = new Set()
|
|
321
|
+
|
|
322
|
+
for (const section of DEPENDENCY_SECTIONS) {
|
|
323
|
+
for (const dependency of Object.keys(packageJson[section] ?? {})) {
|
|
324
|
+
names.add(dependency)
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return names
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function restoreExistingDependencySpecs(sourcePackageJson, targetPackageJson) {
|
|
332
|
+
for (const section of DEPENDENCY_SECTIONS) {
|
|
333
|
+
const sourceDependencies = sourcePackageJson[section] ?? {}
|
|
334
|
+
const targetDependencies = targetPackageJson[section] ?? {}
|
|
335
|
+
|
|
336
|
+
for (const [dependency, version] of Object.entries(sourceDependencies)) {
|
|
337
|
+
if (targetDependencies[dependency] !== undefined) {
|
|
338
|
+
targetDependencies[dependency] = version
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
function restoreLockfiles(packageState) {
|
|
345
|
+
for (const lockfile of LOCKFILES) {
|
|
346
|
+
const lockfilePath = path.join(packageState.cwd, lockfile)
|
|
347
|
+
const content = packageState.lockfiles.get(lockfile)
|
|
348
|
+
|
|
349
|
+
if (content) {
|
|
350
|
+
writeFileSync(lockfilePath, content)
|
|
351
|
+
continue
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (existsSync(lockfilePath)) {
|
|
355
|
+
unlinkSync(lockfilePath)
|
|
356
|
+
}
|
|
357
|
+
}
|
|
138
358
|
}
|
|
139
359
|
|
|
140
360
|
function printHelp() {
|
|
141
361
|
console.log(`Usage: preskok-ui <command> [options]
|
|
142
362
|
|
|
143
363
|
Commands:
|
|
144
|
-
init [items...] run shadcn init
|
|
364
|
+
init [items...] run shadcn init, register Preskok, and optionally add items
|
|
145
365
|
add <items...> register Preskok and add items by name
|
|
146
366
|
registry register the @preskok namespace in components.json
|
|
147
367
|
|
|
148
368
|
Examples:
|
|
369
|
+
npx preskok-ui@latest init
|
|
149
370
|
npx preskok-ui@latest init button
|
|
150
371
|
npx preskok-ui@latest add button
|
|
151
372
|
npx preskok-ui@latest view button
|