@antora/content-aggregator 3.0.0-alpha.6 → 3.0.0-beta.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
@@ -2,24 +2,25 @@
2
2
 
3
3
  module.exports = Object.freeze({
4
4
  COMPONENT_DESC_FILENAME: 'antora.yml',
5
- CONTENT_CACHE_FOLDER: 'content/2',
6
- CONTENT_GLOB: '**/*.*',
5
+ CONTENT_CACHE_FOLDER: 'content',
6
+ CONTENT_SRC_GLOB: '**/*[!~]',
7
+ CONTENT_SRC_OPTS: { follow: true, nomount: true, nosort: true, nounique: true, removeBOM: false, uniqueBy: (m) => m },
7
8
  FILE_MODES: { 100644: 0o100666 & ~process.umask(), 100755: 0o100777 & ~process.umask() },
8
9
  GIT_CORE: 'antora',
9
10
  GIT_OPERATION_LABEL_LENGTH: 8,
10
11
  GIT_PROGRESS_PHASES: ['Counting objects', 'Compressing objects', 'Receiving objects', 'Resolving deltas'],
11
12
  PICOMATCH_VERSION_OPTS: {
12
13
  bash: true,
13
- debug: false,
14
14
  dot: true,
15
15
  fastpaths: false,
16
- lookbehinds: false,
17
- noextglob: true,
16
+ nobracket: true,
18
17
  noglobstar: true,
19
18
  nonegate: true,
20
19
  noquantifiers: true,
20
+ regex: false,
21
21
  strictSlashes: true,
22
22
  },
23
+ REF_PATTERN_CACHE_KEY: Symbol('RefPatternCache'),
23
24
  SYMLINK_FILE_MODE: '120000',
24
25
  VALID_STATE_FILENAME: 'valid',
25
26
  })
@@ -0,0 +1,6 @@
1
+ 'use strict'
2
+
3
+ module.exports = (({ StringDecoder }) => {
4
+ const decoder = new StringDecoder()
5
+ return decoder.write.bind(decoder)
6
+ })(require('string_decoder'))
@@ -0,0 +1,60 @@
1
+ 'use strict'
2
+
3
+ const { compile: bracesToGroup } = require('braces')
4
+ const { makeRe: makePicomatchRx } = require('picomatch')
5
+
6
+ function getPicomatchOpts (cache) {
7
+ return {
8
+ bash: true,
9
+ dot: true,
10
+ expandRange: (begin, end, step, opts) => {
11
+ const pattern = opts ? `{${begin}..${end}..${step}}` : `{${begin}..${end}}`
12
+ return cache.braces.get(pattern) || cache.braces.set(pattern, bracesToGroup(pattern)).get(pattern)
13
+ },
14
+ fastpaths: false,
15
+ nobracket: true,
16
+ noglobstar: true,
17
+ noquantifiers: true,
18
+ regex: false,
19
+ strictSlashes: true,
20
+ }
21
+ }
22
+
23
+ function compileRx (pattern, opts) {
24
+ if (pattern === '*' || pattern === '**') return { test: () => true }
25
+ return pattern.charAt() === '!' // do our own negate
26
+ ? Object.defineProperty(makePicomatchRx(pattern.substr(1), opts), 'negated', { value: true })
27
+ : makePicomatchRx(pattern, opts)
28
+ }
29
+
30
+ function createMatcher (patterns, cache) {
31
+ let opts
32
+ const rxs = patterns.map(
33
+ (pattern) =>
34
+ cache.get(pattern) ||
35
+ cache.set(pattern, compileRx(pattern, opts || (opts = getPicomatchOpts(cache)))).get(pattern)
36
+ )
37
+ return (candidate) => {
38
+ let first = true
39
+ let matched
40
+ for (const rx of rxs) {
41
+ if (matched) {
42
+ if (rx.negated && rx.test(candidate)) return
43
+ } else if (first || !rx.negated) {
44
+ matched = rx.test(candidate)
45
+ }
46
+ first = false
47
+ }
48
+ return matched
49
+ }
50
+ }
51
+
52
+ function filterRefs (candidates, patterns, cache = Object.assign(new Map(), { braces: new Map() })) {
53
+ const isMatch = createMatcher(patterns, cache)
54
+ return candidates.reduce((accum, candidate) => {
55
+ if (isMatch(candidate)) accum.push(candidate)
56
+ return accum
57
+ }, [])
58
+ }
59
+
60
+ module.exports = filterRefs
@@ -2,6 +2,7 @@
2
2
 
3
3
  const { homedir } = require('os')
4
4
  const expandPath = require('@antora/expand-path-helper')
5
+ const invariably = { void: () => undefined }
5
6
  const { promises: fsp } = require('fs')
6
7
  const ospath = require('path')
7
8
 
@@ -9,12 +10,10 @@ class GitCredentialManagerStore {
9
10
  configure ({ config, startDir }) {
10
11
  this.entries = undefined
11
12
  this.urls = {}
12
- if ((this.contents = (config = config || {}).contents)) {
13
+ if ((this.contents = (config = config || {}).contents) || !config.path) {
13
14
  this.path = undefined
14
- } else if (config.path) {
15
- this.path = expandPath(config.path, '~+', startDir)
16
15
  } else {
17
- this.path = undefined
16
+ this.path = expandPath(config.path, { dot: startDir })
18
17
  }
19
18
  return this
20
19
  }
@@ -28,10 +27,7 @@ class GitCredentialManagerStore {
28
27
  contentsPromise = Promise.resolve(this.contents)
29
28
  delimiter = /[,\n]/
30
29
  } else if (this.path) {
31
- contentsPromise = fsp
32
- .access(this.path)
33
- .then(() => fsp.readFile(this.path, 'utf8'))
34
- .catch(() => undefined)
30
+ contentsPromise = fsp.access(this.path).then(() => fsp.readFile(this.path, 'utf8'), invariably.void)
35
31
  } else {
36
32
  const homeGitCredentialsPath = ospath.join(homedir(), '.git-credentials')
37
33
  const xdgConfigGitCredentialsPath = ospath.join(
@@ -45,8 +41,7 @@ class GitCredentialManagerStore {
45
41
  .catch(() =>
46
42
  fsp
47
43
  .access(xdgConfigGitCredentialsPath)
48
- .then(() => fsp.readFile(xdgConfigGitCredentialsPath, 'utf8'))
49
- .catch(() => undefined)
44
+ .then(() => fsp.readFile(xdgConfigGitCredentialsPath, 'utf8'), invariably.void)
50
45
  )
51
46
  }
52
47
  contentsPromise.then((contents) => {
@@ -62,7 +57,7 @@ class GitCredentialManagerStore {
62
57
  if (password) {
63
58
  credentials = { username: decodeURIComponent(username), password: decodeURIComponent(password) }
64
59
  } else if (username) {
65
- credentials = { token: decodeURIComponent(username) }
60
+ credentials = { username: decodeURIComponent(username), password: '' }
66
61
  } else {
67
62
  return accum
68
63
  }
@@ -101,7 +96,7 @@ class GitCredentialManagerStore {
101
96
  const statusCode = 401
102
97
  const statusMessage = 'HTTP Basic: Access Denied'
103
98
  const err = new Error(`HTTP Error: ${statusCode} ${statusMessage}`)
104
- err.name = err.code = 'HTTPError'
99
+ err.name = err.code = 'HttpError'
105
100
  err.data = { statusCode, statusMessage }
106
101
  if (auth) err.rejected = true
107
102
  throw err
@@ -1,32 +1,56 @@
1
1
  'use strict'
2
2
 
3
3
  const get = require('simple-get')
4
- const { HttpProxyAgent, HttpsProxyAgent } = require('hpagent')
5
- const shouldProxy = require('should-proxy')
6
4
 
7
- module.exports = ({ httpProxy, httpsProxy, noProxy }) => {
8
- return async ({ core, emitter, emitterPreifx, url, method, headers, body }) => {
9
- if (body && Array.isArray(body)) {
10
- const buffers = []
11
- for await (const chunk of body) buffers.push(Buffer.from(chunk))
12
- body = Buffer.concat(buffers)
13
- }
14
- const proxy = url.startsWith('https:')
15
- ? { ProxyAgent: HttpsProxyAgent, url: httpsProxy }
16
- : { ProxyAgent: HttpProxyAgent, url: httpProxy }
17
- let agent
18
- if (proxy.url && shouldProxy(url, { no_proxy: noProxy })) {
19
- // see https://github.com/delvedor/hpagent/issues/18
20
- const { protocol, hostname, port, username, password } = new URL(proxy.url)
21
- const proxyUrl = { protocol, hostname, port, username: username || null, password: password || null }
22
- agent = new proxy.ProxyAgent({ proxy: proxyUrl })
5
+ function distillResponse (res) {
6
+ const { url, method, statusCode, statusMessage, headers } = res
7
+ return { url, method, statusCode, statusMessage, headers, body: res }
8
+ }
9
+
10
+ async function mergeBuffers (data) {
11
+ if (!Array.isArray(data)) return data
12
+ if (data.length === 1 && data[0] instanceof Buffer) return data[0]
13
+ const buffers = []
14
+ let offset = 0
15
+ let size = 0
16
+ for await (const chunk of data) {
17
+ buffers.push(chunk)
18
+ size += chunk.byteLength
19
+ }
20
+ data = new Uint8Array(size)
21
+ for (const buffer of buffers) {
22
+ data.set(buffer, offset)
23
+ offset += buffer.byteLength
24
+ }
25
+ return Buffer.from(data.buffer)
26
+ }
27
+
28
+ module.exports = ({ httpProxy, httpsProxy, noProxy }, userAgent) => {
29
+ if ((httpsProxy || httpProxy) && noProxy !== '*') {
30
+ const { HttpProxyAgent, HttpsProxyAgent } = require('hpagent')
31
+ const shouldProxy = require('should-proxy')
32
+ return {
33
+ async request ({ url, method, headers, body }) {
34
+ headers['user-agent'] = userAgent
35
+ body = await mergeBuffers(body)
36
+ const proxy = url.startsWith('https:')
37
+ ? { Agent: HttpsProxyAgent, url: httpsProxy }
38
+ : { Agent: HttpProxyAgent, url: httpProxy }
39
+ const agent =
40
+ proxy.url && shouldProxy(url, { no_proxy: noProxy }) ? new proxy.Agent({ proxy: proxy.url }) : undefined
41
+ return new Promise((resolve, reject) =>
42
+ get({ url, method, agent, headers, body }, (err, res) => (err ? reject(err) : resolve(distillResponse(res))))
43
+ )
44
+ },
23
45
  }
24
- return new Promise((resolve, reject) =>
25
- get({ url, agent, method, headers, body }, (err, res) => {
26
- if (err) return reject(err)
27
- const { url, method, statusCode, statusMessage, headers } = res
28
- resolve({ url, method, statusCode, statusMessage, headers, body: res })
29
- })
30
- )
46
+ }
47
+ return {
48
+ async request ({ url, method, headers, body }) {
49
+ headers['user-agent'] = userAgent
50
+ body = await mergeBuffers(body)
51
+ return new Promise((resolve, reject) =>
52
+ get({ url, method, headers, body }, (err, res) => (err ? reject(err) : resolve(distillResponse(res))))
53
+ )
54
+ },
31
55
  }
32
56
  }
package/lib/git.js ADDED
@@ -0,0 +1,3 @@
1
+ 'use strict'
2
+
3
+ module.exports = require('isomorphic-git')
package/lib/index.js CHANGED
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Responsible for aggregating the content from multiple repositories and
7
7
  * references into a raw aggregate of virtual files that can be organized by a
8
- * subsequent step in the pipeline.
8
+ * subsequent step in the generator.
9
9
  *
10
10
  * @namespace content-aggregator
11
11
  */
@@ -0,0 +1,11 @@
1
+ 'use strict'
2
+
3
+ Promise.allSettled = (iterable) =>
4
+ Promise.all(
5
+ iterable.map((it) =>
6
+ it.then(
7
+ (value) => ({ status: 'fulfilled', value }),
8
+ (reason) => ({ status: 'rejected', reason })
9
+ )
10
+ )
11
+ )
@@ -1,26 +1,33 @@
1
1
  'use strict'
2
2
 
3
- const { expand: expandBraces } = require('braces')
3
+ const { expand: expandBraces, compile: bracesToGroup } = require('braces')
4
4
  const flattenDeep = require('./flatten-deep')
5
5
  const { promises: fsp } = require('fs')
6
- const git = require('isomorphic-git')
7
- const invariably = { true: () => true, false: () => false, void: () => {}, emptyArray: () => [] }
6
+ const git = require('./git')
7
+ const invariably = { true: () => true, false: () => false, void: () => undefined, emptyArray: () => [] }
8
8
  const { makeRe: makePicomatchRx } = require('picomatch')
9
9
 
10
- const RX_ESCAPE_EXCEPT_GLOB = /[.+?^${}()|[\]\\]/g
11
- const RX_MAGIC_DETECTOR = /[*{]/
12
- const RX_QUESTION_MARK = /\?/g
13
- const PICOMATCH_OPTS = { nobracket: true, noextglob: true, noglobstar: true, noquantifiers: true }
14
- const PICOMATCH_NEGATED_OPTS = { nobracket: true, noextglob: true, noquantifiers: true }
10
+ const NON_GLOB_SPECIAL_CHARS_RX = /[.+?^${}()|[\]\\]/g
11
+ const RX_MAGIC_DETECTOR = /[*{(]/
12
+ const PICOMATCH_OPTS = {
13
+ bash: true,
14
+ expandRange: (begin, end, step, opts) => bracesToGroup(opts ? `{${begin}..${end}..${step}}` : `{${begin}..${end}}`),
15
+ fastpaths: false,
16
+ nobracket: true,
17
+ noglobstar: true,
18
+ nonegate: true,
19
+ noquantifiers: true,
20
+ regex: false,
21
+ strictSlashes: true,
22
+ }
15
23
 
16
24
  function resolvePathGlobs (base, patterns, listDirents, retrievePath, tree = { path: '' }) {
17
25
  return patterns.reduce((paths, pattern) => {
18
26
  if (pattern.charAt() === '!') {
19
27
  return paths.then((resolvedPaths) => {
20
28
  if (resolvedPaths.length) {
21
- if (~pattern.indexOf('?')) pattern = pattern.replace(RX_QUESTION_MARK, '\\?')
22
- const rx = makePicomatchRx(pattern, PICOMATCH_NEGATED_OPTS)
23
- return resolvedPaths.filter(rx.test.bind(rx))
29
+ const rx = makePicomatchRx(pattern.substr(1), PICOMATCH_OPTS)
30
+ return resolvedPaths.filter((it) => !rx.test(it))
24
31
  } else {
25
32
  return resolvedPaths
26
33
  }
@@ -38,14 +45,13 @@ async function glob (base, patternSegments, listDirents, retrievePath, { oid, pa
38
45
  let patternSegment = patternSegments[0]
39
46
  patternSegments = patternSegments.slice(1)
40
47
  if (RX_MAGIC_DETECTOR.test(patternSegment)) {
41
- let isMatch
42
- let explicit
48
+ let isMatch, explicit
43
49
  if (patternSegment === '*') {
44
50
  isMatch = (it) => it.charAt() !== '.'
51
+ } else if (~patternSegment.indexOf('(')) {
52
+ isMatch = (isMatch = makePicomatchRx(patternSegment, PICOMATCH_OPTS)).test.bind(isMatch)
45
53
  } else if (~patternSegment.indexOf('{')) {
46
54
  if (globbed) {
47
- if (patternSegment.charAt() === '!') patternSegment = '\\' + patternSegment
48
- if (~patternSegment.indexOf('?')) patternSegment = patternSegment.replace(RX_QUESTION_MARK, '\\?')
49
55
  isMatch = (isMatch = makePicomatchRx(patternSegment, PICOMATCH_OPTS)).test.bind(isMatch)
50
56
  } else if (~patternSegment.indexOf('*')) {
51
57
  const [wildPatterns, literals] = expandBraces(patternSegment).reduce(
@@ -90,22 +96,15 @@ async function glob (base, patternSegments, listDirents, retrievePath, { oid, pa
90
96
  })
91
97
  } else if ((patternSegment += '/' + patternSegments.join('/')).indexOf('{')) {
92
98
  return expandBraces(patternSegment).map((it) => joinPath(path, it))
93
- } else {
94
- return [joinPath(path, patternSegment)]
95
99
  }
100
+ return [joinPath(path, patternSegment)]
96
101
  } else if (globbed) {
97
102
  return (await retrievePath(base, { oid, path }, patternSegment)) ? [joinPath(path, patternSegment)] : []
98
- } else {
99
- return [joinPath(path, patternSegment)]
100
103
  }
104
+ return [joinPath(path, patternSegment)]
101
105
  }
102
106
  }
103
107
 
104
- function regexpEscapeWithGlob (str) {
105
- // we don't escape "-" since it's meaningless in a literal
106
- return str.replace(RX_ESCAPE_EXCEPT_GLOB, '\\$&').replace('*', '.*')
107
- }
108
-
109
108
  function extractMagicBase (patternSegments, base) {
110
109
  let nextSegment
111
110
  if (patternSegments.length) {
@@ -123,12 +122,11 @@ function listDirentsFs (base, path) {
123
122
 
124
123
  function listDirentsGit (repo, treeOid) {
125
124
  return git
126
- .readObject(Object.assign({ oid: treeOid, filepath: '' }, repo))
127
- .catch(() => ({ object: {} }))
128
- .then(({ object: { entries } }) =>
129
- entries
130
- ? entries.map(({ type, oid, path: name }) => ({ name, oid, isDirectory: invariably[type === 'tree'] }))
131
- : []
125
+ .readTree(Object.assign({ oid: treeOid, filepath: '' }, repo))
126
+ .then(
127
+ ({ tree: entries }) =>
128
+ entries.map(({ type, oid, path: name }) => ({ name, oid, isDirectory: invariably[type === 'tree'] })),
129
+ invariably.emptyArray
132
130
  )
133
131
  }
134
132
 
@@ -141,7 +139,13 @@ function makeMatcherRx (pattern) {
141
139
  }
142
140
 
143
141
  function patternToRx (pattern) {
144
- return (pattern.charAt() === '.' ? '' : '(?!\\.)') + regexpEscapeWithGlob(pattern)
142
+ return (
143
+ (pattern.charAt() === '.' ? '' : '(?!\\.)') +
144
+ pattern
145
+ .replace(NON_GLOB_SPECIAL_CHARS_RX, '\\$&')
146
+ .replace('\\\\*', '\\x2a')
147
+ .replace('*', '.*?')
148
+ )
145
149
  }
146
150
 
147
151
  function readdirWithFileTypes (dir) {
@@ -149,10 +153,7 @@ function readdirWithFileTypes (dir) {
149
153
  }
150
154
 
151
155
  function retrievePathFs (base, { path }, subpath) {
152
- return fsp
153
- .access(base + '/' + joinPath(path, subpath))
154
- .then(invariably.true)
155
- .catch(invariably.false)
156
+ return fsp.access(base + '/' + joinPath(path, subpath)).then(invariably.true, invariably.false)
156
157
  }
157
158
 
158
159
  function retrievePathGit (repo, { oid }, filepath) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antora/content-aggregator",
3
- "version": "3.0.0-alpha.6",
3
+ "version": "3.0.0-beta.1",
4
4
  "description": "Fetches and aggregates content from distributed sources for use in an Antora documentation pipeline.",
5
5
  "license": "MPL-2.0",
6
6
  "author": "OpenDevise Inc. (https://opendevise.com)",
@@ -17,16 +17,16 @@
17
17
  },
18
18
  "main": "lib/index.js",
19
19
  "dependencies": {
20
- "@antora/expand-path-helper": "~1.0",
20
+ "@antora/expand-path-helper": "~2.0",
21
+ "@antora/user-require-helper": "~2.0",
21
22
  "braces": "~3.0",
22
23
  "cache-directory": "~2.0",
23
- "camelcase-keys": "~6.2",
24
+ "camelcase-keys": "~7.0",
24
25
  "hpagent": "~0.1.0",
25
- "isomorphic-git": "0.78.5",
26
+ "isomorphic-git": "~1.10",
26
27
  "js-yaml": "~4.1",
27
- "matcher": "~4.0",
28
28
  "multi-progress": "~4.0",
29
- "picomatch": "~2.2",
29
+ "picomatch": "~2.3",
30
30
  "progress": "~2.0",
31
31
  "should-proxy": "~1.0",
32
32
  "simple-get": "~4.0",
@@ -34,7 +34,7 @@
34
34
  "vinyl-fs": "~3.0"
35
35
  },
36
36
  "engines": {
37
- "node": ">=10.17.0"
37
+ "node": ">=12.21.0"
38
38
  },
39
39
  "files": [
40
40
  "lib/"
@@ -49,5 +49,5 @@
49
49
  "static site",
50
50
  "web publishing"
51
51
  ],
52
- "gitHead": "38ec002e88eede3ce5c401a6e226d1a0356945c5"
52
+ "gitHead": "7c5ef1ea93dd489af533c80a936c736013c41769"
53
53
  }