@antora/ui-loader 3.0.3 → 3.1.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/lib/load-ui.js CHANGED
@@ -1,7 +1,6 @@
1
1
  'use strict'
2
2
 
3
3
  const { compile: bracesToGroup } = require('braces')
4
- const camelCaseKeys = require('camelcase-keys')
5
4
  const { createHash } = require('crypto')
6
5
  const expandPath = require('@antora/expand-path-helper')
7
6
  const { File, MemoryFile, ReadableFile } = require('./file')
@@ -112,12 +111,12 @@ async function loadUi (playbook) {
112
111
  .on('error', reject)
113
112
  .pipe(collectFiles(resolve))
114
113
  ).catch((err) => {
115
- const wrapped = new Error(
114
+ const errWrapper = new Error(
116
115
  `Failed to read UI ${bundleFile.isDirectory() ? 'directory' : 'bundle'}: ` +
117
116
  (bundleUrl === bundleFile.path ? bundleUrl : `${bundleFile.path} (resolved from url: ${bundleUrl})`)
118
117
  )
119
- wrapped.stack += '\nCaused by: ' + (err.stack || 'unknown')
120
- throw wrapped
118
+ errWrapper.stack += `\nCaused by: ${err.stack || 'unknown'}`
119
+ throw errWrapper
121
120
  })
122
121
  ),
123
122
  srcSupplementalFiles(supplementalFilesSpec, startDir),
@@ -194,9 +193,9 @@ function downloadBundle (url, to, agent) {
194
193
  )
195
194
  })
196
195
  }).catch((err) => {
197
- const wrapped = new Error(`${err.summary || 'Failed to download UI bundle'}: ${url}`)
198
- wrapped.stack += '\nCaused by: ' + (err.stack || 'unknown')
199
- throw wrapped
196
+ const errWrapper = new Error(`${err.summary || 'Failed to download UI bundle'}: ${url}`)
197
+ errWrapper.stack += `\nCaused by: ${err.stack || 'unknown'}`
198
+ throw errWrapper
200
199
  })
201
200
  }
202
201
 
@@ -257,40 +256,44 @@ function collectFiles (resolve, files = new Map()) {
257
256
  }
258
257
 
259
258
  function srcSupplementalFiles (filesSpec, startDir) {
260
- if (!filesSpec) {
261
- return new Map()
262
- } else if (Array.isArray(filesSpec)) {
263
- return Promise.all(
264
- filesSpec.reduce((accum, { path: path_, contents: contents_ }) => {
265
- if (!path_) {
266
- return accum
267
- } else if (contents_) {
268
- if (~contents_.indexOf('\n') || !EXT_RX.test(contents_)) {
269
- accum.push(new MemoryFile({ path: path_, contents: Buffer.from(contents_) }))
259
+ if (!filesSpec) return new Map()
260
+ let cwd
261
+ return (
262
+ Array.isArray(filesSpec)
263
+ ? Promise.all(
264
+ filesSpec.reduce((accum, { path: path_, contents: contents_ }) => {
265
+ if (!path_) {
266
+ return accum
267
+ } else if (contents_) {
268
+ if (~contents_.indexOf('\n') || !EXT_RX.test(contents_)) {
269
+ accum.push(new MemoryFile({ path: path_, contents: Buffer.from(contents_) }))
270
+ } else {
271
+ contents_ = expandPath(contents_, { dot: startDir })
272
+ accum.push(
273
+ fsp
274
+ .stat(contents_)
275
+ .then((stat) =>
276
+ fsp.readFile(contents_).then((contents) => new File({ path: path_, contents, stat }))
277
+ )
278
+ )
279
+ }
270
280
  } else {
271
- contents_ = expandPath(contents_, { dot: startDir })
272
- accum.push(
273
- fsp
274
- .stat(contents_)
275
- .then((stat) => fsp.readFile(contents_).then((contents) => new File({ path: path_, contents, stat })))
276
- )
281
+ accum.push(new MemoryFile({ path: path_ }))
277
282
  }
278
- } else {
279
- accum.push(new MemoryFile({ path: path_ }))
280
- }
281
- return accum
282
- }, [])
283
- ).then((files) => files.reduce((accum, file) => accum.set(file.path, file) && accum, new Map()))
284
- } else {
285
- const cwd = expandPath(filesSpec, { dot: startDir })
286
- return fsp.access(cwd).then(
287
- () => srcFs(cwd),
288
- (err) => {
289
- // Q: should we skip unreadable files?
290
- throw Object.assign(err, { message: `problem encountered while reading ui.supplemental_files: ${err.message}` })
291
- }
292
- )
293
- }
283
+ return accum
284
+ }, [])
285
+ ).then((files) => files.reduce((accum, file) => accum.set(file.path, file) && accum, new Map()))
286
+ : fsp.access((cwd = expandPath(filesSpec, { dot: startDir }))).then(() => srcFs(cwd))
287
+ ).catch((err) => {
288
+ const dir = cwd ? filesSpec + (filesSpec === cwd ? '' : ` (resolved to ${cwd})`) : undefined
289
+ if (err.code === 'ENOENT' && err.path === cwd) {
290
+ throw new Error(`Specified ui.supplemental_files directory does not exist: ${dir}`)
291
+ } else {
292
+ const errWrapper = new Error(`Failed to read ui.supplemental_files ${cwd ? `directory: ${dir}` : 'entry'}`)
293
+ errWrapper.stack += `\nCaused by: ${err.stack || 'unknown'}`
294
+ throw errWrapper
295
+ }
296
+ })
294
297
  }
295
298
 
296
299
  function mergeFiles (files, supplementalFiles) {
@@ -302,7 +305,7 @@ function loadConfig (files, outputDir) {
302
305
  const configFile = files.get(UI_DESC_FILENAME)
303
306
  if (configFile) {
304
307
  files.delete(UI_DESC_FILENAME)
305
- const config = camelCaseKeys(yaml.load(configFile.contents.toString()), { deep: true })
308
+ const config = camelCaseKeys(yaml.load(configFile.contents.toString()))
306
309
  const staticFiles = config.staticFiles
307
310
  if (staticFiles && staticFiles.length) config.isStaticFile = picomatch(staticFiles, STATIC_FILE_MATCHER_OPTS)
308
311
  if (outputDir !== undefined) config.outputDir = outputDir
@@ -312,6 +315,16 @@ function loadConfig (files, outputDir) {
312
315
  }
313
316
  }
314
317
 
318
+ function camelCaseKeys (o) {
319
+ if (Array.isArray(o)) return o.map(camelCaseKeys)
320
+ if (o == null || o.constructor !== Object) return o
321
+ const accum = {}
322
+ for (const [k, v] of Object.entries(o)) {
323
+ accum[k.toLowerCase().replace(/[_-]([a-z0-9])/g, (_, l, idx) => (idx ? l.toUpperCase() : l))] = camelCaseKeys(v)
324
+ }
325
+ return accum
326
+ }
327
+
315
328
  function classifyFile (file, config) {
316
329
  if (config.isStaticFile && config.isStaticFile(file.path)) {
317
330
  file.type = 'static'
@@ -363,15 +376,14 @@ function srcFs (cwd) {
363
376
  )
364
377
  },
365
378
  (statErr) => {
366
- if (statErr.symlink) {
367
- statErr.message =
368
- statErr.code === 'ELOOP'
369
- ? `Symbolic link cycle detected at ${relpath}`
370
- : `Broken symbolic link detected at ${relpath}`
371
- } else {
372
- statErr.message = statErr.message.replace(`'${abspath}'`, relpath)
373
- }
374
- done(statErr)
379
+ done(
380
+ Object.assign(statErr, {
381
+ message: statErr.symlink
382
+ ? (statErr.code === 'ELOOP' ? 'ELOOP: symbolic link cycle, ' : 'ENOENT: broken symbolic link, ') +
383
+ `${relpath} -> ${statErr.symlink}`
384
+ : statErr.message.replace(`'${abspath}'`, relpath),
385
+ })
386
+ )
375
387
  }
376
388
  )
377
389
  }),
@@ -383,9 +395,14 @@ function srcFs (cwd) {
383
395
  function symlinkAwareStat (path_) {
384
396
  return fsp.lstat(path_).then((lstat) => {
385
397
  if (!lstat.isSymbolicLink()) return lstat
386
- return fsp.stat(path_).catch((statErr) => {
387
- throw Object.assign(statErr, { symlink: true })
388
- })
398
+ return fsp.stat(path_).catch((statErr) =>
399
+ fsp
400
+ .readlink(path_)
401
+ .catch(() => undefined)
402
+ .then((symlink) => {
403
+ throw Object.assign(statErr, { symlink })
404
+ })
405
+ )
389
406
  })
390
407
  }
391
408
 
package/lib/ui-catalog.js CHANGED
@@ -26,6 +26,11 @@ class UiCatalog {
26
26
  return file
27
27
  }
28
28
 
29
+ removeFile (file) {
30
+ const filesForType = this[$files].get(file.type)
31
+ return filesForType ? filesForType.delete(file.path) : false
32
+ }
33
+
29
34
  findByType (type) {
30
35
  const filesForType = this[$files].get(type)
31
36
  return filesForType ? [...filesForType.values()] : []
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antora/ui-loader",
3
- "version": "3.0.3",
3
+ "version": "3.1.0",
4
4
  "description": "Downloads a UI bundle, if necessary, and loads the files into a UI catalog for use in an Antora documentation pipeline.",
5
5
  "license": "MPL-2.0",
6
6
  "author": "OpenDevise Inc. (https://opendevise.com)",
@@ -16,14 +16,21 @@
16
16
  "url": "https://gitlab.com/antora/antora/issues"
17
17
  },
18
18
  "main": "lib/index.js",
19
+ "exports": {
20
+ ".": "./lib/index.js",
21
+ "./ui-catalog": "./lib/ui-catalog.js",
22
+ "./package.json": "./package.json"
23
+ },
24
+ "imports": {
25
+ "#constants": "./lib/constants.js"
26
+ },
19
27
  "dependencies": {
20
28
  "@antora/expand-path-helper": "~2.0",
21
29
  "braces": "~3.0",
22
30
  "cache-directory": "~2.0",
23
- "camelcase-keys": "~7.0",
24
31
  "glob-stream": "~7.0",
25
32
  "gulp-vinyl-zip": "~2.5",
26
- "hpagent": "~0.1.0",
33
+ "hpagent": "~1.0",
27
34
  "js-yaml": "~4.1",
28
35
  "picomatch": "~2.3",
29
36
  "should-proxy": "~1.0",
@@ -31,7 +38,7 @@
31
38
  "vinyl": "~2.2"
32
39
  },
33
40
  "engines": {
34
- "node": ">=12.21.0"
41
+ "node": ">=16.0.0"
35
42
  },
36
43
  "files": [
37
44
  "lib/"