@lightnet/cli 4.8.0 โ†’ 4.8.2

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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # @lightnet/cli
2
2
 
3
+ ## 4.8.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#456](https://github.com/LightNetDev/LightNet/pull/456) [`2c49737`](https://github.com/LightNetDev/LightNet/commit/2c4973792aa695a2b19acc04744aca39bb7f868d) - Update dependencies.
8
+
9
+ ## 4.8.1
10
+
11
+ ### Patch Changes
12
+
13
+ - [#454](https://github.com/LightNetDev/LightNet/pull/454) [`5de5b93`](https://github.com/LightNetDev/LightNet/commit/5de5b931575a9e864c5acfdf991e0e9b2980030b) - Rename check-files scope `thumbnails` to `images`.
14
+
3
15
  ## 4.8.0
4
16
 
5
17
  ### Minor Changes
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "CLI for managing LightNet projects",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
- "version": "4.8.0",
6
+ "version": "4.8.2",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },
@@ -25,16 +25,16 @@
25
25
  "CHANGELOG.md"
26
26
  ],
27
27
  "dependencies": {
28
- "@clack/prompts": "^1.8.0",
28
+ "@clack/prompts": "^1.8.1",
29
29
  "commander": "^15.0.0"
30
30
  },
31
31
  "devDependencies": {
32
- "vitest": "^5.0.0"
32
+ "vitest": "^5.0.5"
33
33
  },
34
34
  "engines": {
35
35
  "node": ">=22"
36
36
  },
37
37
  "scripts": {
38
- "test": "vitest"
38
+ "test": "vitest run"
39
39
  }
40
40
  }
@@ -24,7 +24,7 @@ import {
24
24
  import { cancelPrompt } from "./support/prompt-cancel.js"
25
25
  import { createR2FileStorage } from "./support/r2.js"
26
26
 
27
- const supportedScopes = new Set(["content-files", "thumbnails"])
27
+ const supportedScopes = new Set(["content-files", "images"])
28
28
 
29
29
  const mediaDir = "src/content/media"
30
30
  const mediaImagesDir = "src/content/media/images"
@@ -83,7 +83,7 @@ export async function checkFiles(options, runtime = {}) {
83
83
 
84
84
  const scopes = parseScopes(options.scope)
85
85
  const includeContentFiles = scopes.has("content-files")
86
- const includeThumbnails = scopes.has("thumbnails")
86
+ const includeImages = scopes.has("images")
87
87
 
88
88
  intro("check-files")
89
89
 
@@ -102,9 +102,9 @@ export async function checkFiles(options, runtime = {}) {
102
102
  /** @type {string[]} */
103
103
  let orphanedContentFiles = []
104
104
  /** @type {string[]} */
105
- let orphanedMediaThumbnails = []
105
+ let orphanedMediaImages = []
106
106
  /** @type {string[]} */
107
- let orphanedCategoryThumbnails = []
107
+ let orphanedCategoryImages = []
108
108
  /** @type {string[]} */
109
109
  let removedItems = []
110
110
  /** @type {string[]} */
@@ -112,8 +112,8 @@ export async function checkFiles(options, runtime = {}) {
112
112
 
113
113
  /** @type {FileStorage|undefined} */
114
114
  let contentFileStorage = undefined
115
- const mediaThumbnailStorage = files(cwd, { rootDir: mediaImagesDir })
116
- const categoryThumbnailStorage = files(cwd, { rootDir: categoryImagesDir })
115
+ const mediaImageStorage = files(cwd, { rootDir: mediaImagesDir })
116
+ const categoryImageStorage = files(cwd, { rootDir: categoryImagesDir })
117
117
 
118
118
  if (includeContentFiles) {
119
119
  contentFileStorage = options.r2
@@ -153,7 +153,7 @@ export async function checkFiles(options, runtime = {}) {
153
153
  orphanedContentFiles = r2Result.orphanedFiles
154
154
  if (r2Result.referenceCount === 0) {
155
155
  warnings.push(
156
- 'No R2-backed content file references found. Use "--scope=thumbnails" or check your "--r2" setup.',
156
+ 'No R2-backed content file references found. Use "--scope=images" or check your "--r2" setup.',
157
157
  )
158
158
  }
159
159
  } else {
@@ -177,21 +177,21 @@ export async function checkFiles(options, runtime = {}) {
177
177
  }
178
178
  }
179
179
 
180
- if (includeThumbnails) {
181
- const thumbnailsResult = await runSpinner({
182
- error: "Thumbnail check failed.",
183
- start: "Checking thumbnails",
184
- stop: (result) => formatThumbnailCheckSummary(result),
180
+ if (includeImages) {
181
+ const imagesResult = await runSpinner({
182
+ error: "Image check failed.",
183
+ start: "Checking images",
184
+ stop: (result) => formatImageCheckSummary(result),
185
185
  task: () =>
186
- validateThumbnails(
186
+ validateImages(
187
187
  mediaItems,
188
188
  categories,
189
- mediaThumbnailStorage,
190
- categoryThumbnailStorage,
189
+ mediaImageStorage,
190
+ categoryImageStorage,
191
191
  ),
192
192
  })
193
- orphanedMediaThumbnails = thumbnailsResult.orphanedMediaThumbnails
194
- orphanedCategoryThumbnails = thumbnailsResult.orphanedCategoryThumbnails
193
+ orphanedMediaImages = imagesResult.orphanedMediaImages
194
+ orphanedCategoryImages = imagesResult.orphanedCategoryImages
195
195
  }
196
196
 
197
197
  if (options.fix || options.fixWithoutConfirm) {
@@ -212,7 +212,7 @@ export async function checkFiles(options, runtime = {}) {
212
212
  contentDeletions.push(deletion)
213
213
  deletions.push(deletion)
214
214
  }
215
- for (const filePath of orphanedMediaThumbnails) {
215
+ for (const filePath of orphanedMediaImages) {
216
216
  const deletion = {
217
217
  displayPath: filePath,
218
218
  target: filePath,
@@ -220,7 +220,7 @@ export async function checkFiles(options, runtime = {}) {
220
220
  localDeletions.push(deletion)
221
221
  deletions.push(deletion)
222
222
  }
223
- for (const filePath of orphanedCategoryThumbnails) {
223
+ for (const filePath of orphanedCategoryImages) {
224
224
  const deletion = {
225
225
  displayPath: filePath,
226
226
  target: filePath,
@@ -257,22 +257,22 @@ export async function checkFiles(options, runtime = {}) {
257
257
  task: async () => {
258
258
  const [
259
259
  deletedContentTargets,
260
- deletedMediaThumbnailTargets,
261
- deletedCategoryThumbnailTargets,
260
+ deletedMediaImageTargets,
261
+ deletedCategoryImageTargets,
262
262
  ] = await Promise.all([
263
263
  contentFileStorage
264
264
  ? contentFileStorage.delete(
265
265
  contentDeletions.map((deletion) => deletion.target),
266
266
  )
267
267
  : [],
268
- mediaThumbnailStorage.delete(
268
+ mediaImageStorage.delete(
269
269
  localDeletions
270
270
  .filter((deletion) =>
271
271
  deletion.target.startsWith(mediaImagesDir),
272
272
  )
273
273
  .map((deletion) => deletion.target),
274
274
  ),
275
- categoryThumbnailStorage.delete(
275
+ categoryImageStorage.delete(
276
276
  localDeletions
277
277
  .filter((deletion) =>
278
278
  deletion.target.startsWith(categoryImagesDir),
@@ -283,8 +283,8 @@ export async function checkFiles(options, runtime = {}) {
283
283
  return {
284
284
  deletedContentTargets,
285
285
  deletedLocalTargets: [
286
- ...deletedMediaThumbnailTargets,
287
- ...deletedCategoryThumbnailTargets,
286
+ ...deletedMediaImageTargets,
287
+ ...deletedCategoryImageTargets,
288
288
  ],
289
289
  }
290
290
  },
@@ -304,10 +304,10 @@ export async function checkFiles(options, runtime = {}) {
304
304
  orphanedContentFiles = orphanedContentFiles.filter(
305
305
  (item) => !deletedTargets.has(item),
306
306
  )
307
- orphanedMediaThumbnails = orphanedMediaThumbnails.filter(
307
+ orphanedMediaImages = orphanedMediaImages.filter(
308
308
  (item) => !deletedTargets.has(item),
309
309
  )
310
- orphanedCategoryThumbnails = orphanedCategoryThumbnails.filter(
310
+ orphanedCategoryImages = orphanedCategoryImages.filter(
311
311
  (item) => !deletedTargets.has(item),
312
312
  )
313
313
  }
@@ -318,8 +318,8 @@ export async function checkFiles(options, runtime = {}) {
318
318
  missingContentFiles.length > 0 ||
319
319
  wrongTypeR2ContentFiles.length > 0 ||
320
320
  orphanedContentFiles.length > 0 ||
321
- orphanedMediaThumbnails.length > 0 ||
322
- orphanedCategoryThumbnails.length > 0
321
+ orphanedMediaImages.length > 0 ||
322
+ orphanedCategoryImages.length > 0
323
323
 
324
324
  for (const warning of warnings) {
325
325
  log.warn(warning)
@@ -344,8 +344,8 @@ export async function checkFiles(options, runtime = {}) {
344
344
  formatContentFilePath(filePath, options),
345
345
  ),
346
346
  )
347
- printSection("Orphaned media thumbnails", orphanedMediaThumbnails)
348
- printSection("Orphaned category thumbnails", orphanedCategoryThumbnails)
347
+ printSection("Orphaned media images", orphanedMediaImages)
348
+ printSection("Orphaned category images", orphanedCategoryImages)
349
349
  printSection("Removed items", removedItems)
350
350
 
351
351
  outro(hasIssues ? "Issues found. ๐Ÿšง" : "Cleanup complete. ๐Ÿงน")
@@ -458,17 +458,16 @@ function formatContentCheckSummary(result) {
458
458
  /**
459
459
  * @param {{
460
460
  * fileCount: number
461
- * orphanedCategoryThumbnails: string[]
462
- * orphanedMediaThumbnails: string[]
461
+ * orphanedCategoryImages: string[]
462
+ * orphanedMediaImages: string[]
463
463
  * referenceCount: number
464
464
  * }} result
465
465
  */
466
- function formatThumbnailCheckSummary(result) {
467
- const orphanedThumbnails =
468
- result.orphanedMediaThumbnails.length +
469
- result.orphanedCategoryThumbnails.length
466
+ function formatImageCheckSummary(result) {
467
+ const orphanedImages =
468
+ result.orphanedMediaImages.length + result.orphanedCategoryImages.length
470
469
 
471
- return `Thumbnails: ${formatCount(result.referenceCount, "reference")}, ${formatCount(result.fileCount, "file")}; orphaned: ${orphanedThumbnails} (${result.orphanedMediaThumbnails.length} media, ${result.orphanedCategoryThumbnails.length} categories).`
470
+ return `Images: ${formatCount(result.referenceCount, "reference")}, ${formatCount(result.fileCount, "file")}; orphaned: ${orphanedImages} (${result.orphanedMediaImages.length} media, ${result.orphanedCategoryImages.length} categories).`
472
471
  }
473
472
 
474
473
  /**
@@ -502,7 +501,7 @@ function formatDeletionProgress(action, count) {
502
501
  * @param {string|undefined} rawScope
503
502
  */
504
503
  function parseScopes(rawScope) {
505
- const values = (rawScope ?? "content-files,thumbnails")
504
+ const values = (rawScope ?? "content-files,images")
506
505
  .split(",")
507
506
  .map((value) => value.trim())
508
507
  .filter(Boolean)
@@ -510,7 +509,7 @@ function parseScopes(rawScope) {
510
509
  if (values.length === 0) {
511
510
  throw new CliError(
512
511
  // intentionally kept as a CLI-facing validation error
513
- 'Expected "--scope" to include at least one of "content-files" or "thumbnails".',
512
+ 'Expected "--scope" to include at least one of "content-files" or "images".',
514
513
  )
515
514
  }
516
515
 
@@ -518,7 +517,7 @@ function parseScopes(rawScope) {
518
517
  for (const scope of scopes) {
519
518
  if (!supportedScopes.has(scope)) {
520
519
  throw new CliError(
521
- `Unsupported scope "${scope}". Allowed values: content-files, thumbnails.`,
520
+ `Unsupported scope "${scope}". Allowed values: content-files, images.`,
522
521
  )
523
522
  }
524
523
  }
@@ -540,31 +539,28 @@ async function assertLightNetSiteRoot(cwd) {
540
539
  /**
541
540
  * @param {MediaItem[]} mediaItems
542
541
  * @param {Category[]} categories
543
- * @param {FileStorage} mediaThumbnailStorage
544
- * @param {FileStorage} categoryThumbnailStorage
542
+ * @param {FileStorage} mediaImageStorage
543
+ * @param {FileStorage} categoryImageStorage
545
544
  */
546
- async function validateThumbnails(
545
+ async function validateImages(
547
546
  mediaItems,
548
547
  categories,
549
- mediaThumbnailStorage,
550
- categoryThumbnailStorage,
548
+ mediaImageStorage,
549
+ categoryImageStorage,
551
550
  ) {
552
551
  const mediaReferences = new Set(
553
552
  mediaItems
554
- .map((item) => toThumbnailPath("media", item.image))
553
+ .map((item) => toImagePath("media", item.image))
555
554
  .filter((value) => value !== undefined),
556
555
  )
557
556
  const categoryReferences = new Set(
558
557
  categories
559
- .map((item) => toThumbnailPath("categories", item.image))
558
+ .map((item) => toImagePath("categories", item.image))
560
559
  .filter((value) => value !== undefined),
561
560
  )
562
561
 
563
562
  const [initializedMediaStorage, initializedCategoryStorage] =
564
- await Promise.all([
565
- mediaThumbnailStorage.init(),
566
- categoryThumbnailStorage.init(),
567
- ])
563
+ await Promise.all([mediaImageStorage.init(), categoryImageStorage.init()])
568
564
  const [mediaFiles, categoryFiles] = await Promise.all([
569
565
  initializedMediaStorage.list(),
570
566
  initializedCategoryStorage.list(),
@@ -572,10 +568,10 @@ async function validateThumbnails(
572
568
 
573
569
  return {
574
570
  fileCount: mediaFiles.length + categoryFiles.length,
575
- orphanedMediaThumbnails: mediaFiles.filter(
571
+ orphanedMediaImages: mediaFiles.filter(
576
572
  (file) => !mediaReferences.has(file),
577
573
  ),
578
- orphanedCategoryThumbnails: categoryFiles.filter(
574
+ orphanedCategoryImages: categoryFiles.filter(
579
575
  (file) => !categoryReferences.has(file),
580
576
  ),
581
577
  referenceCount: mediaReferences.size + categoryReferences.size,
@@ -700,7 +696,7 @@ function addFileReference(references, filePath, displayPath, sourceFileName) {
700
696
  * @param {"media"|"categories"} kind
701
697
  * @param {string|undefined} image
702
698
  */
703
- function toThumbnailPath(kind, image) {
699
+ function toImagePath(kind, image) {
704
700
  if (typeof image !== "string") {
705
701
  return undefined
706
702
  }
package/src/index.js CHANGED
@@ -37,7 +37,7 @@ program
37
37
  program
38
38
  .command("check-files")
39
39
  .description(
40
- "check for missing and orphaned content files and thumbnails in a LightNet site",
40
+ "check for missing and orphaned content files and images in a LightNet site",
41
41
  )
42
42
  .option("--fix", "remove orphaned files")
43
43
  .option("--fix-without-confirm", "remove orphaned files without confirmation")
@@ -45,10 +45,7 @@ program
45
45
  "--r2",
46
46
  "validate remote content files in Cloudflare R2 instead of public/files",
47
47
  )
48
- .option(
49
- "--scope <values>",
50
- "comma-separated scopes: content-files,thumbnails",
51
- )
48
+ .option("--scope <values>", "comma-separated scopes: content-files,images")
52
49
  .action(async (options) => {
53
50
  try {
54
51
  const checkSuccessful = await checkFiles(options)