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:
+ *
+ *
+ * -
+ *
+ *
+ * to:
+ *
+ *
+ * -
+ *
+ *
+ *
+ *
+ * */
+
+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",