diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8f9f9da99..171ebddcb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,13 +8,13 @@ jobs: matrix: os: [ubuntu-latest] node-version: [12.x, 14.x] - asciidoctor-core-version: [v2.0.17, main] + asciidoctor-core-version: [v2.0.22, main] experimental: [false] include: - node-version: 14.x os: macos-latest experimental: true - asciidoctor-core-version: v2.0.17 + asciidoctor-core-version: v2.0.22 runs-on: ${{ matrix.os }} continue-on-error: ${{ matrix.experimental }} steps: @@ -46,7 +46,7 @@ jobs: node-version: - 12.x - 14.x - asciidoctor-core-version: [v2.0.17, main] + asciidoctor-core-version: [v2.0.22, main] steps: - uses: actions/checkout@v2 - name: Set up Node ${{ matrix.node-version }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9ca69cd40..f79fb5b0c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,7 +23,7 @@ jobs: npm ci --prefix packages/core - name: Lint, build and test env: - ASCIIDOCTOR_CORE_VERSION: v2.0.17 + ASCIIDOCTOR_CORE_VERSION: v2.0.22 run: | npm run lint npm run test @@ -51,7 +51,7 @@ jobs: # package and publish - name: Package env: - ASCIIDOCTOR_CORE_VERSION: v2.0.17 + ASCIIDOCTOR_CORE_VERSION: v2.0.22 run: ./scripts/package.sh - name: Publish env: diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 524939508..ae4b287e1 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -8,6 +8,30 @@ For a detailed view of what has changed, refer to the {uri-repo}/commits/master[ == Unreleased +Improvements:: +* Build against the latest release of Asciidoctor 2.0.22 + +== 2.2.6 (2022-01-21) + +Bug Fixes:: +* Fix global variable leak by @mojavelinux in #1494 (backport) +* Bridge common Ruby object methods by @ggrossetie in #1550 + +Improvements:: +* Build against the latest release of Asciidoctor 2.0.17 + +Infrastructure:: +* Build against Asciidoctor 2.0.17 by @ggrossetie in #1540 +* Upgrade development dependencies by @ggrossetie in #1549 +* Retrieve upstream from main branch by @mojavelinux in #1495 + +Documentation:: +* Fix 404 links to the GraalVM docs by @StarfallProjects in #1413 +* Rename "JSDoc" to "API Reference" and add link to extension API reference by @hqurve in #1447 +* Update HTML5Converter instantiation method in docs by @danyill in #1437 + +== 2.2.5 (2021-08-08) + Bug Fixes:: * Invoke `LoggerManager#setLogger` setter - thanks @mojavelinux (#1322) diff --git a/packages/core/lib/asciidoctor/js/opal_ext.rb b/packages/core/lib/asciidoctor/js/opal_ext.rb index fe218fc2a..278757916 100644 --- a/packages/core/lib/asciidoctor/js/opal_ext.rb +++ b/packages/core/lib/asciidoctor/js/opal_ext.rb @@ -2,6 +2,7 @@ require 'asciidoctor/js/opal_ext/file' require 'asciidoctor/js/opal_ext/match_data' require 'asciidoctor/js/opal_ext/string' +require 'asciidoctor/js/opal_ext/array' require 'asciidoctor/js/opal_ext/uri' require 'asciidoctor/js/opal_ext/base64' require 'asciidoctor/js/opal_ext/number' diff --git a/packages/core/lib/asciidoctor/js/opal_ext/array.rb b/packages/core/lib/asciidoctor/js/opal_ext/array.rb new file mode 100644 index 000000000..d703dfc9e --- /dev/null +++ b/packages/core/lib/asciidoctor/js/opal_ext/array.rb @@ -0,0 +1,11 @@ +class Array + alias :_original_pack :pack + + def pack format + if format == 'm0' + ::Base64.strict_encode64 self + else + _original_pack self + end + end +end diff --git a/packages/core/lib/asciidoctor/js/postscript.rb b/packages/core/lib/asciidoctor/js/postscript.rb index fe5f3bf25..8050f0056 100644 --- a/packages/core/lib/asciidoctor/js/postscript.rb +++ b/packages/core/lib/asciidoctor/js/postscript.rb @@ -4,3 +4,5 @@ require 'asciidoctor/js/asciidoctor_ext' require 'asciidoctor/js/opal_ext/logger' # override the built-in Logger + +Asciidoctor::InlineLinkRx = %r((^|link:|#{Asciidoctor::CG_BLANK}|\\?<(?=\\?(?:https?|file|ftp|irc)(:))|[>\(\)\[\];"'])(\\?(?:https?|file|ftp|irc)://)(?:([^\s\[\]]+)\[(|#{Asciidoctor::CC_ALL}*?[^\\])\]|(?!\2)([^\s]*?)>|([^\s\[\]<]*([^\s,.?!\[\]<\)])))) diff --git a/packages/core/types/tests.ts b/packages/core/types/tests.ts index a47294a16..d8ec8662a 100644 --- a/packages/core/types/tests.ts +++ b/packages/core/types/tests.ts @@ -207,160 +207,164 @@ assert(fooExtensionsRegistry.hasPreprocessors()); assert(fooExtensionsRegistry.hasTreeProcessors()); const docinfoProcessors = fooExtensionsRegistry.getDocinfoProcessors('head'); assert(docinfoProcessors.length === 1); -const testRegistry = processor.Extensions.create('test', function() { - this.inlineMacro('attrs', function() { - const self = this; - self.matchFormat('short'); - self.defaultAttributes({1: 'a', 2: 'b', foo: 'baz'}); - self.positionalAttributes('a', 'b'); - self.process(function(parent, _, attrs) { - return this.createInline(parent, 'quoted', `a=${attrs['a']},2=${attrs[2]},b=${attrs['b'] || 'nil'},foo=${attrs['foo']}`); + +function createTestRegistry(): Asciidoctor.Extensions.Registry { + const testRegistry = processor.Extensions.create('test', function () { + this.inlineMacro('attrs', function () { + const self = this; + self.matchFormat('short'); + self.defaultAttributes({1: 'a', 2: 'b', foo: 'baz'}); + self.positionalAttributes('a', 'b'); + self.process(function (parent, _, attrs) { + return this.createInline(parent, 'quoted', `a=${attrs['a']},2=${attrs[2]},b=${attrs['b'] || 'nil'},foo=${attrs['foo']}`); + }); }); - }); - this.blockMacro(function() { - this.named('test'); - this.process(function(parent) { - return this.createBlock(parent, 'paragraph', 'this was only a test'); + this.blockMacro(function () { + this.named('test'); + this.process(function (parent) { + return this.createBlock(parent, 'paragraph', 'this was only a test'); + }); }); - }); - this.block('yell', function() { - this.onContext('paragraph'); - this.positionalAttributes('chars'); - this.parseContentAs('simple'); - this.process(function(parent, reader, attributes) { - const chars = attributes['chars']; - const lines = reader.getLines(); - if (chars) { - const regexp = new RegExp(`[${chars}]`, 'g'); - return this.createParagraph(parent, lines.map((l) => l.toLowerCase().replace(regexp, (m) => m.toUpperCase())), attributes); - } else { - const source = lines.map((l) => l.toUpperCase()); - return this.createParagraph(parent, source, attributes); - } + this.block('yell', function () { + this.onContext('paragraph'); + this.positionalAttributes('chars'); + this.parseContentAs('simple'); + this.process(function (parent, reader, attributes) { + const chars = attributes['chars']; + const lines = reader.getLines(); + if (chars) { + const regexp = new RegExp(`[${chars}]`, 'g'); + return this.createParagraph(parent, lines.map((l) => l.toLowerCase().replace(regexp, (m) => m.toUpperCase())), attributes); + } else { + const source = lines.map((l) => l.toUpperCase()); + return this.createParagraph(parent, source, attributes); + } + }); }); - }); - this.block('todo-list', function() { - this.onContext('paragraph'); - this.parseContentAs('simple'); - this.process(function(parent, reader) { - const list = this.createList(parent, 'ulist'); - const lines = reader.getLines(); - for (const line of lines) { - list.append(this.createListItem(list, line)); - } - list.append(this.createListItem(list)); - parent.append(list); + this.block('todo-list', function () { + this.onContext('paragraph'); + this.parseContentAs('simple'); + this.process(function (parent, reader) { + const list = this.createList(parent, 'ulist'); + const lines = reader.getLines(); + for (const line of lines) { + list.append(this.createListItem(list, line)); + } + list.append(this.createListItem(list)); + parent.append(list); + }); }); - }); - this.blockMacro(function() { - this.named('img'); - this.process(function(parent, target) { - return this.createImageBlock(parent, {target: target + '.png', title: 'title', caption: 'caption'}); + this.blockMacro(function () { + this.named('img'); + this.process(function (parent, target) { + return this.createImageBlock(parent, {target: target + '.png', title: 'title', caption: 'caption'}); + }); }); - }); - this.blockMacro(function() { - this.named('open'); - this.process(function(parent, target) { - const block = this.createOpenBlock(parent); - block.append(this.createParagraph(parent, target)); - return block; + this.blockMacro(function () { + this.named('open'); + this.process(function (parent, target) { + const block = this.createOpenBlock(parent); + block.append(this.createParagraph(parent, target)); + return block; + }); }); - }); - this.blockMacro(function() { - this.named('example'); - this.process(function(parent, target) { - return this.createExampleBlock(parent, target); + this.blockMacro(function () { + this.named('example'); + this.process(function (parent, target) { + return this.createExampleBlock(parent, target); + }); }); - }); - this.blockMacro(function() { - this.named('span'); - this.process(function(parent, target) { - return this.createPassBlock(parent, `${target}`); + this.blockMacro(function () { + this.named('span'); + this.process(function (parent, target) { + return this.createPassBlock(parent, `${target}`); + }); }); - }); - this.blockMacro(function() { - this.named('listing'); - this.process(function(parent, target) { - return this.createListingBlock(parent, `console.log('${target}')`); + this.blockMacro(function () { + this.named('listing'); + this.process(function (parent, target) { + return this.createListingBlock(parent, `console.log('${target}')`); + }); }); - }); - this.blockMacro(function() { - this.named('literal'); - this.process(function(parent, target) { - return this.createLiteralBlock(parent, target); + this.blockMacro(function () { + this.named('literal'); + this.process(function (parent, target) { + return this.createLiteralBlock(parent, target); + }); }); - }); - this.inlineMacro(function() { - this.named('mention'); - this.resolveAttributes(false); - this.process(function(parent, target, attrs) { - const text = attrs.text ? attrs.text : target; - return this.createAnchor(parent, text, {type: 'link', target: `https://github.com/${target}`}); + this.inlineMacro(function () { + this.named('mention'); + this.resolveAttributes(false); + this.process(function (parent, target, attrs) { + const text = attrs.text ? attrs.text : target; + return this.createAnchor(parent, text, {type: 'link', target: `https://github.com/${target}`}); + }); }); - }); - this.inlineMacro(function() { - this.named('say'); - this.process(function(parent, target) { - return this.createInlinePass(parent, `*${target}*`, {attributes: {subs: 'normal'}}); + this.inlineMacro(function () { + this.named('say'); + this.process(function (parent, target) { + return this.createInlinePass(parent, `*${target}*`, {attributes: {subs: 'normal'}}); + }); }); - }); - this.inlineMacro(function() { - this.named('@mention'); - this.match(/@(\w+)/); - this.process(function(parent, target) { - const mentionsUriPattern = parent.getDocument().getAttribute('mentions-uri-pattern') || 'https://github.com/%s'; - const mentionsUri = mentionsUriPattern.replace('%s', target); - return this.createAnchor(parent, `@${target}`, {type: 'link', target: mentionsUri}); + this.inlineMacro(function () { + this.named('@mention'); + this.match(/@(\w+)/); + this.process(function (parent, target) { + const mentionsUriPattern = parent.getDocument().getAttribute('mentions-uri-pattern') || 'https://github.com/%s'; + const mentionsUri = mentionsUriPattern.replace('%s', target); + return this.createAnchor(parent, `@${target}`, {type: 'link', target: mentionsUri}); + }); }); }); -}); -const PackageInlineMacro = processor.Extensions.createInlineMacroProcessor('PackageInlineMacro', { - initialize(name, config) { - this.DEFAULT_PACKAGE_URL_FORMAT = config.defaultPackageUrlFormat || 'https://packages.ubuntu.com/bionic/%s'; - this.super(name, config); - }, - process(parent, target) { - const format = parent.getDocument().getAttribute('url-package-url-format', this.DEFAULT_PACKAGE_URL_FORMAT); - const url = format.replace('%s', target); - const content = target; - const attributes = {window: '_blank'}; - return this.createInline(parent, 'anchor', content, {type: 'link', target: url, attributes}); - } -}); -const inlineMacroProcessorInstance = PackageInlineMacro.$new('package', {defaultPackageUrlFormat: 'https://apps.fedoraproject.org/packages/%s'}); -assert(inlineMacroProcessorInstance.getConfig().defaultPackageUrlFormat === 'https://apps.fedoraproject.org/packages/%s'); -assert(inlineMacroProcessorInstance.getName() === 'package'); -testRegistry.inlineMacro(inlineMacroProcessorInstance); -testRegistry.inlineMacro('pkg', function() { - this.option('defaultPackageUrlFormat', 'https://apps.fedoraproject.org/packages/%s'); - this.process(function(parent, target) { - const format = parent.getDocument().getAttribute('url-package-url-format', this.getConfig().defaultPackageUrlFormat); - const url = format.replace('%s', target); - const content = target; - const attributes = {window: '_blank'}; - return this.createInline(parent, 'anchor', content, {type: 'link', target: url, attributes}); + const PackageInlineMacro = processor.Extensions.createInlineMacroProcessor('PackageInlineMacro', { + initialize(name, config) { + this.DEFAULT_PACKAGE_URL_FORMAT = config.defaultPackageUrlFormat || 'https://packages.ubuntu.com/bionic/%s'; + this.super(name, config); + }, + process(parent, target) { + const format = parent.getDocument().getAttribute('url-package-url-format', this.DEFAULT_PACKAGE_URL_FORMAT); + const url = format.replace('%s', target); + const content = target; + const attributes = {window: '_blank'}; + return this.createInline(parent, 'anchor', content, {type: 'link', target: url, attributes}); + } }); -}); -testRegistry.includeProcessor(processor.Extensions.newIncludeProcessor('StaticIncludeProcessor', { - process(doc, reader, target, attrs) { - reader.pushInclude(['included content'], target, target, 1, attrs); - } -})); -const includeProcessor = processor.Extensions.createIncludeProcessor('StaticIncludeProcessor', { - initialize(value) { - this.value = value; - this.super(); - }, - postConstruct() { - this.bar = 'bar'; - }, - process(doc, reader, target, attrs) { - reader.pushInclude([this.value + this.bar], target, target, 1, attrs); - } -}); -const includeProcessorInstance = includeProcessor.$new('foo'); -testRegistry.includeProcessor(includeProcessorInstance); + const inlineMacroProcessorInstance = PackageInlineMacro.$new('package', {defaultPackageUrlFormat: 'https://apps.fedoraproject.org/packages/%s'}); + assert(inlineMacroProcessorInstance.getConfig().defaultPackageUrlFormat === 'https://apps.fedoraproject.org/packages/%s'); + assert(inlineMacroProcessorInstance.getName() === 'package'); + testRegistry.inlineMacro(inlineMacroProcessorInstance); + testRegistry.inlineMacro('pkg', function () { + this.option('defaultPackageUrlFormat', 'https://apps.fedoraproject.org/packages/%s'); + this.process(function (parent, target) { + const format = parent.getDocument().getAttribute('url-package-url-format', this.getConfig().defaultPackageUrlFormat); + const url = format.replace('%s', target); + const content = target; + const attributes = {window: '_blank'}; + return this.createInline(parent, 'anchor', content, {type: 'link', target: url, attributes}); + }); + }); + testRegistry.includeProcessor(processor.Extensions.newIncludeProcessor('StaticIncludeProcessor', { + process(doc, reader, target, attrs) { + reader.pushInclude(['included content'], target, target, 1, attrs); + } + })); + const includeProcessor = processor.Extensions.createIncludeProcessor('StaticIncludeProcessor', { + initialize(value) { + this.value = value; + this.super(); + }, + postConstruct() { + this.bar = 'bar'; + }, + process(doc, reader, target, attrs) { + reader.pushInclude([this.value + this.bar], target, target, 1, attrs); + } + }); + const includeProcessorInstance = includeProcessor.$new('foo'); + testRegistry.includeProcessor(includeProcessorInstance); + return testRegistry; +} const SelfSigningTreeProcessor = processor.Extensions.createTreeProcessor('SelfSigningTreeProcessor', { process(document) { @@ -404,21 +408,32 @@ try { processor.Extensions.unregisterAll(); } +const testRegistry = createTestRegistry(); const groups = testRegistry.getGroups(); assert(Object.keys(groups)[0] === 'test'); -const opts = {extension_registry: testRegistry, header_footer: false, safe: 'safe'}; - -let html = processor.convert('test::[]', opts); +let html = processor.convert('test::[]', { + extension_registry: testRegistry, + standalone: false, + safe: 'safe' +}); assert(html === `

this was only a test

`); -html = processor.convert('attrs:[A,foo=bar]', opts); +html = processor.convert('attrs:[A,foo=bar]', { + extension_registry: createTestRegistry(), + standalone: false, + safe: 'safe' +}); assert(html === `

a=A,2=b,b=nil,foo=bar

`); -html = processor.convert('Install package:asciidoctor[]', opts); +html = processor.convert('Install package:asciidoctor[]', { + extension_registry: createTestRegistry(), + standalone: false, + safe: 'safe' +}); assert(html === `

Install asciidoctor

`); @@ -428,7 +443,11 @@ Hi there! [yell,chars=aeiou] Hi there! -`, opts); +`, { + extension_registry: createTestRegistry(), + standalone: false, + safe: 'safe' +}); assert(html === `

HI THERE!

@@ -440,7 +459,11 @@ html = processor.convert(` [todo-list] redesign website do some nerdy stuff -`, opts); +`, { + extension_registry: createTestRegistry(), + standalone: false, + safe: 'safe' +}); assert(html === `
`); -html = processor.convert('@mojavelinux', opts); +html = processor.convert('@mojavelinux', { + extension_registry: createTestRegistry(), + standalone: false, + safe: 'safe' +}); assert(html === `

@mojavelinux

`); -const docWithImage = processor.load('img::image-name[]', opts); +const docWithImage = processor.load('img::image-name[]', { + extension_registry: createTestRegistry(), + standalone: false, + safe: 'safe' +}); let images = docWithImage.findBy((b) => b.getContext() === 'image'); assert(images.length === 1); assert(images[0].getTitle() === 'title'); @@ -469,7 +500,11 @@ images = docWithImage.findBy({context: 'image'}); assert(images.length === 1); assert(images[0].getTitle() === 'title'); assert(images[0].getCaption() === 'caption'); -html = docWithImage.convert(opts); +html = docWithImage.convert({ + extension_registry: createTestRegistry(), + standalone: false, + safe: 'safe' +}); assert(html === `
image name @@ -501,7 +536,7 @@ assert(result[0].getContext() === 'paragraph'); assert(result[1].getContext() === 'paragraph'); testRegistry.unregister('test'); -html = processor.convert('test::[]', {header_footer: false}); +html = processor.convert('test::[]', {standalone: false, extension_registry: testRegistry}); assert(html === `

test::[]

`); @@ -561,7 +596,7 @@ Guillaume Grossetie == Write in AsciiDoc! AsciiDoc is about being able to focus on expressing your ideas, writing with ease and passing on knowledge without the distraction of complex applications or angle brackets. -In other words, it’s about discovering writing zen.`, {safe: 'safe', header_footer: true, backend: 'blog'}) as string; +In other words, it’s about discovering writing zen.`, {safe: 'safe', standalone: true, backend: 'blog'}) as string; assert(blogResult.includes('Guillaume Grossetie')); // custom blog converter assert(blogResult.includes('
')); // built-in HTML5 converter