UNPKG

@antora/assembler

Version:

A JavaScript library that merges AsciiDoc content from multiple pages in an Antora site into assembly files and delegates to an exporter to convert those files to another format, such as PDF.

201 lines (190 loc) 7.17 kB
'use strict' const createResourceKey = require('./create-resource-key') const generateScopedId = require('./generate-scoped-id') const parseResourceRef = require('./parse-resource-ref') const { resolveEmbedTarget, resolveLinkTarget } = require('./resolver') const { NAMED_ID_ATTR_RX } = require('./rx') function rewriteXrefs ( line, contentCatalog, assemblyModel, ctx, escapeForInline, pagesInOutline, idSeparators, idLeader, doc, sourceLocation ) { return line.replace(/(?<![\\+])xref:((?:\.\/)?[\p{Alpha}0-9_/.{#].*?)\[(|[\s\S]*?[^\\])\]/gu, (_, target, text) => rewriteXref( target, text, contentCatalog, assemblyModel, ctx, escapeForInline, pagesInOutline, idSeparators, idLeader, doc, sourceLocation ) ) } function rewriteXref ( target, text, contentCatalog, assemblyModel, ctx, escapeForInline, pagesInOutline, idSeparators, idLeader, doc, sourceLocation ) { const rawTarget = target if (doc && ~target.indexOf('{')) target = doc.$sub_attributes(target, global.Opal.hash({ attribute_missing: 'skip' })) let fragment, resourceRef const hashIdx = target.indexOf('#') if (~hashIdx) { resourceRef = target.slice(0, hashIdx) fragment = target.slice(hashIdx + 1) } else if (target.endsWith('.adoc') || ~target.indexOf('$')) { resourceRef = target fragment = '' } else { fragment = target } if (!resourceRef) return `xref:${idLeader == null ? rawTarget : idLeader + fragment}[${text}]` const resourceId = parseResourceRef(resourceRef, ctx, 'page', contentCatalog) const family = resourceId.family let resource if (family !== 'page' || !(resource = pagesInOutline?.get(createResourceKey(resourceId)))) { if ((resource = contentCatalog.getById(resourceId))?.pub) { const { linkReferenceStyle, pubRoot, siteRoot } = assemblyModel text ||= resource.asciidoc?.xreftext || rawTarget if (siteRoot || linkReferenceStyle === 'relative') { const hash = fragment && !(family === 'page' && fragment === resource.asciidoc.id) ? '#' + fragment : '' return `${resolveLinkTarget(resource, siteRoot, pubRoot, linkReferenceStyle, escapeForInline)}${hash}[${text}]` } if (doc) { const msg = `Cannot create external ${family} reference in assembly because site URL is unknown: ${rawTarget}` doc.logger.warn(doc.createLogMessage(msg, { source_location: sourceLocation })) } } const linkAttrlist = text ? (~text.indexOf(',') ? `"${text}"` : text) + ',role=unresolved' : (~target.indexOf(':') ? `${rawTarget},` : '') + 'role=unresolved' return `link:${rawTarget}[${linkAttrlist}]` } if (fragment === resource.asciidoc.id) fragment = '' if ( text && (assemblyModel.dropExplicitXrefText === 'always' || (assemblyModel.dropExplicitXrefText === 'if-redundant' && text === resource.title)) ) { text = '' } const componentVersionCtx = { name: ctx.component, version: ctx.version } const refid = generateScopedId( resource.src, componentVersionCtx, idSeparators, assemblyModel.filetype, text.length > 0 ) return `xref:${fragment ? refid + idSeparators.scope + fragment : refid}[${text}]` } function rewriteImageAttr (val, contentCatalog, assemblyModel, ctx, assets) { const match = val.startsWith('image:') && /^image::?(.+?)\[(.*?)\](@|)$/.exec(val) if (!match) return const newTarget = rewriteImageRef(match[1], contentCatalog, assemblyModel, ctx, assets) return newTarget ? `image:${newTarget}[${match[2]}]${match[3]}` : val } function rewriteInlineImages (line, contentCatalog, assemblyModel, ctx, assets, escapeForInline, doc) { return line.replace(/(?<![\\+])image:([^:\s[](?:[^[]*[^\s[])?)\[(|[\s\S]*?[^\\])\]/g, (m, target, attrlist) => { const newTarget = rewriteImageRef(target, contentCatalog, assemblyModel, ctx, assets, escapeForInline, doc) return newTarget ? `image:${newTarget}[${attrlist}]` : m }) } function rewriteImageRef (target, contentCatalog, assemblyModel, ctx, assets, escapeForInline, doc) { if (doc && ~target.indexOf('{')) target = doc.$sub_attributes(target, global.Opal.hash({ attribute_missing: 'skip' })) const image = isResourceRef(target) && contentCatalog.resolveResource(target, ctx, 'image', ['image']) if (!image?.out) return let newTarget const { filetype, embedReferenceStyle, linkReferenceStyle, outDirname, pubRoot, siteRoot } = assemblyModel if (filetype !== 'html') { newTarget = resolveEmbedTarget(image, outDirname, embedReferenceStyle, escapeForInline ?? false) assets.add(image) } else if (siteRoot || linkReferenceStyle === 'relative') { newTarget = resolveLinkTarget(image, siteRoot, pubRoot, linkReferenceStyle, escapeForInline ?? false, false) if (linkReferenceStyle === 'relative') assets.add(image) } if (!newTarget) return return newTarget } function rewriteStyleAttribute (block, lines, idx, idLeader, replacementStyle = '') { let prevLine = lines[idx - 1] const char0 = prevLine?.charAt() if (char0) { if ( (char0 === '.' && /^\.\.?[^ \t.]/.test(prevLine)) || (char0 === '[' && prevLine.charAt(1) === '[' && /^\[\[(?:|[\p{Alpha}_:][\p{Alpha}0-9_\-:.]*(?:, *.+)?)\]\]$/u.test(prevLine)) ) { return rewriteStyleAttribute(block, lines, idx - 1, idLeader, replacementStyle) } } let cellSpec if ( char0 && (char0 === '[' || (block.getDocument().isNested() && (cellSpec = prevLine.match(/^([^[|]*)\| *(\[.+)/)))) && prevLine.charAt(prevLine.length - 1) === ']' ) { if (cellSpec) { prevLine = cellSpec[2] cellSpec = cellSpec[1] } else if (~prevLine.indexOf('id=')) { prevLine = `[${prevLine.slice(1, -1).replace(NAMED_ID_ATTR_RX, '')}]` } let rawStyle const commaIdx = prevLine.indexOf(',') if (~commaIdx) { rawStyle = prevLine.slice(1, commaIdx) if (~rawStyle.indexOf('=')) rawStyle = undefined } else if (!~prevLine.indexOf('=')) { rawStyle = prevLine.slice(1, prevLine.length - 1) } if (rawStyle) { if (~rawStyle.indexOf('#')) { prevLine = prevLine.replace(/#[^.%,\]]+/, `#${idLeader}${block.getId()}`) if (replacementStyle) prevLine = prevLine.replace(/^[^#.%,\]]+/, `[${replacementStyle}`) } else { prevLine = `[${ replacementStyle ? rawStyle.replace(/^[^.%]*/, replacementStyle) : rawStyle }#${idLeader}${block.getId()}${prevLine.slice(rawStyle.length + 1)}` } } else { prevLine = `[${replacementStyle}#${idLeader}${block.getId()}${rawStyle == null ? ',' : ''}${prevLine.slice(1)}` } if (cellSpec) prevLine = `${cellSpec}|${prevLine}` lines[idx - 1] = prevLine } else { lines.splice(idx, 0, `[${replacementStyle}#${idLeader}${block.getId()}]`) } } function isResourceRef (str) { return !(~str.indexOf(':') && (~str.indexOf('://') || (str.startsWith('data:') && ~str.indexOf(',')))) } module.exports = { rewriteXref, rewriteXrefs, rewriteImageAttr, rewriteImageRef, rewriteInlineImages, rewriteStyleAttribute, }