@retailcrm/embed-ui 0.9.21 → 0.9.22-alpha.1
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/CHANGELOG.md +21 -0
- package/README.md +102 -2
- package/bin/embed-ui.mjs +2681 -0
- package/dist/meta.json +151 -136
- package/package.json +21 -9
- package/types/widget.d.ts +7 -139
- package/bin/embed-ui-update.mjs +0 -617
package/bin/embed-ui-update.mjs
DELETED
|
@@ -1,617 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { createInterface } from 'node:readline/promises'
|
|
4
|
-
import { execFileSync } from 'node:child_process'
|
|
5
|
-
import fs from 'node:fs'
|
|
6
|
-
import path from 'node:path'
|
|
7
|
-
import { pathToFileURL } from 'node:url'
|
|
8
|
-
import process from 'node:process'
|
|
9
|
-
|
|
10
|
-
export const ROOT_PACKAGE = '@retailcrm/embed-ui'
|
|
11
|
-
export const TARGET_SECTIONS = [
|
|
12
|
-
'dependencies',
|
|
13
|
-
'devDependencies',
|
|
14
|
-
'peerDependencies',
|
|
15
|
-
'optionalDependencies',
|
|
16
|
-
]
|
|
17
|
-
|
|
18
|
-
export const INSTALLABLE_PACKAGES = [
|
|
19
|
-
{
|
|
20
|
-
id: 'embed-ui',
|
|
21
|
-
name: ROOT_PACKAGE,
|
|
22
|
-
section: 'dependencies',
|
|
23
|
-
description: 'Базовый пакет с общим API и согласованными v1-зависимостями.',
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
id: 'components',
|
|
27
|
-
name: '@retailcrm/embed-ui-v1-components',
|
|
28
|
-
section: 'dependencies',
|
|
29
|
-
description: 'UI-компоненты для host/remote приложений.',
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
id: 'contexts',
|
|
33
|
-
name: '@retailcrm/embed-ui-v1-contexts',
|
|
34
|
-
section: 'dependencies',
|
|
35
|
-
description: 'Реактивные контексты RetailCRM JS API.',
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
id: 'types',
|
|
39
|
-
name: '@retailcrm/embed-ui-v1-types',
|
|
40
|
-
section: 'dependencies',
|
|
41
|
-
description: 'Базовые type declarations для RetailCRM JS API.',
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
id: 'testing',
|
|
45
|
-
name: '@retailcrm/embed-ui-v1-testing',
|
|
46
|
-
section: 'devDependencies',
|
|
47
|
-
description: 'Вспомогательные утилиты и типы для тестов интеграций.',
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
id: 'endpoint',
|
|
51
|
-
name: '@retailcrm/embed-ui-v1-endpoint',
|
|
52
|
-
section: 'dependencies',
|
|
53
|
-
description: 'Endpoint API для интеграций в RetailCRM.',
|
|
54
|
-
},
|
|
55
|
-
]
|
|
56
|
-
|
|
57
|
-
const DEFAULT_INDENT = ' '
|
|
58
|
-
const DEFAULT_NEWLINE = '\n'
|
|
59
|
-
const SKIP_DIRECTORIES = new Set([
|
|
60
|
-
'.git',
|
|
61
|
-
'.hg',
|
|
62
|
-
'.svn',
|
|
63
|
-
'.yarn',
|
|
64
|
-
'node_modules',
|
|
65
|
-
'dist',
|
|
66
|
-
'build',
|
|
67
|
-
'coverage',
|
|
68
|
-
])
|
|
69
|
-
|
|
70
|
-
const HELP_TEXT = `Usage:
|
|
71
|
-
npx @retailcrm/embed-ui [target] [version] [options]
|
|
72
|
-
|
|
73
|
-
Options:
|
|
74
|
-
-t, --target <path> Target path (default: current directory)
|
|
75
|
-
-v, --version <ver> Target version. If omitted, latest npm version is used
|
|
76
|
-
--exact Use exact version instead of range
|
|
77
|
-
--dry-run Show changes without writing package.json
|
|
78
|
-
--add Add selected embed-ui packages into one package.json
|
|
79
|
-
--packages <list> Comma-separated package ids or names for --add
|
|
80
|
-
-h, --help Show this help
|
|
81
|
-
|
|
82
|
-
Examples:
|
|
83
|
-
npx @retailcrm/embed-ui
|
|
84
|
-
npx @retailcrm/embed-ui --version 0.9.11
|
|
85
|
-
npx @retailcrm/embed-ui ./my-project 0.9.11
|
|
86
|
-
npx @retailcrm/embed-ui --target ./my-project --dry-run
|
|
87
|
-
npx @retailcrm/embed-ui --add
|
|
88
|
-
npx @retailcrm/embed-ui --add --packages components,contexts
|
|
89
|
-
`
|
|
90
|
-
|
|
91
|
-
const isSemverLike = (value) => /^v?\d+\.\d+\.\d+/.test(value)
|
|
92
|
-
const stripLeadingV = (value) => value.replace(/^v/, '')
|
|
93
|
-
|
|
94
|
-
const parsePackageList = (value) =>
|
|
95
|
-
value
|
|
96
|
-
.split(',')
|
|
97
|
-
.map((entry) => entry.trim())
|
|
98
|
-
.filter(Boolean)
|
|
99
|
-
|
|
100
|
-
export const parseArgs = (argv) => {
|
|
101
|
-
const options = {
|
|
102
|
-
target: process.cwd(),
|
|
103
|
-
version: null,
|
|
104
|
-
dryRun: false,
|
|
105
|
-
exact: false,
|
|
106
|
-
add: false,
|
|
107
|
-
packages: null,
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const positionals = []
|
|
111
|
-
|
|
112
|
-
for (let index = 0; index < argv.length; index++) {
|
|
113
|
-
const argument = argv[index]
|
|
114
|
-
|
|
115
|
-
if (argument === '-h' || argument === '--help') {
|
|
116
|
-
console.log(HELP_TEXT)
|
|
117
|
-
process.exit(0)
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (argument === '-t' || argument === '--target') {
|
|
121
|
-
const value = argv[index + 1]
|
|
122
|
-
if (!value) {
|
|
123
|
-
throw new Error('Option --target requires a value')
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
options.target = path.resolve(process.cwd(), value)
|
|
127
|
-
index++
|
|
128
|
-
continue
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (argument === '-v' || argument === '--version') {
|
|
132
|
-
const value = argv[index + 1]
|
|
133
|
-
if (!value) {
|
|
134
|
-
throw new Error('Option --version requires a value')
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
options.version = stripLeadingV(value)
|
|
138
|
-
index++
|
|
139
|
-
continue
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (argument === '--packages') {
|
|
143
|
-
const value = argv[index + 1]
|
|
144
|
-
if (!value) {
|
|
145
|
-
throw new Error('Option --packages requires a value')
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
options.packages = parsePackageList(value)
|
|
149
|
-
index++
|
|
150
|
-
continue
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
if (argument === '--dry-run') {
|
|
154
|
-
options.dryRun = true
|
|
155
|
-
continue
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (argument === '--exact') {
|
|
159
|
-
options.exact = true
|
|
160
|
-
continue
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (argument === '--add') {
|
|
164
|
-
options.add = true
|
|
165
|
-
continue
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (argument.startsWith('-')) {
|
|
169
|
-
throw new Error(`Unknown option: ${argument}`)
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
positionals.push(argument)
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (positionals.length > 2) {
|
|
176
|
-
throw new Error('Too many positional arguments')
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
if (positionals.length >= 1) {
|
|
180
|
-
const first = positionals[0]
|
|
181
|
-
if (!options.version && isSemverLike(first)) {
|
|
182
|
-
options.version = stripLeadingV(first)
|
|
183
|
-
} else {
|
|
184
|
-
options.target = path.resolve(process.cwd(), first)
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
if (positionals.length === 2) {
|
|
189
|
-
if (options.version) {
|
|
190
|
-
throw new Error('Version is already specified')
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
options.version = stripLeadingV(positionals[1])
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
if (options.packages && !options.add) {
|
|
197
|
-
throw new Error('Option --packages can only be used together with --add')
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return options
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
export const resolveLatestVersion = () => {
|
|
204
|
-
const output = execFileSync(
|
|
205
|
-
'npm',
|
|
206
|
-
['view', ROOT_PACKAGE, 'version'],
|
|
207
|
-
{
|
|
208
|
-
encoding: 'utf8',
|
|
209
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
210
|
-
}
|
|
211
|
-
).trim()
|
|
212
|
-
|
|
213
|
-
if (!output) {
|
|
214
|
-
throw new Error(`Cannot resolve latest version for ${ROOT_PACKAGE}`)
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return output
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
export const isTargetPackage = (name) =>
|
|
221
|
-
name === ROOT_PACKAGE || name.startsWith(`${ROOT_PACKAGE}-`)
|
|
222
|
-
|
|
223
|
-
const createRange = (version, exact) => exact ? version : `^${version}`
|
|
224
|
-
|
|
225
|
-
export const formatRange = (currentRange, nextVersion, exact) => {
|
|
226
|
-
if (exact) {
|
|
227
|
-
return nextVersion
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
if (currentRange.startsWith('workspace:')) {
|
|
231
|
-
return currentRange
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
if (currentRange.startsWith('~')) {
|
|
235
|
-
return `~${nextVersion}`
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
if (currentRange.startsWith('^')) {
|
|
239
|
-
return `^${nextVersion}`
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
return `^${nextVersion}`
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
export const detectFormatting = (source) => {
|
|
246
|
-
const newline = source.includes('\r\n') ? '\r\n' : DEFAULT_NEWLINE
|
|
247
|
-
const indentMatch = source.match(/\n([ \t]+)"/)
|
|
248
|
-
|
|
249
|
-
return {
|
|
250
|
-
indent: indentMatch?.[1] ?? DEFAULT_INDENT,
|
|
251
|
-
newline,
|
|
252
|
-
trailingNewline: source.endsWith('\n') || source.endsWith('\r\n'),
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
export const serializePackageJson = (packageJson, formatting) => {
|
|
257
|
-
const serialized = JSON.stringify(packageJson, null, formatting.indent)
|
|
258
|
-
.replace(/\n/g, formatting.newline)
|
|
259
|
-
|
|
260
|
-
return formatting.trailingNewline
|
|
261
|
-
? `${serialized}${formatting.newline}`
|
|
262
|
-
: serialized
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
const ensureDirectoryExists = (targetPath) => {
|
|
266
|
-
if (!fs.existsSync(targetPath)) {
|
|
267
|
-
throw new Error(`Path not found: ${targetPath}`)
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
const stat = fs.statSync(targetPath)
|
|
271
|
-
if (!stat.isDirectory()) {
|
|
272
|
-
throw new Error(`Target is not a directory: ${targetPath}`)
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
export const resolvePackageJsonPath = (targetPath) => {
|
|
277
|
-
if (path.basename(targetPath) === 'package.json') {
|
|
278
|
-
if (!fs.existsSync(targetPath)) {
|
|
279
|
-
throw new Error(`package.json not found: ${targetPath}`)
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
return targetPath
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
const packageJsonPath = path.resolve(targetPath, 'package.json')
|
|
286
|
-
|
|
287
|
-
if (!fs.existsSync(packageJsonPath)) {
|
|
288
|
-
throw new Error(`package.json not found: ${packageJsonPath}`)
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
return packageJsonPath
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
export const collectPackageJsonPaths = (targetPath) => {
|
|
295
|
-
const resolvedTarget = path.resolve(targetPath)
|
|
296
|
-
|
|
297
|
-
if (!fs.existsSync(resolvedTarget)) {
|
|
298
|
-
throw new Error(`Path not found: ${resolvedTarget}`)
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
if (path.basename(resolvedTarget) === 'package.json') {
|
|
302
|
-
return [resolvedTarget]
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
ensureDirectoryExists(resolvedTarget)
|
|
306
|
-
|
|
307
|
-
const packageJsonPaths = []
|
|
308
|
-
|
|
309
|
-
const visit = (directoryPath) => {
|
|
310
|
-
const packageJsonPath = path.join(directoryPath, 'package.json')
|
|
311
|
-
if (fs.existsSync(packageJsonPath) && fs.statSync(packageJsonPath).isFile()) {
|
|
312
|
-
packageJsonPaths.push(packageJsonPath)
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
for (const entry of fs.readdirSync(directoryPath, { withFileTypes: true })) {
|
|
316
|
-
if (!entry.isDirectory() || entry.isSymbolicLink()) {
|
|
317
|
-
continue
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
if (SKIP_DIRECTORIES.has(entry.name)) {
|
|
321
|
-
continue
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
visit(path.join(directoryPath, entry.name))
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
visit(resolvedTarget)
|
|
329
|
-
|
|
330
|
-
return packageJsonPaths.sort()
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
const findDependencySection = (packageJson, packageName) => {
|
|
334
|
-
for (const section of TARGET_SECTIONS) {
|
|
335
|
-
const dependencyMap = packageJson[section]
|
|
336
|
-
|
|
337
|
-
if (dependencyMap && typeof dependencyMap === 'object' && packageName in dependencyMap) {
|
|
338
|
-
return section
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
return null
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
export const updatePackageJson = (packageJson, version, exact) => {
|
|
346
|
-
const updates = []
|
|
347
|
-
|
|
348
|
-
for (const section of TARGET_SECTIONS) {
|
|
349
|
-
const dependencyMap = packageJson[section]
|
|
350
|
-
|
|
351
|
-
if (!dependencyMap || typeof dependencyMap !== 'object') {
|
|
352
|
-
continue
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
for (const [name, currentRange] of Object.entries(dependencyMap)) {
|
|
356
|
-
if (!isTargetPackage(name) || typeof currentRange !== 'string') {
|
|
357
|
-
continue
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
const nextRange = formatRange(currentRange, version, exact)
|
|
361
|
-
if (nextRange === currentRange) {
|
|
362
|
-
continue
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
dependencyMap[name] = nextRange
|
|
366
|
-
updates.push({
|
|
367
|
-
type: 'update',
|
|
368
|
-
section,
|
|
369
|
-
name,
|
|
370
|
-
currentRange,
|
|
371
|
-
nextRange,
|
|
372
|
-
})
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
return updates
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
export const resolveInstallPackages = (tokens) => {
|
|
380
|
-
const selectedPackages = []
|
|
381
|
-
const seen = new Set()
|
|
382
|
-
|
|
383
|
-
for (const token of tokens) {
|
|
384
|
-
const normalized = token.trim()
|
|
385
|
-
if (!normalized) {
|
|
386
|
-
continue
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
const numericIndex = Number(normalized)
|
|
390
|
-
const selectedPackage =
|
|
391
|
-
Number.isInteger(numericIndex) && numericIndex >= 1 && numericIndex <= INSTALLABLE_PACKAGES.length
|
|
392
|
-
? INSTALLABLE_PACKAGES[numericIndex - 1]
|
|
393
|
-
: INSTALLABLE_PACKAGES.find((entry) => entry.id === normalized || entry.name === normalized)
|
|
394
|
-
|
|
395
|
-
if (!selectedPackage) {
|
|
396
|
-
const supported = INSTALLABLE_PACKAGES
|
|
397
|
-
.map((entry, index) => `${index + 1}/${entry.id}/${entry.name}`)
|
|
398
|
-
.join(', ')
|
|
399
|
-
|
|
400
|
-
throw new Error(`Unknown add target "${normalized}". Supported values: ${supported}`)
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
if (seen.has(selectedPackage.name)) {
|
|
404
|
-
continue
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
seen.add(selectedPackage.name)
|
|
408
|
-
selectedPackages.push(selectedPackage)
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
return selectedPackages
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
export const installPackages = (packageJson, packages, version, exact) => {
|
|
415
|
-
const updates = []
|
|
416
|
-
|
|
417
|
-
for (const selectedPackage of packages) {
|
|
418
|
-
const section = findDependencySection(packageJson, selectedPackage.name) ?? selectedPackage.section
|
|
419
|
-
const dependencyMap = packageJson[section] ?? {}
|
|
420
|
-
|
|
421
|
-
if (!(section in packageJson)) {
|
|
422
|
-
packageJson[section] = dependencyMap
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
const currentRange = dependencyMap[selectedPackage.name]
|
|
426
|
-
const nextRange = typeof currentRange === 'string'
|
|
427
|
-
? formatRange(currentRange, version, exact)
|
|
428
|
-
: createRange(version, exact)
|
|
429
|
-
|
|
430
|
-
if (currentRange === nextRange) {
|
|
431
|
-
continue
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
dependencyMap[selectedPackage.name] = nextRange
|
|
435
|
-
updates.push({
|
|
436
|
-
type: typeof currentRange === 'string' ? 'update' : 'install',
|
|
437
|
-
section,
|
|
438
|
-
name: selectedPackage.name,
|
|
439
|
-
currentRange: typeof currentRange === 'string' ? currentRange : null,
|
|
440
|
-
nextRange,
|
|
441
|
-
})
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
return updates
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
export const promptForInstallSelection = async (packageJson) => {
|
|
448
|
-
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
449
|
-
throw new Error('Interactive add mode requires a TTY. Use --packages to select packages explicitly.')
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
console.log('Выберите пакеты для установки в текущий package.json:')
|
|
453
|
-
for (const [index, selectedPackage] of INSTALLABLE_PACKAGES.entries()) {
|
|
454
|
-
const currentSection = findDependencySection(packageJson, selectedPackage.name)
|
|
455
|
-
const installedHint = currentSection ? ` Уже есть в ${currentSection}.` : ''
|
|
456
|
-
|
|
457
|
-
console.log(` ${index + 1}. ${selectedPackage.name} (${selectedPackage.id})`)
|
|
458
|
-
console.log(` ${selectedPackage.description} Раздел по умолчанию: ${selectedPackage.section}.${installedHint}`)
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
const readline = createInterface({
|
|
462
|
-
input: process.stdin,
|
|
463
|
-
output: process.stdout,
|
|
464
|
-
})
|
|
465
|
-
|
|
466
|
-
try {
|
|
467
|
-
while (true) {
|
|
468
|
-
const answer = await readline.question(
|
|
469
|
-
'Введите номера, ids или имена пакетов через запятую (например: 1,3 или components,types): '
|
|
470
|
-
)
|
|
471
|
-
|
|
472
|
-
const tokens = parsePackageList(answer)
|
|
473
|
-
if (tokens.length === 0) {
|
|
474
|
-
return []
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
try {
|
|
478
|
-
return resolveInstallPackages(tokens)
|
|
479
|
-
} catch (error) {
|
|
480
|
-
const message = error instanceof Error ? error.message : String(error)
|
|
481
|
-
console.error(message)
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
} finally {
|
|
485
|
-
readline.close()
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
const readPackageJson = (packageJsonPath) => {
|
|
490
|
-
const source = fs.readFileSync(packageJsonPath, 'utf8')
|
|
491
|
-
|
|
492
|
-
return {
|
|
493
|
-
formatting: detectFormatting(source),
|
|
494
|
-
packageJson: JSON.parse(source),
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
const writePackageJson = (packageJsonPath, packageJson, formatting) => {
|
|
499
|
-
fs.writeFileSync(packageJsonPath, serializePackageJson(packageJson, formatting), 'utf8')
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
const printChanges = (changes) => {
|
|
503
|
-
for (const change of changes) {
|
|
504
|
-
const prefix = change.type === 'install'
|
|
505
|
-
? `${change.section}: ${change.name} -> ${change.nextRange}`
|
|
506
|
-
: `${change.section}: ${change.name} ${change.currentRange} -> ${change.nextRange}`
|
|
507
|
-
|
|
508
|
-
console.log(` ${prefix}`)
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
export const runUpdate = (options) => {
|
|
513
|
-
const version = options.version ?? resolveLatestVersion()
|
|
514
|
-
const packageJsonPaths = collectPackageJsonPaths(options.target)
|
|
515
|
-
const reports = []
|
|
516
|
-
|
|
517
|
-
for (const packageJsonPath of packageJsonPaths) {
|
|
518
|
-
const { formatting, packageJson } = readPackageJson(packageJsonPath)
|
|
519
|
-
const updates = updatePackageJson(packageJson, version, options.exact)
|
|
520
|
-
|
|
521
|
-
if (updates.length === 0) {
|
|
522
|
-
continue
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
if (!options.dryRun) {
|
|
526
|
-
writePackageJson(packageJsonPath, packageJson, formatting)
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
reports.push({ packageJsonPath, updates })
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
if (reports.length === 0) {
|
|
533
|
-
console.log(`No ${ROOT_PACKAGE}* dependencies found or changed under ${path.resolve(options.target)}`)
|
|
534
|
-
return
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
const totalUpdates = reports.reduce((sum, report) => sum + report.updates.length, 0)
|
|
538
|
-
|
|
539
|
-
console.log(`Resolved version: ${version}`)
|
|
540
|
-
for (const report of reports) {
|
|
541
|
-
console.log(report.packageJsonPath)
|
|
542
|
-
printChanges(report.updates)
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
if (options.dryRun) {
|
|
546
|
-
console.log('Dry run enabled, package.json files were not modified')
|
|
547
|
-
return
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
console.log(
|
|
551
|
-
`Updated ${totalUpdates} dependency entries in ${reports.length} package.json file(s) under ${path.resolve(options.target)}`
|
|
552
|
-
)
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
export const runAdd = async (options) => {
|
|
556
|
-
const version = options.version ?? resolveLatestVersion()
|
|
557
|
-
const packageJsonPath = resolvePackageJsonPath(path.resolve(options.target))
|
|
558
|
-
const { formatting, packageJson } = readPackageJson(packageJsonPath)
|
|
559
|
-
const selectedPackages = options.packages
|
|
560
|
-
? resolveInstallPackages(options.packages)
|
|
561
|
-
: await promptForInstallSelection(packageJson)
|
|
562
|
-
|
|
563
|
-
if (selectedPackages.length === 0) {
|
|
564
|
-
console.log('Nothing selected, package.json was not modified')
|
|
565
|
-
return
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
const updates = installPackages(packageJson, selectedPackages, version, options.exact)
|
|
569
|
-
|
|
570
|
-
if (updates.length === 0) {
|
|
571
|
-
console.log(`Selected packages are already installed with matching ranges in ${packageJsonPath}`)
|
|
572
|
-
return
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
console.log(`Resolved version: ${version}`)
|
|
576
|
-
console.log(packageJsonPath)
|
|
577
|
-
printChanges(updates)
|
|
578
|
-
|
|
579
|
-
if (options.dryRun) {
|
|
580
|
-
console.log('Dry run enabled, package.json was not modified')
|
|
581
|
-
return
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
writePackageJson(packageJsonPath, packageJson, formatting)
|
|
585
|
-
console.log(`Installed ${updates.length} package entries in ${packageJsonPath}`)
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
export const main = async (argv = process.argv.slice(2)) => {
|
|
589
|
-
const options = parseArgs(argv)
|
|
590
|
-
|
|
591
|
-
if (options.add) {
|
|
592
|
-
await runAdd(options)
|
|
593
|
-
return
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
runUpdate(options)
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
const isExecutedDirectly = () => {
|
|
600
|
-
const entryPath = process.argv[1]
|
|
601
|
-
|
|
602
|
-
if (!entryPath) {
|
|
603
|
-
return false
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
return pathToFileURL(path.resolve(entryPath)).href === import.meta.url
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
if (isExecutedDirectly()) {
|
|
610
|
-
try {
|
|
611
|
-
await main()
|
|
612
|
-
} catch (error) {
|
|
613
|
-
const message = error instanceof Error ? error.message : String(error)
|
|
614
|
-
console.error(message)
|
|
615
|
-
process.exit(1)
|
|
616
|
-
}
|
|
617
|
-
}
|