Socket
Socket
Sign inDemoInstall

@antora/assembler

Package Overview
Dependencies
Maintainers
2
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@antora/assembler - npm Package Compare versions

Comparing version 1.0.0-alpha.7 to 1.0.0-alpha.8

lib/util/sanitize.js

3

lib/assemble-content.js

@@ -6,2 +6,3 @@ 'use strict'

const PromiseQueue = require('./util/promise-queue')
const runCommand = require('./util/run-command')

@@ -27,3 +28,3 @@ async function assembleContent (playbook, contentCatalog, converter, { siteCatalog, configSource }) {

return new PromiseQueue({ concurrency: buildConfig.processLimit })
.add(aggregateDocuments.map((doc) => () => converter.call(this, doc, buildConfig)))
.add(aggregateDocuments.map((doc) => () => converter.call(this, doc, buildConfig, runCommand)))
.toPromise()

@@ -30,0 +31,0 @@ .then((files) => {

@@ -24,7 +24,7 @@ 'use strict'

const negated = pattern.charAt() === '!'
if (negated) pattern = pattern.substr(1)
if (negated) pattern = pattern.slice(1)
let version
const separatorIdx = pattern.search(VERSION_SEPARATOR_RX)
if (~separatorIdx) {
pattern = (version = true) && `${pattern.substr(0, separatorIdx)}%${pattern.substr(separatorIdx + 1) || '*'}`
pattern = (version = true) && `${pattern.slice(0, separatorIdx)}%${pattern.slice(separatorIdx + 1) || '*'}`
}

@@ -31,0 +31,0 @@ return Object.assign(makePicomatchRx(pattern, PICOMATCH_OPTS), {

@@ -32,2 +32,3 @@ 'use strict'

asciidocAttrs['page-partial'] = null
asciidocAttrs['loader-assembler'] = ''
if (config.componentVersions == null) {

@@ -50,3 +51,3 @@ config.componentVersions = ['*']

}
build.cwd = playbook.dir // use playbook.dir the purpose of finding and loading require scripts
build.cwd = playbook.dir // use playbook.dir for the purpose of finding and loading require scripts
if (!('clean' in build) && 'output' in playbook) build.clean = playbook.output.clean

@@ -67,3 +68,3 @@ if (!('publish' in build)) build.publish = true

for (const [k, v] of Object.entries(o)) {
const camelKey = k.charAt() + k.substr(1).replace(/_([a-z])/g, (_, l) => l.toUpperCase())
const camelKey = k.charAt() + k.slice(1).replace(/_([a-z])/g, (_, l) => l.toUpperCase())
accum[camelKey] = ~stopPaths.indexOf(pathPrefix + camelKey) ? v : camelCaseKeys(v, stopPaths, pathPrefix + camelKey)

@@ -70,0 +71,0 @@ }

@@ -5,2 +5,3 @@ 'use strict'

const path = require('node:path/posix')
const sanitize = require('./util/sanitize')

@@ -18,8 +19,15 @@ function produceAggregateDocument (

) {
const pagesInOutline = selectPagesInOutline(
outline,
pages.filter((it) => it.out)
)
const pagesInOutline = selectPagesInOutline(outline, pages)
const navtitle = outline.content
const stem = generateStem(componentVersion, navtitle)
const templateFile = contentCatalog.addFile({
src: {
component: componentVersion.name,
version: componentVersion.version,
module: 'ROOT',
family: 'page',
relative: generateSlug(navtitle),
},
})
const path_ = `${templateFile.out.path}.adoc`
contentCatalog.removeFile(templateFile)
const header = buildAsciiDocHeader(componentVersion, navtitle, doctype)

@@ -37,13 +45,13 @@ const body = aggregateAsciiDoc(

)
const relativeSrcPath = `${stem}.adoc`
return new File({
aggregate: true,
asciidoc: asciidocConfig,
contents: Buffer.from([...header, ...body].join('\n') + '\n'),
mediaType: 'text/asciidoc',
path: relativeSrcPath,
path: path_,
src: {
component: componentVersion.name,
version: componentVersion.version,
basename: path.basename(relativeSrcPath),
stem,
basename: path.basename(path_),
stem: path.basename(path_, '.adoc'),
extname: '.adoc',

@@ -55,3 +63,5 @@ },

function buildAsciiDocHeader (componentVersion, navtitle, doctype = 'book') {
const doctitle = navtitle === componentVersion.title ? navtitle : `${componentVersion.title}: ${navtitle}`
const [navtitlePlain, navtitleAsciiDoc] = sanitize(navtitle)
let doctitle = navtitleAsciiDoc
if (navtitlePlain !== componentVersion.title) doctitle = `${componentVersion.title}: ${doctitle}`
const version = componentVersion.version === 'master' ? '' : componentVersion.version

@@ -95,2 +105,3 @@ return [

sectionMergeStrategy,
lastComponentVersion = componentVersion,
level = 0

@@ -102,6 +113,13 @@ ) {

const { content: navtitle, items, unresolved, urlType, url } = outlineEntry
const [navtitlePlain, navtitleAsciiDoc, navtitlePass] = sanitize(navtitle)
const siteUrl = ((val) => {
if (!val || val === '/') return ''
return val.charAt(val.length - 1) === '/' ? val.slice(0, val.length - 1) : val
})(asciidocConfig.attributes['site-url'])
// FIXME: ideally, resource ID would be stored in navigation so we can look up the page more efficiently
let page = urlType === 'internal' && !unresolved ? pagesInOutline.get(url) : undefined
if (page && pagesInOutline.aggregated?.includes(page)) page = undefined
if (page) {
let contents = page.src.contents
if (contents == null) return buffer
// NOTE: blank lines at top and bottom of document create mismatch when using line numbers to navigate source lines

@@ -116,4 +134,5 @@ // IMPORTANT: this must not leave behind lines the parser will drop!

)
;(pagesInOutline.aggregated ??= []).push(page)
page = new page.constructor(Object.assign({}, page, { contents, mediaType: 'text/asciidoc' }))
const { module: module_, relative, origin } = page.src
const { component, version, module: module_, relative, origin } = page.src
const doc = loadAsciiDoc(page, contentCatalog, asciidocConfig)

@@ -124,5 +143,24 @@ const refs = doc.getCatalog().refs

const docnameForId = docname.replace(/[/]/g, '::').replace(/[.]/g, '-')
const idprefix = `${module_ === 'ROOT' ? '' : module_ + ':'}${docnameForId}:::`
const scopeId = component !== componentVersion.name
const idprefix =
(scopeId ? component + ':' : '') +
(module_ === 'ROOT' ? (scopeId ? ':' : '') : module_ + ':') +
docnameForId +
':::'
buffer.push('')
buffer.push(`:docname: ${docname}`)
if (component !== lastComponentVersion.name) {
const thisComponentVersion =
component === componentVersion.name && version === componentVersion.version
? componentVersion
: contentCatalog.getComponentVersion(component, version)
if (thisComponentVersion) {
buffer.push(`:page-component-name: ${thisComponentVersion.name}`)
buffer.push(`:page-component-version:${thisComponentVersion.version ? ' ' + thisComponentVersion.version : ''}`)
buffer.push(':page-version: {page-component-version}')
buffer.push(`:page-component-display-version: ${thisComponentVersion.displayVersion}`)
buffer.push(`:page-component-title: ${thisComponentVersion.title}`)
lastComponentVersion = thisComponentVersion
}
}
buffer.push(`:page-module: ${module_}`)

@@ -139,3 +177,3 @@ buffer.push(`:page-relative-src-path: ${relative}`)

if (level) {
if (level === 1 && navtitle === componentVersion.title) {
if (level === 1 && navtitlePlain === componentVersion.title) {
level--

@@ -150,3 +188,3 @@ } else {

}
buffer.push(`${'='.repeat(hlevel)} ${navtitle}`)
buffer.push(`${'='.repeat(hlevel)} ${navtitleAsciiDoc}`)
}

@@ -183,6 +221,2 @@ } else {

}
const siteUrl = ((val) => {
if (!val || val === '/') return ''
return val.charAt(val.length - 1) === '/' ? val.substr(0, val.length - 1) : val
})(doc.getAttribute('site-url'))
const lines = doc.getSourceLines()

@@ -264,4 +298,4 @@ const ignoreLines = []

if (~hashIdx) {
pagePart = target.substr(0, hashIdx)
fragment = target.substr(hashIdx + 1)
pagePart = target.slice(0, hashIdx)
fragment = target.slice(hashIdx + 1)
// TODO: for now, assume .adoc; in the future, consider other file extensions

@@ -282,16 +316,20 @@ if (pagePart && !pagePart.endsWith('.adoc')) pagePart += '.adoc'

if (~pagePart.indexOf('@') || /:.*:/.test(pagePart)) {
if (siteUrl && (targetPage = contentCatalog.resolvePage(pagePart, page.src)) && targetPage.out) {
text ||= targetPage.asciidoc?.xreftext || target
return `${siteUrl}${targetPage.pub.url}${fragment && '#' + fragment}[${text}]`
}
// TODO: handle unresolved page better
return siteUrl && (targetPage = contentCatalog.resolvePage(pagePart, page.src)) && targetPage.out
? `${siteUrl}${targetPage.pub.url}${fragment && '#' + fragment}[${text}]`
: m
return m
} else if (pagePart.indexOf(':') < 0) {
if (module_ !== 'ROOT') pagePart = `${module_}:${pagePart}`
} else if (pagePart.startsWith('ROOT:')) {
pagePart = pagePart.substr(5)
pagePart = pagePart.slice(5)
}
if (!(targetPage = pagesInOutline.get(pagePart))) {
if (siteUrl && (targetPage = contentCatalog.resolvePage(pagePart, page.src)) && targetPage.out) {
text ||= targetPage.asciidoc?.xreftext || target
return `${siteUrl}${targetPage.pub.url}${fragment && '#' + fragment}[${text}]`
}
// TODO: handle unresolved page better
return siteUrl && (targetPage = contentCatalog.resolvePage(target, page.src)) && targetPage.out
? `${siteUrl}${targetPage.pub.url}${fragment && '#' + fragment}[${text}]`
: m
return m
}

@@ -317,2 +355,3 @@ pagePart = pagePart

})
// TODO: handle unresolved attachment page
return attachment && attachment.out

@@ -370,3 +409,3 @@ ? `${siteUrl}${attachment.pub.url.replace(/_/g, '{underscore}')}[${text}]`

let imageMacroOffset = (
lastImageMacroAt?.[0] === idx ? line.substr(0, lastImageMacroAt[1]) : line
lastImageMacroAt?.[0] === idx ? line.slice(0, lastImageMacroAt[1]) : line
).lastIndexOf('image::')

@@ -376,5 +415,5 @@ if (imageMacroOffset > 0) {

block.getDocument().isNested() &&
(prefix = line.substr(0, imageMacroOffset)).trimRight().endsWith('|')
(prefix = line.slice(0, imageMacroOffset)).trimRight().endsWith('|')
) {
line = line.substr(prefix.length)
line = line.slice(prefix.length)
} else {

@@ -390,3 +429,3 @@ imageMacroOffset = -1

if (image && image.out) {
const boxedAttrlist = line.substr(line.indexOf('['))
const boxedAttrlist = line.slice(line.indexOf('['))
image.out.assembled = true

@@ -418,3 +457,11 @@ lines[idx] = `${prefix}image::${image.out.path}${boxedAttrlist}`

}
} else if (val != null && !(doc.isAttributeLocked(name) || name === 'doctype' || name === 'leveloffset')) {
} else if (
!(
val == null ||
doc.isAttributeLocked(name) ||
name === 'doctype' ||
name === 'leveloffset' ||
name === 'underscore'
)
) {
accum.push(`:!${name}:`)

@@ -428,33 +475,40 @@ }

}
} else {
if (level) {
if (level === 1 && navtitle === componentVersion.title) {
level--
} else {
buffer.push('')
// NOTE: try to toggle sectids; otherwise, fallback to globally unique synthetic ID
let toggleSectids, syntheticId
if (!('sectids' in asciidocConfig.attributes)) {
} else if (level) {
if (level === 1 && navtitlePlain === componentVersion.title) {
level--
} else {
buffer.push('')
// NOTE: try to toggle sectids; otherwise, fallback to globally unique synthetic ID
// Q: should we unset docname, page-module, etc?
let toggleSectids, syntheticId
if (!('sectids' in asciidocConfig.attributes)) {
buffer.push(':!sectids:')
toggleSectids = true
} else if (typeof asciidocConfig.attributes.sectids === 'string') {
if ('sectids' in mutableAttributes) {
buffer.push(':!sectids:')
toggleSectids = true
} else if (typeof asciidocConfig.attributes.sectids === 'string') {
if ('sectids' in mutableAttributes) {
buffer.push(':!sectids:')
toggleSectids = true
} else {
syntheticId = `__object-id-${global.Opal.hash(outlineEntry).$object_id()}`
}
} else {
syntheticId = `__object-id-${global.Opal.hash(outlineEntry).$object_id()}`
}
// Q: should we unset docname, page-module, etc?
const sectionTitle = urlType === 'external' ? `${url}[${navtitle.replace(/\]/, '\\]')}]` : navtitle
let hlevel = level + 1
if (hlevel > 6) {
hlevel = 6
buffer.push(syntheticId ? `[discrete#${syntheticId}]` : '[discrete]')
} else if (syntheticId) {
buffer.push(`[#${syntheticId}]`)
}
let sectionTitle = navtitleAsciiDoc
if (urlType === 'external') {
sectionTitle = `${url}[${navtitlePass ? navtitleAsciiDoc : navtitleAsciiDoc.replace(/\]/g, '\\]')}]`
} else if (urlType === 'internal' && !unresolved && siteUrl) {
const resource = contentCatalog.getFiles().find((it) => it.pub.url === url)
if (resource?.out) {
sectionTitle = navtitlePass ? navtitleAsciiDoc : navtitleAsciiDoc.replace(/\]/g, '\\]')
sectionTitle = `${siteUrl}${resource.pub.url}[${sectionTitle}]`
}
buffer.push(`${'='.repeat(hlevel)} ${sectionTitle}`)
if (toggleSectids) buffer.push(':sectids:')
}
let hlevel = level + 1
if (hlevel > 6) {
hlevel = 6
buffer.push(syntheticId ? `[discrete#${syntheticId}]` : '[discrete]')
} else if (syntheticId) {
buffer.push(`[#${syntheticId}]`)
}
buffer.push(`${'='.repeat(hlevel)} ${sectionTitle}`)
if (toggleSectids) buffer.push(':sectids:')
}

@@ -465,3 +519,7 @@ }

if (items) {
items.forEach((item) => {
// NOTE: drop first child if same as parent; should we keep if content is different?
;(urlType === 'internal' && urlType === items[0].urlType && url === items[0].url && !items[0].items
? items.slice(1)
: items
).forEach((item) => {
buffer.push(

@@ -478,2 +536,3 @@ ...aggregateAsciiDoc(

sectionMergeStrategy,
lastComponentVersion,
nextLevel

@@ -487,15 +546,8 @@ )

function generateStem (componentVersion, title) {
const { name, version } = componentVersion
const segments = []
if (name !== 'ROOT') segments.push(name)
if (version && version !== 'master') segments.push(version)
segments.push(
title
.toLowerCase()
.replace(/&.+?;|[^ \p{Alpha}0-9_\-.]/gu, '')
.replace(/[ _.]/g, '-')
.replace(/--+/g, '-')
)
return path.join(...segments)
function generateSlug (title) {
return title
.toLowerCase()
.replace(/&.+?;|[^ \p{Alpha}0-9_\-.]/gu, '')
.replace(/[ _.]/g, '-')
.replace(/--+/g, '-')
}

@@ -537,6 +589,6 @@

if (~commaIdx) {
rawStyle = prevLine.substr(1, commaIdx - 1)
rawStyle = prevLine.slice(1, commaIdx - 1)
if (~rawStyle.indexOf('=')) rawStyle = undefined
} else if (!~prevLine.indexOf('=')) {
rawStyle = prevLine.substr(1, prevLine.length - 2)
rawStyle = prevLine.slice(1, prevLine.length - 2)
}

@@ -550,6 +602,6 @@ if (rawStyle) {

replacementStyle ? rawStyle.replace(/^[^.%]*/, replacementStyle) : rawStyle
}#${idprefix}${block.getId()}${prevLine.substr(rawStyle.length + 1)}`
}#${idprefix}${block.getId()}${prevLine.slice(rawStyle.length + 1)}`
}
} else {
prevLine = `[${replacementStyle}#${idprefix}${block.getId()}${rawStyle == null ? ',' : ''}${prevLine.substr(1)}`
prevLine = `[${replacementStyle}#${idprefix}${block.getId()}${rawStyle == null ? ',' : ''}${prevLine.slice(1)}`
}

@@ -556,0 +608,0 @@ if (cellSpec) prevLine = `${cellSpec}|${prevLine}`

@@ -8,2 +8,4 @@ 'use strict'

const IMAGE_MACRO_RX = /^image::?(.+?)\[(.*?)\]$/
function produceAggregateDocuments (loadAsciiDoc, contentCatalog, assemblerConfig) {

@@ -24,16 +26,21 @@ const { insertStartPage, rootLevel, sectionMergeStrategy, asciidoc: assemblerAsciiDocConfig } = assemblerConfig

})
const mergedAsciiDocAttributes = mergedAsciiDocConfig.attributes
Object.entries(mergedAsciiDocAttributes).forEach(([name, val]) => {
const match = name.endsWith('-image') && val.startsWith('image:') && IMAGE_MACRO_RX.exec(val)
if (!(match && isResourceRef(match[1]))) return
// Q should we allow image to be resolved relative to component version?
const image = contentCatalog.resolveResource(match[1], undefined, 'image', ['image'])
if (!image?.out) return
mergedAsciiDocAttributes[name] = `image:${image.out.path}[${match[2]}]`
image.out.assembled = true
})
const rootEntry = { content: title }
const startPage = contentCatalog.getComponentVersionStartPage(componentName, version)
let startPageUrl
if (startPage && insertStartPage) {
if (includedInNav(navigation, (startPageUrl = startPage.pub.url))) {
startPageUrl = undefined
} else {
Object.assign(rootEntry, { url: startPageUrl, urlType: 'internal' })
let startPage = contentCatalog.getComponentVersionStartPage(componentName, version)
if (startPage && startPage.src.component === componentName && startPage.src.version === version) {
if (insertStartPage && !includedInNav(navigation, startPage.pub.url)) {
Object.assign(rootEntry, { url: startPage.pub.url, urlType: 'internal' })
}
}
// Q: should we always use a reference page here?
const startPage_ =
startPage ??
createFile({
} else {
// Q: should we always use a reference page as startPage for computing mutableAttributes?
startPage = createFile({
component: componentVersion.name,

@@ -44,3 +51,4 @@ version: componentVersion.version,

})
const mutableAttributes = selectMutableAttributes(loadAsciiDoc, contentCatalog, startPage_, mergedAsciiDocConfig)
}
const mutableAttributes = selectMutableAttributes(loadAsciiDoc, contentCatalog, startPage, mergedAsciiDocConfig)
delete mutableAttributes.doctype

@@ -62,6 +70,6 @@ accum = accum.concat(

)
mergedAsciiDocConfig.attributes.doctype = doctype
mergedAsciiDocAttributes.doctype = doctype
sourceHighlighter
? (mergedAsciiDocConfig.attributes['source-highlighter'] = sourceHighlighter)
: delete mergedAsciiDocConfig.attributes['source-highlighter']
? (mergedAsciiDocAttributes['source-highlighter'] = sourceHighlighter)
: delete mergedAsciiDocAttributes['source-highlighter']
return accum

@@ -120,2 +128,6 @@ },

function isResourceRef (target) {
return ~target.indexOf(':') && !(~target.indexOf('://') || (target.startsWith('data:') && ~target.indexOf(',')))
}
// when root level is 0, merge the navigation into the rootEntry

@@ -122,0 +134,0 @@ // when root level is 1, create navigation per navigation menu

{
"name": "@antora/assembler",
"version": "1.0.0-alpha.7",
"version": "1.0.0-alpha.8",
"description": "An extension library for Antora that assembles content from multiple pages into a single AsciiDoc file to converted and publish.",

@@ -18,4 +18,4 @@ "license": "MPL-2.0",

"test": "_mocha test",
"prepublishOnly": "node $npm_config_local_prefix/npm/prepublishOnly.js",
"postpublish": "node $npm_config_local_prefix/npm/postpublish.js"
"prepublishOnly": "npx -y downdoc --prepublish",
"postpublish": "npx -y downdoc --postpublish"
},

@@ -40,4 +40,4 @@ "main": "lib/index.js",

"devDependencies": {
"@antora/asciidoc-loader": "3.0.1",
"@antora/site-publisher": "3.0.1"
"@antora/asciidoc-loader": "~3.1",
"@antora/site-publisher": "~3.1"
},

@@ -44,0 +44,0 @@ "engines": {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc