@antora/ui-loader
Advanced tools
Comparing version 3.2.0-alpha.4 to 3.2.0-alpha.5
@@ -6,12 +6,11 @@ 'use strict' | ||
UI_DESC_FILENAME: 'ui.yml', | ||
UI_SRC_GLOB: '**/*[!~]', | ||
UI_SRC_GLOB: '**/!(*~)', | ||
UI_SRC_OPTS: { | ||
braceExpansion: false, | ||
dot: true, | ||
follow: true, | ||
ignore: ['.git/**'], | ||
nomount: true, | ||
nosort: true, | ||
nounique: true, | ||
strict: false, | ||
ignore: ['.git'], | ||
objectMode: true, | ||
onlyFiles: false, | ||
unique: false, | ||
}, | ||
}) |
'use strict' | ||
const { Readable } = require('stream') | ||
const { Stats } = require('fs') | ||
const { constants: fsc } = require('node:fs') | ||
const { posix: path } = require('node:path') | ||
const { Readable } = require('node:stream') | ||
const Vinyl = require('vinyl') | ||
const DEFAULT_FILE_MODE = 0o100666 & ~process.umask() | ||
const invariably = { true: () => true, false: () => false } | ||
@@ -30,3 +32,9 @@ class File extends Vinyl { | ||
const contents = file.contents || Buffer.alloc(0) | ||
const stat = Object.assign(new Stats(), { mode: DEFAULT_FILE_MODE, mtime: undefined, size: contents.length }) | ||
const stat = { | ||
mode: DEFAULT_FILE_MODE, | ||
size: contents.length, | ||
isDirectory: invariably.false, | ||
isFile: invariably.true, | ||
isSymbolicLink: invariably.false, | ||
} | ||
super(Object.assign({}, file, { contents, stat })) | ||
@@ -36,14 +44,79 @@ } | ||
class ReadableFile extends Readable { | ||
constructor (file) { | ||
super({ objectMode: true }) | ||
this._file = file | ||
class ZipReadable extends Readable { | ||
constructor (zipFile, options = {}) { | ||
super({ objectMode: true, highWaterMark: 1 }) | ||
if ((this._closeable = (this._zipFile = zipFile).reader.fd != null) && !zipFile.autoClose) { | ||
throw new Error('ZipReadable requires file-based ZipFile to be initialized with autoClose:true option') | ||
} | ||
if (!zipFile.lazyEntries) { | ||
throw new Error('ZipReadable requires ZipFile to be initialized with lazyEntries:true option') | ||
} | ||
if ((this._startPath = options.startPath) && (this._startPath = path.join('/', this._startPath + '/')) !== '/') { | ||
this._startPath = this._startPath.slice(1) | ||
} else { | ||
this._startPath = undefined | ||
} | ||
this._init() | ||
} | ||
_read () { | ||
this.push(this._file) | ||
this.push((this._file = null)) | ||
_init () { | ||
const zipFile = this._zipFile | ||
zipFile | ||
.on('entry', (entry) => { | ||
const mode = this.getFileMode(entry) | ||
if ((mode & fsc.S_IFMT) === fsc.S_IFDIR) return zipFile.readEntry() | ||
let path_ = entry.fileName | ||
if (this._startPath) { | ||
if (path_.length < this._startPath.length || !path_.startsWith(this._startPath)) return zipFile.readEntry() | ||
path_ = path_.slice(this._startPath.length) | ||
} | ||
const isLink = (mode & fsc.S_IFMT) === fsc.S_IFLNK | ||
const stat = { | ||
mode, | ||
mtime: entry.getLastModDate(), | ||
size: entry.uncompressedSize, | ||
isDirectory: invariably.false, | ||
isFile: invariably[!isLink], | ||
isSymbolicLink: invariably[isLink], | ||
} | ||
const file = { path: path_, stat } | ||
if (stat.size === 0) { | ||
file.contents = Buffer.alloc(0) | ||
this.push(new File(file)) | ||
} else { | ||
zipFile.openReadStream(entry, (readErr, readStream) => { | ||
if (readErr) { | ||
zipFile.close() | ||
this.emit('error', readErr) | ||
return | ||
} | ||
if (isLink) { | ||
const buffer = [] | ||
readStream | ||
.on('data', (chunk) => buffer.push(chunk)) | ||
.on('error', (readStreamErr) => this.emit('error', readStreamErr)) | ||
.on('end', () => { | ||
file.symlink = (buffer.length === 1 ? buffer[0] : Buffer.concat(buffer)).toString() | ||
this.push(new File(file)) | ||
}) | ||
} else { | ||
file.contents = readStream | ||
this.push(new File(file)) | ||
} | ||
}) | ||
} | ||
}) | ||
.on(this._closeable ? 'close' : 'end', () => zipFile.emittedError || this.push(null)) | ||
} | ||
_read (_n) { | ||
this._zipFile.readEntry() | ||
} | ||
getFileMode ({ externalFileAttributes }) { | ||
const attr = externalFileAttributes >> 16 || 33188 | ||
return [448, 56, 7].map((mask) => attr & mask).reduce((a, b) => a + b, attr & fsc.S_IFMT) | ||
} | ||
} | ||
module.exports = { File, MemoryFile, ReadableFile } | ||
module.exports = { File, MemoryFile, ZipReadable } |
'use strict' | ||
const { compile: bracesToGroup } = require('braces') | ||
const { createHash } = require('crypto') | ||
const { createHash } = require('node:crypto') | ||
const expandPath = require('@antora/expand-path-helper') | ||
const { File, MemoryFile, ReadableFile } = require('./file') | ||
const { promises: fsp } = require('fs') | ||
const { File, MemoryFile, ZipReadable } = require('./file') | ||
const { promises: fsp } = require('node:fs') | ||
const { concat: get } = require('simple-get') | ||
const getCacheDir = require('cache-directory') | ||
const globStream = require('glob-stream') | ||
const { inspect } = require('util') | ||
const ospath = require('path') | ||
const { globStream } = require('fast-glob') | ||
const { inspect } = require('node:util') | ||
const invariably = { false: () => false, void: () => undefined } | ||
const ospath = require('node:path') | ||
const { posix: path } = ospath | ||
const picomatch = require('picomatch') | ||
const posixify = ospath.sep === '\\' ? (p) => p.replace(/\\/g, '/') : undefined | ||
const { pipeline, Transform, Writable } = require('stream') | ||
const { pipeline, PassThrough, Writable } = require('node:stream') | ||
const forEach = (write, final) => new Writable({ objectMode: true, write, final }) | ||
const map = (transform) => new Transform({ objectMode: true, transform }) | ||
const through = () => new PassThrough({ objectMode: true }) | ||
const UiCatalog = require('./ui-catalog') | ||
const yaml = require('js-yaml') | ||
const vzip = require('@vscode/gulp-vinyl-zip') | ||
const yauzl = require('yauzl') | ||
@@ -107,9 +108,6 @@ const STATIC_FILE_MATCHER_OPTS = { | ||
? srcFs(ospath.join(bundleFile.path, bundle.startPath || '', '.')).then(resolve, reject) | ||
: vzip | ||
.src(bundleFile.path) | ||
: srcZip(bundleFile.path, { startPath: bundle.startPath }) | ||
.on('error', (err) => reject(Object.assign(err, { message: `not a valid zip file; ${err.message}` }))) | ||
.pipe(selectFilesStartingFrom(bundle.startPath)) | ||
.pipe(bufferizeContents()) | ||
.pipe(bufferizeContentsAndCollectFiles(resolve)) | ||
.on('error', reject) | ||
.pipe(collectFiles(resolve)) | ||
).catch((err) => { | ||
@@ -183,4 +181,3 @@ const msg = | ||
} | ||
new ReadableFile(new MemoryFile({ path: ospath.basename(to), contents })) | ||
.pipe(vzip.src()) | ||
srcZip(contents, { testOnly: true }) | ||
.on('error', (err) => | ||
@@ -193,3 +190,3 @@ reject(Object.assign(err, { message: `not a valid zip file; ${err.message}`, summary: 'Invalid UI bundle' })) | ||
.then(() => fsp.writeFile(to, contents)) | ||
.then(() => resolve(new File({ path: to, stat: { isDirectory: () => false } }))) | ||
.then(() => resolve(new File({ path: to, stat: { isDirectory: invariably.false } }))) | ||
) | ||
@@ -206,58 +203,2 @@ }) | ||
function selectFilesStartingFrom (startPath) { | ||
if (!startPath || (startPath = path.join('/', startPath + '/')) === '/') { | ||
return map((file, _, next) => { | ||
if (file.isNull()) { | ||
next() | ||
} else { | ||
next( | ||
null, | ||
new File({ path: posixify ? posixify(file.path) : file.path, contents: file.contents, stat: file.stat }) | ||
) | ||
} | ||
}) | ||
} else { | ||
startPath = startPath.substr(1) | ||
const startPathOffset = startPath.length | ||
return map((file, _, next) => { | ||
if (file.isNull()) { | ||
next() | ||
} else { | ||
const path_ = posixify ? posixify(file.path) : file.path | ||
if (path_.length > startPathOffset && path_.startsWith(startPath)) { | ||
next(null, new File({ path: path_.substr(startPathOffset), contents: file.contents, stat: file.stat })) | ||
} else { | ||
next() | ||
} | ||
} | ||
}) | ||
} | ||
} | ||
function bufferizeContents () { | ||
return map((file, _, next) => { | ||
// NOTE gulp-vinyl-zip automatically converts the contents of an empty file to a Buffer | ||
if (file.isStream()) { | ||
const buffer = [] | ||
pipeline( | ||
file.contents, | ||
forEach((chunk, _, done) => buffer.push(chunk) && done()), | ||
(err) => (err ? next(err) : next(null, Object.assign(file, { contents: Buffer.concat(buffer) }))) | ||
) | ||
} else { | ||
next(null, file) | ||
} | ||
}) | ||
} | ||
function collectFiles (resolve, files = new Map()) { | ||
return forEach( | ||
(file, _, done) => { | ||
files.set(file.path, file) | ||
done() | ||
}, | ||
(done) => done() || resolve(files) | ||
) | ||
} | ||
function srcSupplementalFiles (filesSpec, startDir) { | ||
@@ -359,13 +300,11 @@ if (!filesSpec) return new Map() | ||
function srcFs (cwd) { | ||
return new Promise((resolve, reject, cache = Object.create(null), files = new Map(), relpathStart = cwd.length + 1) => | ||
return new Promise((resolve, reject, files = new Map()) => | ||
pipeline( | ||
globStream(UI_SRC_GLOB, Object.assign({ cache, cwd }, UI_SRC_OPTS)), | ||
forEach(({ path: abspathPosix }, _, done) => { | ||
if ((cache[abspathPosix] || {}).constructor === Array) return done() // detects some directories | ||
const abspath = posixify ? ospath.normalize(abspathPosix) : abspathPosix | ||
const relpath = abspath.substr(relpathStart) | ||
symlinkAwareStat(abspath).then( | ||
globStream(UI_SRC_GLOB, Object.assign({ cwd }, UI_SRC_OPTS)), | ||
forEach(({ path: relpath, dirent }, _, done) => { | ||
if (dirent.isDirectory()) return done() | ||
const relpathPosix = relpath | ||
const abspath = posixify ? ospath.join(cwd, (relpath = ospath.normalize(relpath))) : cwd + '/' + relpath | ||
fsp.stat(abspath).then( | ||
(stat) => { | ||
if (stat.isDirectory()) return done() // detects directories that slipped through cache check | ||
const relpathPosix = posixify ? posixify(relpath) : relpath | ||
fsp.readFile(abspath).then( | ||
@@ -381,12 +320,14 @@ (contents) => { | ||
}, | ||
(statErr) => { | ||
done( | ||
Object.assign(statErr, { | ||
message: statErr.symlink | ||
? (statErr.code === 'ELOOP' ? 'ELOOP: symbolic link cycle, ' : 'ENOENT: broken symbolic link, ') + | ||
`${relpath} -> ${statErr.symlink}` | ||
: statErr.message.replace(`'${abspath}'`, relpath), | ||
}) | ||
) | ||
} | ||
(statErr) => | ||
dirent.isSymbolicLink() | ||
? fsp | ||
.readlink(abspath) | ||
.then( | ||
(symlink) => | ||
(statErr.code === 'ELOOP' ? 'ELOOP: symbolic link cycle, ' : 'ENOENT: broken symbolic link, ') + | ||
`${relpath} -> ${symlink}`, | ||
() => statErr.message.replace(`'${abspath}'`, relpath) | ||
) | ||
.then((message) => done(Object.assign(statErr, { message }))) | ||
: done(Object.assign(statErr, { message: statErr.message.replace(`'${abspath}'`, relpath) })) | ||
) | ||
@@ -399,16 +340,34 @@ }), | ||
function symlinkAwareStat (path_) { | ||
return fsp.lstat(path_).then((lstat) => { | ||
if (!lstat.isSymbolicLink()) return lstat | ||
return fsp.stat(path_).catch((statErr) => | ||
fsp | ||
.readlink(path_) | ||
.catch(() => undefined) | ||
.then((symlink) => { | ||
throw Object.assign(statErr, { symlink }) | ||
}) | ||
) | ||
function srcZip (file, options = {}) { | ||
const result = options.testOnly // is it necessary to close streams in this case, or just sink()? | ||
? forEach((file_, _, done) => (file_.isStream() ? file_.contents.on('close', done).destroy() : done())) | ||
: through() | ||
yauzl[file instanceof Buffer ? 'fromBuffer' : 'open'](file, { lazyEntries: true }, (err, zipFile) => { | ||
if (err) return result.emit('error', err) | ||
new ZipReadable(zipFile, options).pipe(result) | ||
}) | ||
return result | ||
} | ||
function bufferizeContentsAndCollectFiles (resolve, files = new Map()) { | ||
return forEach( | ||
(file, _, done) => { | ||
if (file.isStream()) { | ||
const buffer = [] | ||
file.contents | ||
.on('data', (chunk) => buffer.push(chunk)) | ||
.on('end', () => { | ||
file.contents = buffer.length === 1 ? buffer[0] : Buffer.concat(buffer) | ||
files.set(file.path, file) | ||
done() | ||
}) | ||
} else { | ||
files.set(file.path, file) | ||
done() | ||
} | ||
}, | ||
(done) => done() || resolve(files) | ||
) | ||
} | ||
function transformError (err, msg) { | ||
@@ -415,0 +374,0 @@ const errWrapper = new Error(msg) |
{ | ||
"name": "@antora/ui-loader", | ||
"version": "3.2.0-alpha.4", | ||
"version": "3.2.0-alpha.5", | ||
"description": "Downloads a UI bundle, if necessary, and loads the files into a UI catalog for use in an Antora documentation pipeline.", | ||
@@ -29,15 +29,15 @@ "license": "MPL-2.0", | ||
"@antora/expand-path-helper": "~2.0", | ||
"@vscode/gulp-vinyl-zip": "~2.5", | ||
"braces": "~3.0", | ||
"cache-directory": "~2.0", | ||
"glob-stream": "~7.0", | ||
"fast-glob": "~3.3", | ||
"hpagent": "~1.2", | ||
"js-yaml": "~4.1", | ||
"picomatch": "~2.3", | ||
"picomatch": "~4.0", | ||
"should-proxy": "~1.0", | ||
"simple-get": "~4.0", | ||
"vinyl": "~2.2" | ||
"vinyl": "~3.0", | ||
"yauzl": "~3.1" | ||
}, | ||
"engines": { | ||
"node": ">=16.0.0" | ||
"node": ">=18.0.0" | ||
}, | ||
@@ -44,0 +44,0 @@ "files": [ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
23191
521
2
+ Addedfast-glob@~3.3
+ Addedyauzl@~3.1
+ Added@nodelib/fs.scandir@2.1.5(transitive)
+ Added@nodelib/fs.stat@2.0.5(transitive)
+ Added@nodelib/fs.walk@1.2.8(transitive)
+ Addedbare-events@2.5.0(transitive)
+ Addedfast-fifo@1.3.2(transitive)
+ Addedfast-glob@3.3.2(transitive)
+ Addedfastq@1.17.1(transitive)
+ Addedglob-parent@5.1.2(transitive)
+ Addedmerge2@1.4.1(transitive)
+ Addedmicromatch@4.0.8(transitive)
+ Addedpicomatch@4.0.2(transitive)
+ Addedqueue-microtask@1.2.3(transitive)
+ Addedqueue-tick@1.0.1(transitive)
+ Addedreplace-ext@2.0.0(transitive)
+ Addedreusify@1.0.4(transitive)
+ Addedrun-parallel@1.2.0(transitive)
+ Addedstreamx@2.20.2(transitive)
+ Addedteex@1.0.1(transitive)
+ Addedtext-decoder@1.2.1(transitive)
+ Addedvinyl@3.0.0(transitive)
+ Addedyauzl@3.1.3(transitive)
- Removed@vscode/gulp-vinyl-zip@~2.5
- Removedglob-stream@~7.0
- Removed@vscode/gulp-vinyl-zip@2.5.0(transitive)
- Removedappend-buffer@1.0.2(transitive)
- Removedbalanced-match@1.0.2(transitive)
- Removedbrace-expansion@1.1.11(transitive)
- Removedbuffer-equal@1.0.1(transitive)
- Removedcall-bind@1.0.7(transitive)
- Removedclone-buffer@1.0.0(transitive)
- Removedcloneable-readable@1.1.3(transitive)
- Removedconcat-map@0.0.1(transitive)
- Removedconvert-source-map@1.9.0(transitive)
- Removedcore-util-is@1.0.3(transitive)
- Removeddefine-data-property@1.1.4(transitive)
- Removeddefine-properties@1.2.1(transitive)
- Removedduplexify@3.7.14.1.3(transitive)
- Removedend-of-stream@1.4.4(transitive)
- Removedes-define-property@1.0.0(transitive)
- Removedes-errors@1.3.0(transitive)
- Removedextend@3.0.2(transitive)
- Removedfd-slicer@1.1.0(transitive)
- Removedflush-write-stream@1.1.1(transitive)
- Removedfs-mkdirp-stream@1.0.0(transitive)
- Removedfs.realpath@1.0.0(transitive)
- Removedfunction-bind@1.1.2(transitive)
- Removedget-intrinsic@1.2.4(transitive)
- Removedglob@7.2.3(transitive)
- Removedglob-parent@3.1.06.0.2(transitive)
- Removedglob-stream@6.1.07.0.0(transitive)
- Removedgopd@1.0.1(transitive)
- Removedgraceful-fs@4.2.11(transitive)
- Removedhas-property-descriptors@1.0.2(transitive)
- Removedhas-proto@1.0.3(transitive)
- Removedhas-symbols@1.0.3(transitive)
- Removedhasown@2.0.2(transitive)
- Removedinflight@1.0.6(transitive)
- Removedinherits@2.0.4(transitive)
- Removedis-absolute@1.0.0(transitive)
- Removedis-buffer@1.1.6(transitive)
- Removedis-glob@3.1.0(transitive)
- Removedis-negated-glob@1.0.0(transitive)
- Removedis-relative@1.0.0(transitive)
- Removedis-unc-path@1.0.0(transitive)
- Removedis-utf8@0.2.1(transitive)
- Removedis-valid-glob@1.0.0(transitive)
- Removedis-windows@1.0.2(transitive)
- Removedisarray@1.0.0(transitive)
- Removedjson-stable-stringify-without-jsonify@1.0.1(transitive)
- Removedlazystream@1.0.1(transitive)
- Removedlead@1.0.0(transitive)
- Removedminimatch@3.1.2(transitive)
- Removednormalize-path@2.1.1(transitive)
- Removednow-and-later@2.0.1(transitive)
- Removedobject-keys@1.1.1(transitive)
- Removedobject.assign@4.1.5(transitive)
- Removedordered-read-streams@1.0.1(transitive)
- Removedpath-dirname@1.0.2(transitive)
- Removedpath-is-absolute@1.0.1(transitive)
- Removedprocess-nextick-args@2.0.1(transitive)
- Removedpump@2.0.13.0.2(transitive)
- Removedpumpify@1.5.12.0.1(transitive)
- Removedqueue@4.5.1(transitive)
- Removedreadable-stream@2.3.83.6.2(transitive)
- Removedremove-bom-buffer@3.0.0(transitive)
- Removedremove-bom-stream@1.2.0(transitive)
- Removedreplace-ext@1.0.1(transitive)
- Removedresolve-options@1.1.0(transitive)
- Removedsafe-buffer@5.1.2(transitive)
- Removedset-function-length@1.2.2(transitive)
- Removedstream-shift@1.0.3(transitive)
- Removedstring_decoder@1.1.1(transitive)
- Removedthrough@2.3.8(transitive)
- Removedthrough2@2.0.54.0.2(transitive)
- Removedthrough2-filter@3.1.0(transitive)
- Removedto-absolute-glob@2.0.2(transitive)
- Removedto-through@2.0.0(transitive)
- Removedunc-path-regex@0.1.2(transitive)
- Removedunique-stream@2.3.1(transitive)
- Removedutil-deprecate@1.0.2(transitive)
- Removedvalue-or-function@3.0.0(transitive)
- Removedvinyl@2.2.1(transitive)
- Removedvinyl-fs@3.0.3(transitive)
- Removedvinyl-sourcemap@1.1.0(transitive)
- Removedxtend@4.0.2(transitive)
- Removedyauzl@2.10.0(transitive)
- Removedyazl@2.5.1(transitive)
Updatedpicomatch@~4.0
Updatedvinyl@~3.0