@newlogic-digital/cli 1.5.0-next.4 → 1.5.0-next.5
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/index.mjs +2 -1
- package/package.json +1 -1
- package/src/commands/blocks/index.mjs +2 -1
- package/src/commands/blocks/service.mjs +79 -25
package/index.mjs
CHANGED
|
@@ -150,11 +150,12 @@ if (!command) {
|
|
|
150
150
|
|
|
151
151
|
-- blocks --
|
|
152
152
|
${styleText('green', 'newlogic blocks list')} - Lists all available installable blocks with descriptions
|
|
153
|
-
${styleText('green', 'newlogic blocks add')} ${styleText('yellow', '<name...>')} - Installs one or more blocks by kebab-case or PascalCase name
|
|
153
|
+
${styleText('green', 'newlogic blocks add')} ${styleText('yellow', '<name[@variant]...>')} - Installs one or more blocks by kebab-case or PascalCase name
|
|
154
154
|
${styleText('green', 'newlogic blocks remove')} ${styleText('yellow', '<name...>')} - Removes one or more blocks and orphaned dependencies
|
|
155
155
|
${styleText('green', 'newlogic blocks update')} - Reinstalls all configured blocks from ${styleText('yellow', 'newlogic.config.json')}
|
|
156
156
|
${styleText('green', 'newlogic blocks add')} ${styleText('yellow', 'about-accordion')}
|
|
157
157
|
${styleText('green', 'newlogic blocks add')} ${styleText('yellow', 'AboutAccordion')}
|
|
158
|
+
${styleText('green', 'newlogic blocks add')} ${styleText('yellow', 'header-nav-left@stimulus')}
|
|
158
159
|
${styleText('green', 'newlogic blocks add')} ${styleText('yellow', 'header-nav-left contact-info-card hero-floating-text')}
|
|
159
160
|
${styleText('green', 'newlogic blocks remove')} ${styleText('yellow', 'about-accordion')}
|
|
160
161
|
${styleText('green', 'newlogic blocks remove')} ${styleText('yellow', 'header-nav-left hero-floating-text')}
|
package/package.json
CHANGED
|
@@ -134,13 +134,14 @@ function printBlocksUsage() {
|
|
|
134
134
|
styleText(['white', 'bold'], 'Usage:'),
|
|
135
135
|
'',
|
|
136
136
|
` ${styleText('green', 'newlogic blocks list')} - Lists all available blocks with descriptions`,
|
|
137
|
-
` ${styleText('green', 'newlogic blocks add')} ${styleText('yellow', '<name...>')} - Adds one or more blocks by kebab-case or PascalCase name`,
|
|
137
|
+
` ${styleText('green', 'newlogic blocks add')} ${styleText('yellow', '<name[@variant]...>')} - Adds one or more blocks by kebab-case or PascalCase name`,
|
|
138
138
|
` ${styleText('green', 'newlogic blocks remove')} ${styleText('yellow', '<name...>')} - Removes one or more blocks and orphaned dependencies`,
|
|
139
139
|
` ${styleText('green', 'newlogic blocks update')} - Reinstalls all configured blocks from ${styleText('yellow', 'newlogic.config.json')}`,
|
|
140
140
|
'',
|
|
141
141
|
styleText(['white', 'bold'], 'Examples:'),
|
|
142
142
|
'',
|
|
143
143
|
` ${styleText('green', 'newlogic blocks add')} ${styleText('yellow', 'header-nav-left contact-info-card hero-floating-text')}`,
|
|
144
|
+
` ${styleText('green', 'newlogic blocks add')} ${styleText('yellow', 'header-nav-left@stimulus')}`,
|
|
144
145
|
` ${styleText('green', 'newlogic blocks remove')} ${styleText('yellow', 'header-nav-left hero-floating-text')}`,
|
|
145
146
|
].join('\n'))
|
|
146
147
|
}
|
|
@@ -83,6 +83,51 @@ function assertBlockName(name, label = 'block name') {
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
function parseBlockSpecifier(rawValue, {
|
|
87
|
+
label = 'block name',
|
|
88
|
+
allowObject = false,
|
|
89
|
+
} = {}) {
|
|
90
|
+
if (allowObject && rawValue && typeof rawValue === 'object' && !Array.isArray(rawValue)) {
|
|
91
|
+
const name = normalizeBlockName(rawValue.name)
|
|
92
|
+
const variant = rawValue.variant == null ? '' : `${rawValue.variant}`.trim()
|
|
93
|
+
|
|
94
|
+
assertBlockName(name, 'configured block name')
|
|
95
|
+
|
|
96
|
+
if (rawValue.variant != null && !variant) {
|
|
97
|
+
throw new Error(`Configured block "${name}" has an empty variant`)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
name,
|
|
102
|
+
variant: variant || undefined,
|
|
103
|
+
variantExplicit: rawValue.variant != null,
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const value = `${rawValue ?? ''}`.trim()
|
|
108
|
+
|
|
109
|
+
if (!value) {
|
|
110
|
+
throw new Error(`Missing ${label}`)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const variantSeparator = value.indexOf('@')
|
|
114
|
+
const rawName = variantSeparator === -1 ? value : value.slice(0, variantSeparator)
|
|
115
|
+
const rawVariant = variantSeparator === -1 ? '' : value.slice(variantSeparator + 1).trim()
|
|
116
|
+
const name = normalizeBlockName(rawName)
|
|
117
|
+
|
|
118
|
+
assertBlockName(name, label)
|
|
119
|
+
|
|
120
|
+
if (variantSeparator !== -1 && !rawVariant) {
|
|
121
|
+
throw new Error(`Invalid ${label}: "${value}"`)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
name,
|
|
126
|
+
variant: rawVariant || undefined,
|
|
127
|
+
variantExplicit: variantSeparator !== -1,
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
86
131
|
function toBlockKey(block) {
|
|
87
132
|
return `${block.name}@${block.variant}`
|
|
88
133
|
}
|
|
@@ -151,20 +196,14 @@ function loadProjectConfig(projectRoot) {
|
|
|
151
196
|
}
|
|
152
197
|
|
|
153
198
|
const blocks = blocksRaw.map((entry, index) => {
|
|
154
|
-
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
|
|
199
|
+
if (typeof entry !== 'string' && (!entry || typeof entry !== 'object' || Array.isArray(entry))) {
|
|
155
200
|
throw new Error(`Invalid block config entry at index ${index}`)
|
|
156
201
|
}
|
|
157
202
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (!variant) {
|
|
164
|
-
throw new Error(`Configured block "${name}" is missing a variant`)
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return { name, variant }
|
|
203
|
+
return parseBlockSpecifier(entry, {
|
|
204
|
+
label: `block config entry at index ${index}`,
|
|
205
|
+
allowObject: true,
|
|
206
|
+
})
|
|
168
207
|
})
|
|
169
208
|
|
|
170
209
|
return { configPath, config, blocks: dedupeExplicitBlocks(blocks) }
|
|
@@ -173,7 +212,7 @@ function loadProjectConfig(projectRoot) {
|
|
|
173
212
|
function saveProjectConfig(configPath, config, blocks) {
|
|
174
213
|
const nextConfig = {
|
|
175
214
|
...config,
|
|
176
|
-
blocks,
|
|
215
|
+
blocks: blocks.map(block => block.variantExplicit ? `${block.name}@${block.variant}` : block.name),
|
|
177
216
|
}
|
|
178
217
|
|
|
179
218
|
fs.writeFileSync(configPath, `${JSON.stringify(nextConfig, null, 2)}\n`)
|
|
@@ -194,15 +233,25 @@ function normalizeRequestedBlockNames(rawNames, label = 'block name') {
|
|
|
194
233
|
throw new Error(`Missing ${label}`)
|
|
195
234
|
}
|
|
196
235
|
|
|
197
|
-
const normalizedNames = rawNames
|
|
198
|
-
|
|
236
|
+
const normalizedNames = rawNames
|
|
237
|
+
.map(rawName => parseBlockSpecifier(rawName, { label }).name)
|
|
199
238
|
|
|
200
|
-
|
|
239
|
+
return [...new Set(normalizedNames)]
|
|
240
|
+
}
|
|
201
241
|
|
|
202
|
-
|
|
203
|
-
|
|
242
|
+
function normalizeRequestedBlocks(rawNames, label = 'block name') {
|
|
243
|
+
if (!Array.isArray(rawNames) || rawNames.length === 0) {
|
|
244
|
+
throw new Error(`Missing ${label}`)
|
|
245
|
+
}
|
|
204
246
|
|
|
205
|
-
|
|
247
|
+
const blocks = rawNames.map(rawName => parseBlockSpecifier(rawName, { label }))
|
|
248
|
+
const byName = new Map()
|
|
249
|
+
|
|
250
|
+
for (const block of blocks) {
|
|
251
|
+
byName.set(block.name, block)
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return [...byName.values()]
|
|
206
255
|
}
|
|
207
256
|
|
|
208
257
|
async function createMetaValidator(repository) {
|
|
@@ -488,16 +537,21 @@ export function createBlocksService({
|
|
|
488
537
|
}
|
|
489
538
|
|
|
490
539
|
async function addBlocks(rawNames) {
|
|
491
|
-
const
|
|
540
|
+
const requestedBlocks = normalizeRequestedBlocks(rawNames)
|
|
492
541
|
const rootBlocks = []
|
|
493
542
|
|
|
494
|
-
for (const
|
|
495
|
-
const meta = await getMeta(name)
|
|
543
|
+
for (const requestedBlock of requestedBlocks) {
|
|
544
|
+
const meta = await getMeta(requestedBlock.name)
|
|
496
545
|
|
|
497
546
|
rootBlocks.push({
|
|
498
|
-
name,
|
|
499
|
-
variant:
|
|
547
|
+
name: requestedBlock.name,
|
|
548
|
+
variant: requestedBlock.variant,
|
|
549
|
+
variantExplicit: requestedBlock.variantExplicit,
|
|
500
550
|
})
|
|
551
|
+
|
|
552
|
+
if (requestedBlock.variant && !meta.install?.variants?.[requestedBlock.variant]) {
|
|
553
|
+
throw new Error(`Variant "${requestedBlock.variant}" is not available for block "${requestedBlock.name}"`)
|
|
554
|
+
}
|
|
501
555
|
}
|
|
502
556
|
|
|
503
557
|
const plan = await resolveInstallPlan(rootBlocks)
|
|
@@ -506,12 +560,12 @@ export function createBlocksService({
|
|
|
506
560
|
|
|
507
561
|
const { configPath, config, blocks } = loadProjectConfig(projectRoot)
|
|
508
562
|
const nextBlocks = dedupeExplicitBlocks([
|
|
509
|
-
...blocks.filter(block => !
|
|
563
|
+
...blocks.filter(block => !requestedBlocks.some(requestedBlock => requestedBlock.name === block.name)),
|
|
510
564
|
...rootBlocks,
|
|
511
565
|
])
|
|
512
566
|
|
|
513
567
|
saveProjectConfig(configPath, config, nextBlocks)
|
|
514
|
-
logger.info(`added ${rootBlocks.map(block => `${block.name}@${block.variant}`).join(', ')}`)
|
|
568
|
+
logger.info(`added ${rootBlocks.map(block => block.variantExplicit ? `${block.name}@${block.variant}` : block.name).join(', ')}`)
|
|
515
569
|
|
|
516
570
|
return {
|
|
517
571
|
blocks: rootBlocks,
|