diff --git a/packages/assembler/lib/produce-assembly-file.js b/packages/assembler/lib/produce-assembly-file.js index df2d23d74dcb59d3d284ac794055c0dafa27e8fd..6378bf5e9119352e223b978cce49593eaf63cc09 100644 --- a/packages/assembler/lib/produce-assembly-file.js +++ b/packages/assembler/lib/produce-assembly-file.js @@ -371,57 +371,70 @@ function mergeAsciiDoc ( if (~line.indexOf('xref:')) { // Q: should we allow : as first character of target? line = line.replace(/(? { - let pagePart, fragment, targetPage + let relativePart, fragment, targetResource, isPage const hashIdx = target.indexOf('#') + const dollarIdx = target.indexOf('$') if (~hashIdx) { - pagePart = target.slice(0, hashIdx) + relativePart = target.slice(0, hashIdx) fragment = target.slice(hashIdx + 1) - // TODO: for now, assume .adoc; in the future, consider other file extensions - if (pagePart && !pagePart.endsWith('.adoc')) pagePart += '.adoc' - } else if (target.endsWith('.adoc')) { - pagePart = target + } else if (~dollarIdx || target.endsWith('.adoc')) { + relativePart = target fragment = '' } else { fragment = target } - if (!pagePart) { + if (!relativePart) { // Q: should we validate the internal ID here? return text && ~text.indexOf('=') ? `xref:${idPrefix}${fragment}[${text}]` : `<<${idPrefix}${fragment}${text ? ',' + text.replace(/\\]/g, ']') : ''}>>` } - 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}]` + if (~dollarIdx) { + if (relativePart.slice(dollarIdx).startsWith('$./')) { + relativePart = relativePart.slice(0, dollarIdx + 1) + topicPrefix + relativePart.slice(dollarIdx + 3) } - // TODO: handle unresolved page better + if ((isPage = /\bpage\$/.test(relativePart))) relativePart = relativePart.replace('page$', '') + } else { + isPage = true + if (relativePart.startsWith('./')) relativePart = topicPrefix + relativePart.slice(2) + if (~hashIdx && !relativePart.endsWith('.adoc')) relativePart += '.adoc' + } + if (!isPage || ~relativePart.indexOf('@') || /:.*:/.test(relativePart)) { + if (siteUrl && (targetResource = contentCatalog.resolveResource(relativePart, page.src, 'page'))?.out) { + text ||= targetResource.asciidoc?.xreftext || target + return `${siteUrl}${targetResource.pub.url}${fragment && '#' + fragment}[${text}]` + } + // TODO: handle unresolved resource better return m } let targetModule - const colonIdx = pagePart.indexOf(':') + const colonIdx = relativePart.indexOf(':') if (~colonIdx) { - targetModule = pagePart.slice(0, colonIdx) - pagePart = pagePart.slice(colonIdx + 1) + targetModule = relativePart.slice(0, colonIdx) + relativePart = relativePart.slice(colonIdx + 1) + if (relativePart.startsWith('./')) relativePart = topicPrefix + relativePart.slice(2) } else { targetModule = module_ } - if (pagePart.startsWith('./')) pagePart = topicPrefix + pagePart.slice(2) - const pageResourceRef = targetModule === 'ROOT' ? pagePart : `${targetModule}:${pagePart}` - if (!(targetPage = pagesInOutline.get(pageResourceRef))) { - if (siteUrl && (targetPage = contentCatalog.resolvePage(pageResourceRef, page.src)) && targetPage.out) { - text ||= targetPage.asciidoc?.xreftext || target - return `${siteUrl}${targetPage.pub.url}${fragment && '#' + fragment}[${text}]` + const pageResourceRef = targetModule === 'ROOT' ? relativePart : `${targetModule}:${relativePart}` + if (!(targetResource = pagesInOutline.get(pageResourceRef))) { + if ( + siteUrl && + (targetResource = contentCatalog.resolvePage(pageResourceRef, page.src)) && + targetResource.out + ) { + text ||= targetResource.asciidoc?.xreftext || target + return `${siteUrl}${targetResource.pub.url}${fragment && '#' + fragment}[${text}]` } // TODO: handle unresolved page better return m } - if (targetModule !== 'ROOT') pagePart = `${targetModule}${idCoordinateSeparator}${pagePart}` - pagePart = pagePart.replace(/\.adoc$/, '').replace(/[/.]/g, '-') + if (targetModule !== 'ROOT') relativePart = `${targetModule}${idCoordinateSeparator}${relativePart}` + relativePart = relativePart.replace(/\.adoc$/, '').replace(/[/.]/g, '-') const refid = fragment - ? `${pagePart}${idScopeSeparator}${fragment}` - : pagePart + (ReservedIdNames.includes(pagePart) ? idScopeSeparator : '') - return `<<${refid}${text && text !== targetPage.title ? ',' + text.replace(/\\]/g, ']') : ''}>>` + ? `${relativePart}${idScopeSeparator}${fragment}` + : relativePart + (ReservedIdNames.includes(relativePart) ? idScopeSeparator : '') + return `<<${refid}${text && text !== targetResource.title ? ',' + text.replace(/\\]/g, ']') : ''}>>` }) } if (~line.indexOf('link:{attachmentsdir}/')) { diff --git a/packages/assembler/test/scenarios/attachment-reference/data.yml b/packages/assembler/test/scenarios/attachment-reference/data.yml index d37f917725bb4b484b1df54b46629ebee943b22c..5e1eaf29b688645ffa7b46d2295bb06e0d5771d8 100644 --- a/packages/assembler/test/scenarios/attachment-reference/data.yml +++ b/packages/assembler/test/scenarios/attachment-reference/data.yml @@ -14,7 +14,7 @@ files: - relative: intro.adoc family: partial contents: |- - contents + Download the xref:attachment$form.pdf[Form Title]. - relative: form.pdf family: attachment assembler: diff --git a/packages/assembler/test/scenarios/attachment-reference/expects/index.adoc b/packages/assembler/test/scenarios/attachment-reference/expects/index.adoc index 866ad402c678dbf883662ea8658224c5c9a2ccc7..61c08a145f725394231064d07352f6cb9408445e 100644 --- a/packages/assembler/test/scenarios/attachment-reference/expects/index.adoc +++ b/packages/assembler/test/scenarios/attachment-reference/expects/index.adoc @@ -19,7 +19,7 @@ [#the-page] == The Page Title -contents +Download the https://docs.example.org/the-component/1.0/_attachments/form.pdf[Form Title]. :!sectids: == https://docs.example.org/the-component/1.0/_attachments/form.pdf[Form Title]