Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepare the repo to include .adoc files from an URI #18

Merged
merged 1 commit into from
Nov 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions bin/makepdf
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,8 @@ function build_pdf_manual()

# Create argument list, necessary as we have dynamic attributes coming from another file
# The param string needs to be properly constructed, please be careful, see comment below.
# Note regarding the attribute: allow-uri-read
# For details read the comment in ./lib/extensions/remote-include-processor.js

param=''
param+='-d book '
Expand All @@ -263,6 +265,7 @@ function build_pdf_manual()
param+='-a partialsdir='$(pwd)/modules/${source_root}/pages/_partials/' '
param+='-a revnumber='${branch}' '
param+='-a revdate="'${release_date}'" '
param+='-a allow-uri-read="" '
param+="$attributes"' '
param+='--base-dir '$(pwd)' '
param+='--out-file '${build_directory}/${branch}_ownCloud_${manual_infix}_Manual.pdf' '
Expand Down
203 changes: 203 additions & 0 deletions lib/extensions/remote-include-processor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
/**
* This script mimics the capability of Asciidoc:
* Including content by URI in Antora
* https://docs.asciidoctor.org/asciidoc/latest/directives/include-uri/#reference-include-content-by-uri
* eg: include::https://raw.githubusercontent.com/asciidoctor/asciidoctor/master/README.adoc[]
*
* Note check if you need a leveloffset like [leveloffset=+1]
* This may be necessary for the makepdf script to avoid having the included content starting on a separate page.
*
* Note that the makepdf script needs to have the 'allow-uri-read="" ' attribute param set in the code.
*
* Note that no attributes in the included document can be resolved if they are defined outside of this repo
*
* Source:
* Add support for including content from a URL (i.e., remote include)
* https://gitlab.com/antora/antora/-/issues/246
* https://github.com/feelpp/book.feelpp.org/blob/master/lib/remote-include-processor.js
*/
const CIRCUMFIX_COMMENT_SUFFIX_RX = / (?:\*[/)]|--%?>)$/
const NEWLINE_RX = /\r\n?|\n/
const TAG_DELIMITER_RX = /[,;]/
const TAG_DIRECTIVE_RX = /\b(?:tag|(end))::(\S+)\[\]$/
const LINES_DOTDOT_RX = /\.\./


function getTags (attrs) {
if ( 'tag' in attrs ) {
const tag = attrs['tag']
if (tag && tag !== '!') {
return tag.charAt() === '!' ? new Map().set(tag.substr(1), false) : new Map().set(tag, true)
}
} else if ( 'tags' in attrs ) {
const tags = attrs['tags']
if (tags) {
let result = new Map()
let any = false
tags.split(TAG_DELIMITER_RX).forEach((tag) => {
if (tag && tag !== '!') {
any = true
tag.charAt() === '!' ? result.set(tag.substr(1), false) : result.set(tag, true)
}
})
if (any) return result
}
}
}


function applyTagFiltering (contents, tags) {
let selecting, selectingDefault, wildcard
if (tags.has('**')) {
if (tags.has('*')) {
selectingDefault = selecting = tags.get('**')
wildcard = tags.get('*')
tags.delete('*')
} else {
selectingDefault = selecting = wildcard = tags.get('**')
}
tags.delete('**')
} else {
selectingDefault = selecting = !Array.from(tags.values()).includes(true)
if (tags.has('*')) {
wildcard = tags.get('*')
tags.delete('*')
}
}

const lines = []
const tagStack = []
const usedTags = []
let activeTag
let lineNum = 0
let startLineNum
contents.split(NEWLINE_RX).forEach((line) => {
lineNum++
let m
let l = line
if (
(l.endsWith('[]') ||
(~l.indexOf('[] ') &&
(m = l.match(CIRCUMFIX_COMMENT_SUFFIX_RX)) &&
(l = l.substr(0, m.index)).endsWith('[]'))) &&
(m = l.match(TAG_DIRECTIVE_RX))
) {
const thisTag = m[2]
if (m[1]) {
if (thisTag === activeTag) {
tagStack.shift()
;[activeTag, selecting] = tagStack.length ? tagStack[0] : [undefined, selectingDefault]
} else if (tags.has(thisTag)) {
const idx = tagStack.findIndex(([name]) => name === thisTag)
if (~idx) {
tagStack.splice(idx, 1)
//console.warn(`line ${lineNum}: mismatched end tag in include: expected ${activeTag}, found ${thisTag}`)
}
//} else {
// //console.warn(`line ${lineNum}: unexpected end tag in include: ${thisTag}`)
//}
}
} else if (tags.has(thisTag)) {
usedTags.push(thisTag)
tagStack.unshift([(activeTag = thisTag), (selecting = tags.get(thisTag))])
} else if (wildcard !== undefined) {
selecting = activeTag && !selecting ? false : wildcard
tagStack.unshift([(activeTag = thisTag), selecting])
}
} else if (selecting) {
if (!startLineNum) startLineNum = lineNum
lines.push(line)
}
})
// Q: use _.difference(Object.keys(tags), usedTags)?
//const missingTags = Object.keys(tags).filter((e) => !usedTags.includes(e))
//if (missingTags.length) {
// console.warn(`tag${missingTags.length > 1 ? 's' : ''} '${missingTags.join(',')}' not found in include`)
//}
return [lines, startLineNum || 1]
}


function getLines (attrs) {
if ( 'lines' in attrs ) {
const lines = attrs['lines']
if (lines) {
// console.warn(`have lines` + lines)
let result = [] // new Map()
let any = false
lines.split(TAG_DELIMITER_RX).forEach((line) => {
if (line && line !== '!') {
let tryMultipleLines = line.split(LINES_DOTDOT_RX)
if ( tryMultipleLines.length === 1 ) {
any = true
result.push([tryMultipleLines[0], tryMultipleLines[0]])
}
else if ( tryMultipleLines.length === 2 ) {
any = true
result.push([tryMultipleLines[0], tryMultipleLines[1]])
}
}
})
if (any) return result
}
}
}

function applyLineFiltering (contents, linesToInclude) {
const lines = []
let lineNum = 0
let startLineNum
let registerCurrentLine = false

const nLinesPair = linesToInclude.length
let currentLinePair = 0
let startLine = linesToInclude[currentLinePair][0]
let endLine = linesToInclude[currentLinePair][1]
// console.warn(`applyLineFiltering ` + startLine + ' and ' + endLine )

contents.split(NEWLINE_RX).forEach((line) => {
lineNum++

if ( !registerCurrentLine ) {
if ( lineNum == startLine )
registerCurrentLine = true
}

if ( registerCurrentLine )
{
if (!startLineNum) startLineNum = lineNum
lines.push(line)

if ( lineNum == endLine ) {
registerCurrentLine = false
currentLinePair++
if ( currentLinePair >= nLinesPair )
return [lines, startLineNum]
else {
startLine = linesToInclude[currentLinePair][0]
endLine = linesToInclude[currentLinePair][1]
}
}
}
})
return [lines, startLineNum || 1]
}

module.exports = function () {
this.includeProcessor(function () {
this.$option('position', '>>')
this.handles((target) => target.startsWith('https://'))
this.process((doc, reader, target, attrs) => {
const contents = require('child_process').execFileSync('curl', ['--silent', '-L', target], { encoding: 'utf8' })
let includeContents = contents
let startLineNum = 1
const tags = getTags(attrs)
const lines = getLines(attrs)
if (tags) [includeContents, startLineNum] = applyTagFiltering(includeContents, tags)
else if (lines) [includeContents, startLineNum] = applyLineFiltering(includeContents, lines)
reader.pushInclude(includeContents, target, target, startLineNum, attrs)
// reader.pushInclude(contents, target, target, 1, attrs)
})
})
}

1 change: 1 addition & 0 deletions site.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ asciidoc:
previous-ios-app-version: 11.7
extensions:
- ./lib/extensions/tabs.js
- ./lib/extensions/remote-include-processor.js
- ./node_modules/asciidoctor-kroki/src/asciidoctor-kroki.js