diff --git a/lib/render-content/create-processor.js b/lib/render-content/create-processor.js index e083f8da10..98e975645d 100644 --- a/lib/render-content/create-processor.js +++ b/lib/render-content/create-processor.js @@ -20,16 +20,10 @@ import rewriteLocalLinks from './plugins/rewrite-local-links.js' import rewriteImgSources from './plugins/rewrite-asset-urls.js' import rewriteAssetImgTags from './plugins/rewrite-asset-img-tags.js' import useEnglishHeadings from './plugins/use-english-headings.js' -import wrapInElement from './plugins/wrap-in-element.js' import headingLinks from './plugins/heading-links.js' import rewriteTheadThScope from './plugins/rewrite-thead-th-scope.js' import rewriteForRowheaders from './plugins/rewrite-for-rowheaders.js' - -// plugins aren't designed to be used more than once, -// this workaround lets us do that -// see https://github.com/unifiedjs/unified/issues/79 -const wrapperForImages = () => - wrapInElement({ selector: 'ol > li img', wrapper: 'span.procedural-image-wrapper' }) +import wrapProceduralImages from './plugins/wrap-procedural-images.js' export default function createProcessor(context) { return unified() @@ -46,7 +40,7 @@ export default function createProcessor(context) { subset: false, }) .use(raw) - .use(wrapperForImages) + .use(wrapProceduralImages) .use(rewriteTheadThScope) .use(rewriteForRowheaders) .use(rewriteImgSources) diff --git a/lib/render-content/plugins/wrap-in-element.js b/lib/render-content/plugins/wrap-in-element.js deleted file mode 100644 index 3fc7bc4399..0000000000 --- a/lib/render-content/plugins/wrap-in-element.js +++ /dev/null @@ -1,45 +0,0 @@ -import { visit } from 'unist-util-visit' -import { selectAll } from 'hast-util-select' -import { parseSelector } from 'hast-util-parse-selector' - -/* - * Attacher - */ -export default (options) => { - const selector = options.selector || options.select || 'body' - const wrapper = options.wrapper || options.wrap - const rewrite = options.rewrite - const additionalAttributes = options.wrapperAdditionalAttributes - - /* - * Transformer - */ - return (tree) => { - if (wrapper && typeof wrapper !== 'string') { - throw new TypeError('Expected a `string` as wrapper') - } - - if (typeof selector !== 'string') { - throw new TypeError('Expected a `string` as selector') - } - - for (const match of selectAll(selector, tree)) { - visit(tree, match, (node, i, parent) => { - const parsedWrapper = parseSelector(wrapper) - if (additionalAttributes) { - parsedWrapper.properties = Object.assign( - {}, - parsedWrapper.properties || {}, - additionalAttributes - ) - } - if (rewrite) { - parsedWrapper.children = node.children - } else { - parsedWrapper.children = [node] - } - parent.children[i] = parsedWrapper - }) - } - } -} diff --git a/lib/render-content/plugins/wrap-procedural-images.js b/lib/render-content/plugins/wrap-procedural-images.js new file mode 100644 index 0000000000..a4b22b6abd --- /dev/null +++ b/lib/render-content/plugins/wrap-procedural-images.js @@ -0,0 +1,51 @@ +import { visitParents } from 'unist-util-visit-parents' + +/** + * Where it can mutate the AST to swap from: + * + *
    + *
  1. + * + * + * to: + * + *
      + *
    1. + * + * + * + * + * */ + +function matcher(node) { + return node.type === 'element' && node.tagName === 'img' +} + +function insideOlLi(ancestors) { + const li = ancestors.findIndex((node) => node.tagName === 'li') + if (li > -1) { + const ol = ancestors.slice(0, li).findIndex((node) => node.tagName === 'ol') + return ol > -1 + } + return false +} + +function visitor(node, ancestors) { + if (insideOlLi(ancestors)) { + const shallowClone = Object.assign({}, node) + shallowClone.tagName = 'span' + shallowClone.properties = { class: 'procedural-image-wrapper' } + shallowClone.children = [node] + const parent = ancestors.at(-1) + parent.children = parent.children.map((child) => { + if (child.tagName === 'img') { + return shallowClone + } + return child + }) + } +} + +export default function wrapProceduralImages() { + return (tree) => visitParents(tree, matcher, visitor) +} diff --git a/package-lock.json b/package-lock.json index fe783f940a..dfbc46c206 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,8 +39,6 @@ "got": "^13.0.0", "gray-matter": "^4.0.3", "hast-util-from-parse5": "^7.1.0", - "hast-util-parse-selector": "^3.1.0", - "hast-util-select": "^5.0.2", "hast-util-to-string": "^2.0.0", "hastscript": "^7.0.2", "helmet": "^7.0.0", @@ -6219,14 +6217,6 @@ "node": ">= 0.8" } }, - "node_modules/bcp-47-match": { - "version": "2.0.0", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/before-after-hook": { "version": "2.2.2", "dev": true, @@ -7230,10 +7220,6 @@ "url": "https://github.com/sponsors/fb55" } }, - "node_modules/css-selector-parser": { - "version": "1.4.1", - "license": "MIT" - }, "node_modules/css-to-react-native": { "version": "3.0.0", "license": "MIT", @@ -7603,17 +7589,6 @@ "node": ">=8" } }, - "node_modules/direction": { - "version": "2.0.0", - "license": "MIT", - "bin": { - "direction": "cli.js" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/doctrine": { "version": "3.0.0", "dev": true, @@ -9952,32 +9927,6 @@ "version": "6.0.1", "license": "MIT" }, - "node_modules/hast-util-select": { - "version": "5.0.2", - "license": "MIT", - "dependencies": { - "@types/hast": "^2.0.0", - "@types/unist": "^2.0.0", - "bcp-47-match": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "css-selector-parser": "^1.0.0", - "direction": "^2.0.0", - "hast-util-has-property": "^2.0.0", - "hast-util-is-element": "^2.0.0", - "hast-util-to-string": "^2.0.0", - "hast-util-whitespace": "^2.0.0", - "not": "^0.1.0", - "nth-check": "^2.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0", - "unist-util-visit": "^4.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/hast-util-to-html": { "version": "8.0.2", "license": "MIT", @@ -15141,9 +15090,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/not": { - "version": "0.1.0" - }, "node_modules/npm-merge-driver-install": { "version": "3.0.0", "dev": true, @@ -23565,9 +23511,6 @@ "safe-buffer": "5.1.2" } }, - "bcp-47-match": { - "version": "2.0.0" - }, "before-after-hook": { "version": "2.2.2", "dev": true @@ -24198,9 +24141,6 @@ "nth-check": "^2.0.1" } }, - "css-selector-parser": { - "version": "1.4.1" - }, "css-to-react-native": { "version": "3.0.0", "requires": { @@ -24417,9 +24357,6 @@ "path-type": "^4.0.0" } }, - "direction": { - "version": "2.0.0" - }, "doctrine": { "version": "3.0.0", "dev": true, @@ -25973,27 +25910,6 @@ } } }, - "hast-util-select": { - "version": "5.0.2", - "requires": { - "@types/hast": "^2.0.0", - "@types/unist": "^2.0.0", - "bcp-47-match": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "css-selector-parser": "^1.0.0", - "direction": "^2.0.0", - "hast-util-has-property": "^2.0.0", - "hast-util-is-element": "^2.0.0", - "hast-util-to-string": "^2.0.0", - "hast-util-whitespace": "^2.0.0", - "not": "^0.1.0", - "nth-check": "^2.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0", - "unist-util-visit": "^4.0.0", - "zwitch": "^2.0.0" - } - }, "hast-util-to-html": { "version": "8.0.2", "requires": { @@ -29527,9 +29443,6 @@ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==" }, - "not": { - "version": "0.1.0" - }, "npm-merge-driver-install": { "version": "3.0.0", "dev": true diff --git a/package.json b/package.json index cbbea70ac4..28bd3c0daf 100644 --- a/package.json +++ b/package.json @@ -86,8 +86,6 @@ "got": "^13.0.0", "gray-matter": "^4.0.3", "hast-util-from-parse5": "^7.1.0", - "hast-util-parse-selector": "^3.1.0", - "hast-util-select": "^5.0.2", "hast-util-to-string": "^2.0.0", "hastscript": "^7.0.2", "helmet": "^7.0.0",