diff options
| author | Shipwreckt <me@shipwreckt.co.uk> | 2025-10-31 20:02:14 +0000 |
|---|---|---|
| committer | Shipwreckt <me@shipwreckt.co.uk> | 2025-10-31 20:02:14 +0000 |
| commit | 7a52ddeba2a68388b544f529d2d92104420f77b0 (patch) | |
| tree | 15ddd47457a2cb4a96060747437d36474e4f6b4e /node_modules/posthtml/lib | |
| parent | 53d6ae2b5568437afa5e4995580a3fb679b7b91b (diff) | |
Changed from static to 11ty!
Diffstat (limited to 'node_modules/posthtml/lib')
| -rw-r--r-- | node_modules/posthtml/lib/api.js | 145 | ||||
| -rw-r--r-- | node_modules/posthtml/lib/index.js | 323 |
2 files changed, 468 insertions, 0 deletions
diff --git a/node_modules/posthtml/lib/api.js b/node_modules/posthtml/lib/api.js new file mode 100644 index 0000000..e929cfb --- /dev/null +++ b/node_modules/posthtml/lib/api.js @@ -0,0 +1,145 @@ +'use strict' + +/** + * # API + * + * @author Ivan Voischev (@voischev), + * Anton Winogradov (@awinogradov), + * Alexej Yaroshevich (@zxqfox), + * Vasiliy (@Yeti-or) + * + * @namespace tree + */ +function Api () { + this.walk = walk + this.match = match +} + +/** + * Walks the tree and passes all nodes via a callback + * + * @memberof tree + * + * @param {Function} cb Callback + * @return {Function} Callback(node) + * + *@example + * ```js + * export const walk = (tree) => { + * tree.walk((node) => { + * let classes = node.attrs && node.attrs.class.split(' ') || [] + * + * if (classes.includes(className)) return cb(node) + * return node + * }) + * } + * ``` + */ +function walk (cb) { + return traverse(this, cb) +} + +/** + * Matches an expression to search for nodes in the tree + * + * @memberof tree + * + * @param {String|RegExp|Object|Array} expression - Matcher(s) to search + * @param {Function} cb Callback + * + * @return {Function} Callback(node) + * + * @example + * ```js + * export const match = (tree) => { + * // Single matcher + * tree.match({ tag: 'custom-tag' }, (node) => { + * let tag = node.tag + * + * Object.assign(node, { tag: 'div', attrs: {class: tag} }) + * + * return node + * }) + * // Multiple matchers + * tree.match([{ tag: 'b' }, { tag: 'strong' }], (node) => { + * let style = 'font-weight: bold;' + * + * node.tag = 'span' + * + * node.attrs + * ? ( node.attrs.style + * ? ( node.attrs.style += style ) + * : node.attrs.style = style + * ) + * : node.attrs = { style: style } + * + * return node + * }) + * } + * ``` + */ +function match (expression, cb) { + return Array.isArray(expression) + ? traverse(this, node => { + for (let i = 0; i < expression.length; i++) { + if (compare(expression[i], node)) return cb(node) + } + + return node + }) + : traverse(this, node => { + if (compare(expression, node)) return cb(node) + + return node + }) +} + +module.exports = Api +module.exports.match = match +module.exports.walk = walk + +/** @private */ +function traverse (tree, cb) { + if (Array.isArray(tree)) { + for (let i = 0; i < tree.length; i++) { + tree[i] = traverse(cb(tree[i]), cb) + } + } else if ( + tree && + typeof tree === 'object' && + Object.prototype.hasOwnProperty.call(tree, 'content') + ) traverse(tree.content, cb) + + return tree +} + +/** @private */ +function compare (expected, actual) { + if (expected instanceof RegExp) { + if (typeof actual === 'object') return false + if (typeof actual === 'string') return expected.test(actual) + } + + if (typeof expected !== typeof actual) return false + if (typeof expected !== 'object' || expected === null) { + return expected === actual + } + + if (Array.isArray(expected)) { + return expected.every(exp => [].some.call(actual, act => compare(exp, act))) + } + + return Object.keys(expected).every(key => { + const ao = actual[key] + const eo = expected[key] + + if (typeof eo === 'object' && eo !== null && ao !== null) { + return compare(eo, ao) + } + if (typeof eo === 'boolean') { + return eo !== (ao == null) + } + + return ao === eo + }) +} diff --git a/node_modules/posthtml/lib/index.js b/node_modules/posthtml/lib/index.js new file mode 100644 index 0000000..542c347 --- /dev/null +++ b/node_modules/posthtml/lib/index.js @@ -0,0 +1,323 @@ +const pkg = require('../package.json') +const Api = require('./api.js') + +let { parser } = require('posthtml-parser') +let { render } = require('posthtml-render') + +/** + * @author Ivan Voischev (@voischev), + * Ivan Demidov (@scrum) + * + * @requires api + * @requires posthtml-parser + * @requires posthtml-render + * + * @constructor PostHTML + * @param {Array} plugins - An array of PostHTML plugins + */ +class PostHTML { + constructor (plugins) { + /** + * PostHTML Instance + * + * @prop plugins + * @prop options + */ + this.version = pkg.version + this.name = pkg.name + this.plugins = typeof plugins === 'function' ? [plugins] : plugins || [] + this.source = '' + + /** + * Tree messages to store and pass metadata between plugins + * + * @memberof tree + * @type {Array} messages + * + * @example + * ```js + * export default function plugin (options = {}) { + * return function (tree) { + * tree.messages.push({ + * type: 'dependency', + * file: 'path/to/dependency.html', + * from: tree.options.from + * }) + * + * return tree + * } + * } + * ``` + */ + this.messages = [] + + /** + * Tree method parsing string inside plugins. + * + * @memberof tree + * @type {Function} parser + * + * @example + * ```js + * export default function plugin (options = {}) { + * return function (tree) { + * tree.match({ tag: 'include' }, function(node) { + * node.tag = false; + * node.content = tree.parser(fs.readFileSync(node.attr.src)) + * return node + * }) + * + * return tree + * } + * } + * ``` + */ + this.parser = parser + + /** + * Tree method rendering tree to string inside plugins. + * + * @memberof tree + * @type {Function} render + * + * @example + * ```js + * export default function plugin (options = {}) { + * return function (tree) { + * var outherTree = ['\n', {tag: 'div', content: ['1']}, '\n\t', {tag: 'div', content: ['2']}, '\n']; + * var htmlWitchoutSpaceless = tree.render(outherTree).replace(/[\n|\t]/g, ''); + * return tree.parser(htmlWitchoutSpaceless) + * } + * } + * ``` + */ + this.render = render + + // extend api methods + Api.call(this) + } + + /** + * @this posthtml + * @param {Function} plugin - A PostHTML plugin + * @returns {Constructor} - this(PostHTML) + * + * **Usage** + * ```js + * ph.use((tree) => { tag: 'div', content: tree }) + * .process('<html>..</html>', {}) + * .then((result) => result)) + * ``` + */ + use (...args) { + this.plugins.push(...args) + + return this + } + + /** + * @param {String} html - Input (HTML) + * @param {?Object} options - PostHTML Options + * @returns {Object<{html: String, tree: PostHTMLTree}>} - Sync Mode + * @returns {Promise<{html: String, tree: PostHTMLTree}>} - Async Mode (default) + * + * **Usage** + * + * **Sync** + * ```js + * ph.process('<html>..</html>', { sync: true }).html + * ``` + * + * **Async** + * ```js + * ph.process('<html>..</html>', {}).then((result) => result)) + * ``` + */ + process (tree, options = {}) { + /** + * ## PostHTML Options + * + * @type {Object} + * @prop {?Boolean} options.sync - enables sync mode, plugins will run synchronously, throws an error when used with async plugins + * @prop {?Function} options.parser - use custom parser, replaces default (posthtml-parser) + * @prop {?Function} options.render - use custom render, replaces default (posthtml-render) + * @prop {?Boolean} options.skipParse - disable parsing + * @prop {?Array} options.directives - Adds processing of custom [directives](https://github.com/posthtml/posthtml-parser#directives). + */ + this.options = options + this.source = tree + + if (options.parser) parser = this.parser = options.parser + if (options.render) render = this.render = options.render + + tree = options.skipParse + ? tree || [] + : parser(tree, options) + + tree = [].concat(tree) + + // sync mode + if (options.sync === true) { + this.plugins.forEach((plugin, index) => { + _treeExtendApi(tree, this) + + let result + + if (plugin.length === 2 || isPromise(result = plugin(tree))) { + throw new Error( + `Can’t process contents in sync mode because of async plugin: ${plugin.name}` + ) + } + + // clearing the tree of options + if (index !== this.plugins.length - 1 && !options.skipParse) { + tree = [].concat(tree) + } + + // return the previous tree unless result is fulfilled + tree = result || tree + }) + + return lazyResult(render, tree) + } + + // async mode + let i = 0 + + const next = (result, cb) => { + _treeExtendApi(result, this) + + // all plugins called + if (this.plugins.length <= i) { + cb(null, result) + return + } + + // little helper to go to the next iteration + function _next (res) { + if (res && !options.skipParse) { + res = [].concat(res) + } + + return next(res || result, cb) + } + + // call next + const plugin = this.plugins[i++] + + if (plugin.length === 2) { + plugin(result, (err, res) => { + if (err) return cb(err) + _next(res) + }) + return + } + + // sync and promised plugins + let err = null + + const res = tryCatch(() => plugin(result), e => { + err = e + return e + }) + + if (err) { + cb(err) + return + } + + if (isPromise(res)) { + res.then(_next).catch(cb) + return + } + + _next(res) + } + + return new Promise((resolve, reject) => { + next(tree, (err, tree) => { + if (err) reject(err) + else resolve(lazyResult(render, tree)) + }) + }) + } +} + +/** + * @exports posthtml + * + * @param {Array} plugins + * @return {Function} posthtml + * + * **Usage** + * ```js + * import posthtml from 'posthtml' + * import plugin from 'posthtml-plugin' + * + * const ph = posthtml([ plugin() ]) + * ``` + */ +module.exports = plugins => new PostHTML(plugins) + +/** + * Extension of options tree + * + * @private + * + * @param {Array} tree + * @param {Object} PostHTML + * @returns {?*} + */ +function _treeExtendApi (t, _t) { + if (typeof t === 'object') { + t = Object.assign(t, _t) + } +} + +/** + * Checks if parameter is a Promise (or thenable) object. + * + * @private + * + * @param {*} promise - Target `{}` to test + * @returns {Boolean} + */ +function isPromise (promise) { + return !!promise && typeof promise.then === 'function' +} + +/** + * Simple try/catch helper, if exists, returns result + * + * @private + * + * @param {Function} tryFn - try block + * @param {Function} catchFn - catch block + * @returns {?*} + */ +function tryCatch (tryFn, catchFn) { + try { + return tryFn() + } catch (err) { + catchFn(err) + } +} + +/** + * Wraps the PostHTMLTree within an object using a getter to render HTML on demand. + * + * @private + * + * @param {Function} render + * @param {Array} tree + * @returns {Object<{html: String, tree: Array}>} + */ +function lazyResult (render, tree) { + return { + get html () { + return render(tree, tree.options) + }, + tree, + messages: tree.messages + } +} |
