@antora/ui-loader 3.0.3 → 3.1.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/lib/constants.js CHANGED
@@ -12,6 +12,5 @@ module.exports = Object.freeze({
12
12
  nosort: true,
13
13
  nounique: true,
14
14
  strict: false,
15
- uniqueBy: (m) => m,
16
15
  },
17
16
  })
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'
@@ -340,21 +353,20 @@ function resolveOut (file, outputDir = '_') {
340
353
  }
341
354
 
342
355
  function srcFs (cwd) {
343
- const relpathStart = cwd.length + 1
344
- return new Promise((resolve, reject, cache = Object.create(null), files = new Map()) =>
356
+ return new Promise((resolve, reject, cache = Object.create(null), files = new Map(), relpathStart = cwd.length + 1) =>
345
357
  pipeline(
346
358
  globStream(UI_SRC_GLOB, Object.assign({ cache, cwd }, UI_SRC_OPTS)),
347
359
  forEach(({ path: abspathPosix }, _, done) => {
348
- if (Array.isArray(cache[abspathPosix])) return done() // detects some directories, but not all
360
+ if ((cache[abspathPosix] || {}).constructor === Array) return done() // detects some directories
349
361
  const abspath = posixify ? ospath.normalize(abspathPosix) : abspathPosix
350
362
  const relpath = abspath.substr(relpathStart)
351
363
  symlinkAwareStat(abspath).then(
352
364
  (stat) => {
353
- if (stat.isDirectory()) return done() // detects remaining directories
365
+ if (stat.isDirectory()) return done() // detects directories that slipped through cache check
366
+ const relpathPosix = posixify ? posixify(relpath) : relpath
354
367
  fsp.readFile(abspath).then(
355
368
  (contents) => {
356
- const path_ = posixify ? posixify(relpath) : relpath
357
- files.set(path_, new File({ cwd, path: path_, contents, stat, local: true }))
369
+ files.set(relpathPosix, new File({ cwd, path: relpathPosix, contents, stat, local: true }))
358
370
  done()
359
371
  },
360
372
  (readErr) => {
@@ -363,15 +375,14 @@ function srcFs (cwd) {
363
375
  )
364
376
  },
365
377
  (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)
378
+ done(
379
+ Object.assign(statErr, {
380
+ message: statErr.symlink
381
+ ? (statErr.code === 'ELOOP' ? 'ELOOP: symbolic link cycle, ' : 'ENOENT: broken symbolic link, ') +
382
+ `${relpath} -> ${statErr.symlink}`
383
+ : statErr.message.replace(`'${abspath}'`, relpath),
384
+ })
385
+ )
375
386
  }
376
387
  )
377
388
  }),
@@ -383,9 +394,14 @@ function srcFs (cwd) {
383
394
  function symlinkAwareStat (path_) {
384
395
  return fsp.lstat(path_).then((lstat) => {
385
396
  if (!lstat.isSymbolicLink()) return lstat
386
- return fsp.stat(path_).catch((statErr) => {
387
- throw Object.assign(statErr, { symlink: true })
388
- })
397
+ return fsp.stat(path_).catch((statErr) =>
398
+ fsp
399
+ .readlink(path_)
400
+ .catch(() => undefined)
401
+ .then((symlink) => {
402
+ throw Object.assign(statErr, { symlink })
403
+ })
404
+ )
389
405
  })
390
406
  }
391
407
 
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.1",
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/"