@antora/ui-loader 3.0.0-beta.2 → 3.0.0-beta.3

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
@@ -11,7 +11,7 @@ module.exports = Object.freeze({
11
11
  nomount: true,
12
12
  nosort: true,
13
13
  nounique: true,
14
- removeBOM: false,
14
+ strict: false,
15
15
  uniqueBy: (m) => m,
16
16
  },
17
17
  })
package/lib/load-ui.js CHANGED
@@ -1,5 +1,6 @@
1
1
  'use strict'
2
2
 
3
+ const { compile: bracesToGroup } = require('braces')
3
4
  const camelCaseKeys = require('camelcase-keys')
4
5
  const concat = require('simple-concat')
5
6
  const { createHash } = require('crypto')
@@ -8,17 +9,25 @@ const { File, MemoryFile, ReadableFile } = require('./file')
8
9
  const { promises: fsp } = require('fs')
9
10
  const { concat: get } = require('simple-get')
10
11
  const getCacheDir = require('cache-directory')
11
- const minimatchAll = require('minimatch-all')
12
+ const globStream = require('glob-stream')
12
13
  const ospath = require('path')
13
14
  const { posix: path } = ospath
15
+ const picomatch = require('picomatch')
14
16
  const posixify = ospath.sep === '\\' ? (p) => p.replace(/\\/g, '/') : undefined
15
- const { Transform } = require('stream')
17
+ const { pipeline, Transform } = require('stream')
16
18
  const map = (transform, flush = undefined) => new Transform({ objectMode: true, transform, flush })
17
19
  const UiCatalog = require('./ui-catalog')
18
20
  const yaml = require('js-yaml')
19
- const vfs = require('vinyl-fs')
20
21
  const vzip = require('gulp-vinyl-zip')
21
22
 
23
+ const STATIC_FILE_MATCHER_OPTS = {
24
+ expandRange: (begin, end, step, opts) => bracesToGroup(opts ? `{${begin}..${end}..${step}}` : `{${begin}..${end}}`),
25
+ fastpaths: false,
26
+ nobracket: true,
27
+ noquantifiers: true,
28
+ regex: false,
29
+ strictSlashes: true,
30
+ }
22
31
  const { UI_CACHE_FOLDER, UI_DESC_FILENAME, UI_SRC_GLOB, UI_SRC_OPTS } = require('./constants')
23
32
  const URI_SCHEME_RX = /^https?:\/\//
24
33
  const EXT_RX = /\.[a-z]{2,3}$/
@@ -94,11 +103,7 @@ async function loadUi (playbook) {
94
103
  resolveBundle.then((bundleFile) =>
95
104
  new Promise((resolve, reject) =>
96
105
  bundleFile.isDirectory()
97
- ? vfs
98
- .src(UI_SRC_GLOB, Object.assign({ cwd: bundleFile.path }, UI_SRC_OPTS))
99
- .on('error', reject)
100
- .pipe(relativizeFiles())
101
- .pipe(collectFiles(resolve))
106
+ ? srcFs(bundleFile.path).then(resolve, reject)
102
107
  : vzip
103
108
  .src(bundleFile.path)
104
109
  .on('error', (err) => reject(Object.assign(err, { message: `not a valid zip file; ${err.message}` })))
@@ -280,16 +285,7 @@ function srcSupplementalFiles (filesSpec, startDir) {
280
285
  const cwd = expandPath(filesSpec, { dot: startDir })
281
286
  return fsp
282
287
  .access(cwd)
283
- .then(
284
- () =>
285
- new Promise((resolve, reject) =>
286
- vfs
287
- .src(UI_SRC_GLOB, Object.assign({ cwd, dot: true }, UI_SRC_OPTS))
288
- .on('error', reject)
289
- .pipe(relativizeFiles())
290
- .pipe(collectFiles(resolve))
291
- )
292
- )
288
+ .then(() => srcFs(cwd))
293
289
  .catch((err) => {
294
290
  // Q: should we skip unreadable files?
295
291
  throw Object.assign(err, { message: `problem encountered while reading ui.supplemental_files: ${err.message}` })
@@ -297,17 +293,6 @@ function srcSupplementalFiles (filesSpec, startDir) {
297
293
  }
298
294
  }
299
295
 
300
- function relativizeFiles () {
301
- return map((file, _, next) => {
302
- if (file.isNull()) {
303
- next()
304
- } else {
305
- const path_ = posixify ? posixify(file.relative) : file.relative
306
- next(null, new File({ cwd: file.cwd, path: path_, contents: file.contents, stat: file.stat, local: true }))
307
- }
308
- })
309
- }
310
-
311
296
  function mergeFiles (files, supplementalFiles) {
312
297
  if (supplementalFiles.size) supplementalFiles.forEach((file) => files.set(file.path, file))
313
298
  return files
@@ -318,15 +303,9 @@ function loadConfig (files, outputDir) {
318
303
  if (configFile) {
319
304
  files.delete(UI_DESC_FILENAME)
320
305
  const config = camelCaseKeys(yaml.load(configFile.contents.toString()), { deep: true })
321
- if (outputDir !== undefined) config.outputDir = outputDir
322
306
  const staticFiles = config.staticFiles
323
- if (staticFiles) {
324
- if (!Array.isArray(staticFiles)) {
325
- config.staticFiles = [staticFiles]
326
- } else if (staticFiles.length === 0) {
327
- delete config.staticFiles
328
- }
329
- }
307
+ if (staticFiles && staticFiles.length) config.isStaticFile = picomatch(staticFiles, STATIC_FILE_MATCHER_OPTS)
308
+ if (outputDir !== undefined) config.outputDir = outputDir
330
309
  return config
331
310
  } else {
332
311
  return { outputDir }
@@ -334,7 +313,7 @@ function loadConfig (files, outputDir) {
334
313
  }
335
314
 
336
315
  function classifyFile (file, config) {
337
- if (config.staticFiles && isStaticFile(file, config.staticFiles)) {
316
+ if (config.isStaticFile && config.isStaticFile(file.path)) {
338
317
  file.type = 'static'
339
318
  file.out = resolveOut(file, '')
340
319
  } else if (file.isDot()) {
@@ -345,10 +324,6 @@ function classifyFile (file, config) {
345
324
  return file
346
325
  }
347
326
 
348
- function isStaticFile (file, staticFiles) {
349
- return minimatchAll(file.path, staticFiles)
350
- }
351
-
352
327
  function resolveType (file) {
353
328
  const firstPathSegment = file.path.split('/', 1)[0]
354
329
  if (firstPathSegment === 'layouts') return 'layout'
@@ -364,4 +339,52 @@ function resolveOut (file, outputDir = '_') {
364
339
  return { dirname, basename, path: path.join(dirname, basename) }
365
340
  }
366
341
 
342
+ function srcFs (cwd) {
343
+ return new Promise((resolve, reject, cache = {}, files = new Map()) =>
344
+ pipeline(
345
+ globStream(UI_SRC_GLOB, Object.assign({ cache, cwd }, UI_SRC_OPTS)),
346
+ map(({ path: abspathPosix }, _, next) => {
347
+ const abspath = posixify ? ospath.normalize(abspathPosix) : abspathPosix
348
+ const relpath = abspath.substr(cwd.length + 1)
349
+ symlinkAwareStat(abspath).then(
350
+ (stat) => {
351
+ if (stat.isDirectory()) return next()
352
+ fsp.readFile(abspath).then(
353
+ (contents) => {
354
+ const path_ = posixify ? posixify(relpath) : relpath
355
+ files.set(path_, new File({ cwd, path: path_, contents, stat, local: true }))
356
+ next()
357
+ },
358
+ (readErr) => {
359
+ next(Object.assign(readErr, { message: readErr.message.replace(`'${abspath}'`, relpath) }))
360
+ }
361
+ )
362
+ },
363
+ (statErr) => {
364
+ if (statErr.symlink) {
365
+ statErr.message =
366
+ statErr.code === 'ELOOP'
367
+ ? `Symbolic link cycle detected at ${relpath}`
368
+ : `Broken symbolic link detected at ${relpath}`
369
+ } else {
370
+ statErr.message = statErr.message.replace(`'${abspath}'`, relpath)
371
+ }
372
+ next(statErr)
373
+ }
374
+ )
375
+ }),
376
+ (err) => (err ? reject(err) : resolve(files))
377
+ )
378
+ )
379
+ }
380
+
381
+ function symlinkAwareStat (path_) {
382
+ return fsp.lstat(path_).then((lstat) => {
383
+ if (!lstat.isSymbolicLink()) return lstat
384
+ return fsp.stat(path_).catch((statErr) => {
385
+ throw Object.assign(statErr, { symlink: true })
386
+ })
387
+ })
388
+ }
389
+
367
390
  module.exports = loadUi
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antora/ui-loader",
3
- "version": "3.0.0-beta.2",
3
+ "version": "3.0.0-beta.3",
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)",
@@ -18,17 +18,17 @@
18
18
  "main": "lib/index.js",
19
19
  "dependencies": {
20
20
  "@antora/expand-path-helper": "~2.0",
21
+ "braces": "~3.0",
21
22
  "cache-directory": "~2.0",
22
23
  "camelcase-keys": "~7.0",
23
24
  "gulp-vinyl-zip": "~2.5",
24
25
  "hpagent": "~0.1.0",
25
26
  "js-yaml": "~4.1",
26
- "minimatch-all": "~1.1",
27
+ "picomatch": "~2.3",
27
28
  "should-proxy": "~1.0",
28
29
  "simple-concat": "~1.0",
29
30
  "simple-get": "~4.0",
30
- "vinyl": "~2.2",
31
- "vinyl-fs": "~3.0"
31
+ "vinyl": "~2.2"
32
32
  },
33
33
  "engines": {
34
34
  "node": ">=12.21.0"
@@ -45,5 +45,5 @@
45
45
  "static site",
46
46
  "web publishing"
47
47
  ],
48
- "gitHead": "5cd3f9cc70622e465cb44daf1aa2035ed5a35f54"
48
+ "gitHead": "45da95a2e2dea538379d2d9f42013d2208fb86c3"
49
49
  }