@metalsmith/in-place
Advanced tools
+293
| 'use strict'; | ||
| var isUtf8 = require('is-utf8'); | ||
| var path = require('path'); | ||
| var jstransformer = require('jstransformer'); | ||
| function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } | ||
| function _interopNamespace(e) { | ||
| if (e && e.__esModule) return e; | ||
| var n = Object.create(null); | ||
| if (e) { | ||
| Object.keys(e).forEach(function (k) { | ||
| if (k !== 'default') { | ||
| var d = Object.getOwnPropertyDescriptor(e, k); | ||
| Object.defineProperty(n, k, d.get ? d : { | ||
| enumerable: true, | ||
| get: function () { return e[k]; } | ||
| }); | ||
| } | ||
| }); | ||
| } | ||
| n["default"] = e; | ||
| return n; | ||
| } | ||
| var isUtf8__default = /*#__PURE__*/_interopDefaultLegacy(isUtf8); | ||
| var jstransformer__default = /*#__PURE__*/_interopDefaultLegacy(jstransformer); | ||
| /** | ||
| * Parse a filepath into dirname, base & extensions | ||
| * @param {string} filename | ||
| */ | ||
| function parseFilepath(filename) { | ||
| const isNested = filename.includes(path.sep); | ||
| const dir = isNested ? path.dirname(filename) : ''; | ||
| const [base, ...extensions] = path.basename(filename).split('.'); | ||
| return { | ||
| dirname: dir, | ||
| base, | ||
| extensions | ||
| }; | ||
| } | ||
| /** | ||
| * @param {string} filename | ||
| * @param {import('./index').Options} opts | ||
| * @returns {string} | ||
| */ | ||
| function handleExtname(filename, opts) { | ||
| const { | ||
| dirname, | ||
| base, | ||
| extensions | ||
| } = parseFilepath(filename); | ||
| const extname = opts.extname && opts.extname.slice(1); | ||
| // decouples file extension chaining order from transformer usage order | ||
| for (let i = extensions.length; i--;) { | ||
| if (opts.transform.inputFormats.includes(extensions[i])) { | ||
| extensions.splice(i, 1); | ||
| break; | ||
| } | ||
| } | ||
| const isLast = !extensions.length; | ||
| if (isLast && extname) extensions.push(extname); | ||
| return [path.join(dirname, base), ...extensions].join('.'); | ||
| } | ||
| /** | ||
| * Get a transformer by name ("jstransformer-ejs"), shortened name ("ejs") or filesystem path | ||
| * @param {string|JsTransformer} namePathOrTransformer | ||
| * @param {import('metalsmith').Debugger} debug | ||
| * @returns {Promise<JsTransformer>} | ||
| */ | ||
| function getTransformer(namePathOrTransformer, debug) { | ||
| let transform = null; | ||
| const t = namePathOrTransformer; | ||
| const tName = t; | ||
| const tPath = t; | ||
| // let the jstransformer constructor throw errors | ||
| if (typeof t !== 'string') { | ||
| transform = Promise.resolve(t); | ||
| } else { | ||
| if (path.isAbsolute(tPath) || tPath.startsWith('.') || tName.startsWith('jstransformer-')) { | ||
| debug('Importing transformer: %s', tPath); | ||
| transform = (function (t) { return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(t)); }); })(tPath).then(t => t.default); | ||
| } else { | ||
| debug('Importing transformer: jstransformer-%s', tName); | ||
| // suppose a shorthand where the jstransformer- prefix is omitted, more likely | ||
| transform = (function (t) { return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(t)); }); })(`jstransformer-${tName}`).then(t => t.default).catch(() => { | ||
| // else fall back to trying to import the name | ||
| debug.warn('"jstransformer-%s" not found, trying "%s" instead', tName, tName); | ||
| return (function (t) { return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(t)); }); })(tName).then(t => t.default); | ||
| }); | ||
| } | ||
| } | ||
| return transform.then(t => { | ||
| return jstransformer__default["default"](t); | ||
| }); | ||
| } | ||
| /** | ||
| * @callback Render | ||
| * @param {string} source | ||
| * @param {Object} options | ||
| * @param {Object} locals | ||
| * @returns {string} | ||
| */ | ||
| /** | ||
| * @callback RenderAsync | ||
| * @param {string} source | ||
| * @param {Object} options | ||
| * @param {Object} locals | ||
| * @param {Function} callback | ||
| * @returns {Promise<string>} | ||
| */ | ||
| /** | ||
| * @callback Compile | ||
| * @param {string} source | ||
| * @param {Object} options | ||
| * @returns {string} | ||
| */ | ||
| /** | ||
| * @callback CompileAsync | ||
| * @param {string} source | ||
| * @param {Object} options | ||
| * @param {Function} callback | ||
| * @returns {Promise<string>} | ||
| */ | ||
| /** | ||
| * @typedef {Object} JsTransformer | ||
| * @property {string} name | ||
| * @property {string[]} inputFormats | ||
| * @property {string} outputFormat | ||
| * @property {Render} [render] | ||
| * @property {RenderAsync} [renderAsync] | ||
| * @property {Compile} [compile] | ||
| * @property {CompileAsync} [compileAsync] | ||
| */ | ||
| /* c8 ignore start */ | ||
| let debug = () => { | ||
| throw new Error('uninstantiated debug'); | ||
| }; | ||
| /* c8 ignore end */ | ||
| async function render({ | ||
| filename, | ||
| files, | ||
| metalsmith, | ||
| options, | ||
| transform | ||
| }) { | ||
| const file = files[filename]; | ||
| const engineOptions = Object.assign({}, options.engineOptions); | ||
| if (options.engineOptions.filename) { | ||
| Object.assign(engineOptions, { | ||
| // set the filename in options for jstransformers requiring it (like Pug) | ||
| filename: metalsmith.path(metalsmith.source(), filename) | ||
| }); | ||
| } | ||
| const metadata = metalsmith.metadata(); | ||
| debug(`rendering ${filename}`); | ||
| const locals = Object.assign({}, metadata, file); | ||
| const contents = file.contents.toString(); | ||
| return transform.renderAsync(contents, engineOptions, locals).then(rendered => { | ||
| const newName = handleExtname(filename, { | ||
| ...options, | ||
| transform | ||
| }); | ||
| debug('Done rendering %s', filename); | ||
| debug('Renaming "%s" to "%s"', filename, newName); | ||
| if (newName !== filename) { | ||
| delete files[filename]; | ||
| files[newName] = file; | ||
| } | ||
| files[newName].contents = Buffer.from(rendered.body); | ||
| }).catch(err => { | ||
| err.message = `${filename}: ${err.message}`; | ||
| throw err; | ||
| }); | ||
| } | ||
| /** | ||
| * Validate, checks whether a file should be processed | ||
| */ | ||
| function validate({ | ||
| filename, | ||
| files, | ||
| transform | ||
| }) { | ||
| const { | ||
| extensions | ||
| } = parseFilepath(filename); | ||
| debug(`validating ${filename} %O %O`, extensions, transform.inputFormats); | ||
| // IF the transform has inputFormats defined, invalidate the file if it has no matching extname | ||
| if (transform.inputFormats && !extensions.some(fmt => transform.inputFormats.includes(fmt))) { | ||
| debug.warn('Validation failed for file "%s", transformer %s supports extensions %s.', filename, transform.name, transform.inputFormats.map(i => `.${i}`).join(', ')); | ||
| } | ||
| // Files that are not utf8 are ignored | ||
| if (!isUtf8__default["default"](files[filename].contents)) { | ||
| debug.warn(`Validation failed, %s is not utf-8`, filename); | ||
| return false; | ||
| } | ||
| return true; | ||
| } | ||
| /** | ||
| * @typedef {Object} Options | ||
| * @property {string|JsTransformer} transform Jstransformer to run: name of a node module or local JS module path (starting with `.`) whose default export is a jstransformer. As a shorthand for existing transformers you can remove the `jstransformer-` prefix: `marked` will be understood as `jstransformer-marked`. Or an actual jstransformer; an object with `name`, `inputFormats`,`outputFormat`, and at least one of the render methods `render`, `renderAsync`, `compile` or `compileAsync` described in the [jstransformer API docs](https://github.com/jstransformers/jstransformer#api) | ||
| * @property {string} [pattern='**\/*.<transform.inputFormats>'] (*optional*) One or more paths or glob patterns to limit the scope of the transform. Defaults to `'**\/*.<transform.inputFormats>*'` | ||
| * @property {Object} [engineOptions={}] (*optional*) Pass options to the jstransformer templating engine that's rendering your files. The default is `{}` | ||
| * @property {string} [extname] (*optional*) Pass `''` to remove the extension or `'.<extname>'` to keep or rename it. Defaults to `transform.outputFormat` | ||
| **/ | ||
| /** | ||
| * Set default options based on jstransformer `transform` | ||
| * @param {JsTransformer} transform | ||
| * @returns {Options} | ||
| */ | ||
| function normalizeOptions(transform) { | ||
| const extMatch = transform.inputFormats.length === 1 ? transform.inputFormats[0] : `{${transform.inputFormats.join(',')}}`; | ||
| return { | ||
| pattern: `**/*.${extMatch}*`, | ||
| extname: `.${transform.outputFormat}`, | ||
| engineOptions: {} | ||
| }; | ||
| } | ||
| /** | ||
| * A metalsmith plugin for in-place templating | ||
| * @param {Options} options | ||
| * @returns {import('metalsmith').Plugin} | ||
| */ | ||
| function inPlace(options = {}) { | ||
| let transform; | ||
| return async function inPlace(files, metalsmith, done) { | ||
| debug = metalsmith.debug('@metalsmith/in-place'); | ||
| // Check whether the pattern option is valid | ||
| if (options.pattern && !(typeof options.pattern === 'string' || Array.isArray(options.pattern))) { | ||
| return done(new Error('invalid pattern, the pattern option should be a string or array of strings. See https://www.npmjs.com/package/@metalsmith/in-place#pattern')); | ||
| } | ||
| // skip resolving the transform option on repeat runs | ||
| if (!transform) { | ||
| try { | ||
| transform = await getTransformer(options.transform, debug); | ||
| } catch (err) { | ||
| // pass through jstransformer & Node import resolution errors | ||
| return done(err); | ||
| } | ||
| } | ||
| options = Object.assign(normalizeOptions(transform), options); | ||
| debug('Running with options %O', options); | ||
| const matchedFiles = metalsmith.match(options.pattern); | ||
| // Filter files by validity, pass basename to avoid dots in folder path | ||
| const validFiles = matchedFiles.filter(filename => validate({ | ||
| filename, | ||
| files, | ||
| transform | ||
| })); | ||
| // Let the user know when there are no files to process | ||
| if (validFiles.length === 0) { | ||
| debug.warn('No valid files to process.'); | ||
| return done(); | ||
| } else { | ||
| debug('Rendering %s files', validFiles.length); | ||
| } | ||
| // Map all files that should be processed to an array of promises and call done when finished | ||
| return Promise.all(validFiles.map(filename => render({ | ||
| filename, | ||
| files, | ||
| metalsmith, | ||
| options, | ||
| transform | ||
| }))).then(() => done()).catch(error => done(error)); | ||
| }; | ||
| } | ||
| module.exports = inPlace; | ||
| //# sourceMappingURL=index.cjs.map |
| {"version":3,"file":"index.cjs","sources":["../src/utils.js","../src/index.js"],"sourcesContent":["import { dirname, join, basename, sep, isAbsolute } from 'path'\nimport jstransformer from 'jstransformer'\n\n/**\n * Parse a filepath into dirname, base & extensions\n * @param {string} filename\n */\nexport function parseFilepath(filename) {\n const isNested = filename.includes(sep)\n const dir = isNested ? dirname(filename) : ''\n const [base, ...extensions] = basename(filename).split('.')\n return { dirname: dir, base, extensions }\n}\n\n/**\n * @param {string} filename\n * @param {import('./index').Options} opts\n * @returns {string}\n */\nexport function handleExtname(filename, opts) {\n const { dirname, base, extensions } = parseFilepath(filename)\n const extname = opts.extname && opts.extname.slice(1)\n // decouples file extension chaining order from transformer usage order\n for (let i = extensions.length; i--; ) {\n if (opts.transform.inputFormats.includes(extensions[i])) {\n extensions.splice(i, 1)\n break\n }\n }\n const isLast = !extensions.length\n if (isLast && extname) extensions.push(extname)\n return [join(dirname, base), ...extensions].join('.')\n}\n\n/**\n * Get a transformer by name (\"jstransformer-ejs\"), shortened name (\"ejs\") or filesystem path\n * @param {string|JsTransformer} namePathOrTransformer\n * @param {import('metalsmith').Debugger} debug\n * @returns {Promise<JsTransformer>}\n */\nexport function getTransformer(namePathOrTransformer, debug) {\n let transform = null\n const t = namePathOrTransformer\n const tName = t\n const tPath = t\n\n // let the jstransformer constructor throw errors\n if (typeof t !== 'string') {\n transform = Promise.resolve(t)\n } else {\n if (isAbsolute(tPath) || tPath.startsWith('.') || tName.startsWith('jstransformer-')) {\n debug('Importing transformer: %s', tPath)\n transform = import(tPath).then((t) => t.default)\n } else {\n debug('Importing transformer: jstransformer-%s', tName)\n // suppose a shorthand where the jstransformer- prefix is omitted, more likely\n transform = import(`jstransformer-${tName}`)\n .then((t) => t.default)\n .catch(() => {\n // else fall back to trying to import the name\n debug.warn('\"jstransformer-%s\" not found, trying \"%s\" instead', tName, tName)\n return import(tName).then((t) => t.default)\n })\n }\n }\n return transform.then((t) => {\n return jstransformer(t)\n })\n}\n","import isUtf8 from 'is-utf8'\nimport { parseFilepath, handleExtname, getTransformer } from './utils.js'\n\n/**\n * @callback Render\n * @param {string} source\n * @param {Object} options\n * @param {Object} locals\n * @returns {string}\n */\n\n/**\n * @callback RenderAsync\n * @param {string} source\n * @param {Object} options\n * @param {Object} locals\n * @param {Function} callback\n * @returns {Promise<string>}\n */\n\n/**\n * @callback Compile\n * @param {string} source\n * @param {Object} options\n * @returns {string}\n */\n\n/**\n * @callback CompileAsync\n * @param {string} source\n * @param {Object} options\n * @param {Function} callback\n * @returns {Promise<string>}\n */\n\n/**\n * @typedef {Object} JsTransformer\n * @property {string} name\n * @property {string[]} inputFormats\n * @property {string} outputFormat\n * @property {Render} [render]\n * @property {RenderAsync} [renderAsync]\n * @property {Compile} [compile]\n * @property {CompileAsync} [compileAsync]\n */\n\n/* c8 ignore start */\nlet debug = () => {\n throw new Error('uninstantiated debug')\n}\n/* c8 ignore end */\n\nasync function render({ filename, files, metalsmith, options, transform }) {\n const file = files[filename]\n const engineOptions = Object.assign({}, options.engineOptions)\n if (options.engineOptions.filename) {\n Object.assign(engineOptions, {\n // set the filename in options for jstransformers requiring it (like Pug)\n filename: metalsmith.path(metalsmith.source(), filename)\n })\n }\n const metadata = metalsmith.metadata()\n debug(`rendering ${filename}`)\n\n const locals = Object.assign({}, metadata, file)\n const contents = file.contents.toString()\n\n return transform\n .renderAsync(contents, engineOptions, locals)\n .then((rendered) => {\n const newName = handleExtname(filename, { ...options, transform })\n debug('Done rendering %s', filename)\n debug('Renaming \"%s\" to \"%s\"', filename, newName)\n\n if (newName !== filename) {\n delete files[filename]\n files[newName] = file\n }\n files[newName].contents = Buffer.from(rendered.body)\n })\n .catch((err) => {\n err.message = `${filename}: ${err.message}`\n throw err\n })\n}\n\n/**\n * Validate, checks whether a file should be processed\n */\n\nfunction validate({ filename, files, transform }) {\n const { extensions } = parseFilepath(filename)\n debug(`validating ${filename} %O %O`, extensions, transform.inputFormats)\n\n // IF the transform has inputFormats defined, invalidate the file if it has no matching extname\n if (transform.inputFormats && !extensions.some((fmt) => transform.inputFormats.includes(fmt))) {\n debug.warn(\n 'Validation failed for file \"%s\", transformer %s supports extensions %s.',\n filename,\n transform.name,\n transform.inputFormats.map((i) => `.${i}`).join(', ')\n )\n }\n\n // Files that are not utf8 are ignored\n if (!isUtf8(files[filename].contents)) {\n debug.warn(`Validation failed, %s is not utf-8`, filename)\n return false\n }\n return true\n}\n\n/**\n * @typedef {Object} Options\n * @property {string|JsTransformer} transform Jstransformer to run: name of a node module or local JS module path (starting with `.`) whose default export is a jstransformer. As a shorthand for existing transformers you can remove the `jstransformer-` prefix: `marked` will be understood as `jstransformer-marked`. Or an actual jstransformer; an object with `name`, `inputFormats`,`outputFormat`, and at least one of the render methods `render`, `renderAsync`, `compile` or `compileAsync` described in the [jstransformer API docs](https://github.com/jstransformers/jstransformer#api)\n * @property {string} [pattern='**\\/*.<transform.inputFormats>'] (*optional*) One or more paths or glob patterns to limit the scope of the transform. Defaults to `'**\\/*.<transform.inputFormats>*'`\n * @property {Object} [engineOptions={}] (*optional*) Pass options to the jstransformer templating engine that's rendering your files. The default is `{}`\n * @property {string} [extname] (*optional*) Pass `''` to remove the extension or `'.<extname>'` to keep or rename it. Defaults to `transform.outputFormat`\n **/\n\n/**\n * Set default options based on jstransformer `transform`\n * @param {JsTransformer} transform\n * @returns {Options}\n */\nfunction normalizeOptions(transform) {\n const extMatch =\n transform.inputFormats.length === 1 ? transform.inputFormats[0] : `{${transform.inputFormats.join(',')}}`\n return {\n pattern: `**/*.${extMatch}*`,\n extname: `.${transform.outputFormat}`,\n engineOptions: {}\n }\n}\n\n/**\n * A metalsmith plugin for in-place templating\n * @param {Options} options\n * @returns {import('metalsmith').Plugin}\n */\nfunction inPlace(options = {}) {\n let transform\n\n return async function inPlace(files, metalsmith, done) {\n debug = metalsmith.debug('@metalsmith/in-place')\n\n // Check whether the pattern option is valid\n if (options.pattern && !(typeof options.pattern === 'string' || Array.isArray(options.pattern))) {\n return done(\n new Error(\n 'invalid pattern, the pattern option should be a string or array of strings. See https://www.npmjs.com/package/@metalsmith/in-place#pattern'\n )\n )\n }\n\n // skip resolving the transform option on repeat runs\n if (!transform) {\n try {\n transform = await getTransformer(options.transform, debug)\n } catch (err) {\n // pass through jstransformer & Node import resolution errors\n return done(err)\n }\n }\n\n options = Object.assign(normalizeOptions(transform), options)\n\n debug('Running with options %O', options)\n\n const matchedFiles = metalsmith.match(options.pattern)\n\n // Filter files by validity, pass basename to avoid dots in folder path\n const validFiles = matchedFiles.filter((filename) => validate({ filename, files, transform }))\n\n // Let the user know when there are no files to process\n if (validFiles.length === 0) {\n debug.warn('No valid files to process.')\n return done()\n } else {\n debug('Rendering %s files', validFiles.length)\n }\n\n // Map all files that should be processed to an array of promises and call done when finished\n return Promise.all(validFiles.map((filename) => render({ filename, files, metalsmith, options, transform })))\n .then(() => done())\n .catch((error) => done(error))\n }\n}\n\nexport default inPlace\n"],"names":["parseFilepath","filename","isNested","includes","sep","dir","dirname","base","extensions","basename","split","handleExtname","opts","extname","slice","i","length","transform","inputFormats","splice","isLast","push","join","getTransformer","namePathOrTransformer","debug","t","tName","tPath","Promise","resolve","isAbsolute","startsWith","then","default","catch","warn","jstransformer","Error","render","files","metalsmith","options","file","engineOptions","Object","assign","path","source","metadata","locals","contents","toString","renderAsync","rendered","newName","Buffer","from","body","err","message","validate","some","fmt","name","map","isUtf8","normalizeOptions","extMatch","pattern","outputFormat","inPlace","done","Array","isArray","matchedFiles","match","validFiles","filter","all","error"],"mappings":"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"} |
| import { Plugin } from 'metalsmith'; | ||
| export default initializeInPlace; | ||
| export type Render = (source: string, options: any, locals: any) => string; | ||
| export type RenderAsync = (source: string, options: any, locals: any, callback: Function) => Promise<string>; | ||
| export type Compile = (source: string, options: any) => string; | ||
| export type CompileAsync = (source: string, options: any, callback: Function) => Promise<string>; | ||
| export type JsTransformer = { | ||
| name: string; | ||
| inputFormats: string[]; | ||
| outputFormat: string; | ||
| render?: Render; | ||
| renderAsync?: RenderAsync; | ||
| compile?: Compile; | ||
| compileAsync?: CompileAsync; | ||
| [key]?: string; | ||
| }; | ||
| export type Options = { | ||
| /** | ||
| * Jstransformer to run: name of a node module or local JS module path (starting with `.`) whose default export is a jstransformer. As a shorthand for existing transformers you can remove the `jstransformer-` prefix: `marked` will be understood as `jstransformer-marked`. Or an actual jstransformer; an object with `name`, `inputFormats`,`outputFormat`, and at least one of the render methods `render`, `renderAsync`, `compile` or `compileAsync` described in the [jstransformer API docs](https://github.com/jstransformers/jstransformer#api) | ||
| */ | ||
| transform: string | JsTransformer; | ||
| /** | ||
| * One or more paths or glob patterns to limit the scope of the transform. | ||
| * @default '**\/*.<transform.inputFormats>' | ||
| */ | ||
| pattern?: string|string[]; | ||
| /** | ||
| * Pass options to the jstransformer templating engine that's rendering your files. | ||
| * @default {} | ||
| */ | ||
| engineOptions?: any; | ||
| /** | ||
| * Pass `''` to remove the extension or `'.<extname>'` to keep or rename it. | ||
| * @default transform.outputFormat | ||
| */ | ||
| extname?: string; | ||
| }; | ||
| /** | ||
| * A metalsmith plugin for in-place templating | ||
| * @example | ||
| * import nunjucks from 'jstransformer-nunjucks' | ||
| * | ||
| * metalsmith | ||
| * .use(inPlace({ transform: 'jstransformer-nunjucks' })) // use jstransformer-nunjucks | ||
| * .use(inPlace({ transform: 'nunjucks' })) // shorthand for above | ||
| * .use(inPlace({ transform: nunjucks })) // equivalent to above | ||
| * .use(inPlace({ transform: './local/transform.js' })) // custom local transformer | ||
| * .use(inPlace({ transform: { // custom inline transformer | ||
| * name: 'prepend-hello', | ||
| * inputFormats: ['prepend-hello'], | ||
| * outputFormat: 'html', | ||
| * render(str, options, locals) => { | ||
| * return 'hello ' + str | ||
| * } | ||
| * }})) | ||
| */ | ||
| declare function initializeInPlace(options?: Options): Plugin; |
| {"version":3,"file":"index.js","sources":["../src/utils.js","../src/index.js"],"sourcesContent":["import { dirname, join, basename, sep, isAbsolute } from 'path'\nimport jstransformer from 'jstransformer'\n\n/**\n * Parse a filepath into dirname, base & extensions\n * @param {string} filename\n */\nexport function parseFilepath(filename) {\n const isNested = filename.includes(sep)\n const dir = isNested ? dirname(filename) : ''\n const [base, ...extensions] = basename(filename).split('.')\n return { dirname: dir, base, extensions }\n}\n\n/**\n * @param {string} filename\n * @param {import('./index').Options} opts\n * @returns {string}\n */\nexport function handleExtname(filename, opts) {\n const { dirname, base, extensions } = parseFilepath(filename)\n const extname = opts.extname && opts.extname.slice(1)\n // decouples file extension chaining order from transformer usage order\n for (let i = extensions.length; i--; ) {\n if (opts.transform.inputFormats.includes(extensions[i])) {\n extensions.splice(i, 1)\n break\n }\n }\n const isLast = !extensions.length\n if (isLast && extname) extensions.push(extname)\n return [join(dirname, base), ...extensions].join('.')\n}\n\n/**\n * Get a transformer by name (\"jstransformer-ejs\"), shortened name (\"ejs\") or filesystem path\n * @param {string|JsTransformer} namePathOrTransformer\n * @param {import('metalsmith').Debugger} debug\n * @returns {Promise<JsTransformer>}\n */\nexport function getTransformer(namePathOrTransformer, debug) {\n let transform = null\n const t = namePathOrTransformer\n const tName = t\n const tPath = t\n\n // let the jstransformer constructor throw errors\n if (typeof t !== 'string') {\n transform = Promise.resolve(t)\n } else {\n if (isAbsolute(tPath) || tPath.startsWith('.') || tName.startsWith('jstransformer-')) {\n debug('Importing transformer: %s', tPath)\n transform = import(tPath).then((t) => t.default)\n } else {\n debug('Importing transformer: jstransformer-%s', tName)\n // suppose a shorthand where the jstransformer- prefix is omitted, more likely\n transform = import(`jstransformer-${tName}`)\n .then((t) => t.default)\n .catch(() => {\n // else fall back to trying to import the name\n debug.warn('\"jstransformer-%s\" not found, trying \"%s\" instead', tName, tName)\n return import(tName).then((t) => t.default)\n })\n }\n }\n return transform.then((t) => {\n return jstransformer(t)\n })\n}\n","import isUtf8 from 'is-utf8'\nimport { parseFilepath, handleExtname, getTransformer } from './utils.js'\n\n/**\n * @callback Render\n * @param {string} source\n * @param {Object} options\n * @param {Object} locals\n * @returns {string}\n */\n\n/**\n * @callback RenderAsync\n * @param {string} source\n * @param {Object} options\n * @param {Object} locals\n * @param {Function} callback\n * @returns {Promise<string>}\n */\n\n/**\n * @callback Compile\n * @param {string} source\n * @param {Object} options\n * @returns {string}\n */\n\n/**\n * @callback CompileAsync\n * @param {string} source\n * @param {Object} options\n * @param {Function} callback\n * @returns {Promise<string>}\n */\n\n/**\n * @typedef {Object} JsTransformer\n * @property {string} name\n * @property {string[]} inputFormats\n * @property {string} outputFormat\n * @property {Render} [render]\n * @property {RenderAsync} [renderAsync]\n * @property {Compile} [compile]\n * @property {CompileAsync} [compileAsync]\n */\n\n/* c8 ignore start */\nlet debug = () => {\n throw new Error('uninstantiated debug')\n}\n/* c8 ignore end */\n\nasync function render({ filename, files, metalsmith, options, transform }) {\n const file = files[filename]\n const engineOptions = Object.assign({}, options.engineOptions)\n if (options.engineOptions.filename) {\n Object.assign(engineOptions, {\n // set the filename in options for jstransformers requiring it (like Pug)\n filename: metalsmith.path(metalsmith.source(), filename)\n })\n }\n const metadata = metalsmith.metadata()\n debug(`rendering ${filename}`)\n\n const locals = Object.assign({}, metadata, file)\n const contents = file.contents.toString()\n\n return transform\n .renderAsync(contents, engineOptions, locals)\n .then((rendered) => {\n const newName = handleExtname(filename, { ...options, transform })\n debug('Done rendering %s', filename)\n debug('Renaming \"%s\" to \"%s\"', filename, newName)\n\n if (newName !== filename) {\n delete files[filename]\n files[newName] = file\n }\n files[newName].contents = Buffer.from(rendered.body)\n })\n .catch((err) => {\n err.message = `${filename}: ${err.message}`\n throw err\n })\n}\n\n/**\n * Validate, checks whether a file should be processed\n */\n\nfunction validate({ filename, files, transform }) {\n const { extensions } = parseFilepath(filename)\n debug(`validating ${filename} %O %O`, extensions, transform.inputFormats)\n\n // IF the transform has inputFormats defined, invalidate the file if it has no matching extname\n if (transform.inputFormats && !extensions.some((fmt) => transform.inputFormats.includes(fmt))) {\n debug.warn(\n 'Validation failed for file \"%s\", transformer %s supports extensions %s.',\n filename,\n transform.name,\n transform.inputFormats.map((i) => `.${i}`).join(', ')\n )\n }\n\n // Files that are not utf8 are ignored\n if (!isUtf8(files[filename].contents)) {\n debug.warn(`Validation failed, %s is not utf-8`, filename)\n return false\n }\n return true\n}\n\n/**\n * @typedef {Object} Options\n * @property {string|JsTransformer} transform Jstransformer to run: name of a node module or local JS module path (starting with `.`) whose default export is a jstransformer. As a shorthand for existing transformers you can remove the `jstransformer-` prefix: `marked` will be understood as `jstransformer-marked`. Or an actual jstransformer; an object with `name`, `inputFormats`,`outputFormat`, and at least one of the render methods `render`, `renderAsync`, `compile` or `compileAsync` described in the [jstransformer API docs](https://github.com/jstransformers/jstransformer#api)\n * @property {string} [pattern='**\\/*.<transform.inputFormats>'] (*optional*) One or more paths or glob patterns to limit the scope of the transform. Defaults to `'**\\/*.<transform.inputFormats>*'`\n * @property {Object} [engineOptions={}] (*optional*) Pass options to the jstransformer templating engine that's rendering your files. The default is `{}`\n * @property {string} [extname] (*optional*) Pass `''` to remove the extension or `'.<extname>'` to keep or rename it. Defaults to `transform.outputFormat`\n **/\n\n/**\n * Set default options based on jstransformer `transform`\n * @param {JsTransformer} transform\n * @returns {Options}\n */\nfunction normalizeOptions(transform) {\n const extMatch =\n transform.inputFormats.length === 1 ? transform.inputFormats[0] : `{${transform.inputFormats.join(',')}}`\n return {\n pattern: `**/*.${extMatch}*`,\n extname: `.${transform.outputFormat}`,\n engineOptions: {}\n }\n}\n\n/**\n * A metalsmith plugin for in-place templating\n * @param {Options} options\n * @returns {import('metalsmith').Plugin}\n */\nfunction inPlace(options = {}) {\n let transform\n\n return async function inPlace(files, metalsmith, done) {\n debug = metalsmith.debug('@metalsmith/in-place')\n\n // Check whether the pattern option is valid\n if (options.pattern && !(typeof options.pattern === 'string' || Array.isArray(options.pattern))) {\n return done(\n new Error(\n 'invalid pattern, the pattern option should be a string or array of strings. See https://www.npmjs.com/package/@metalsmith/in-place#pattern'\n )\n )\n }\n\n // skip resolving the transform option on repeat runs\n if (!transform) {\n try {\n transform = await getTransformer(options.transform, debug)\n } catch (err) {\n // pass through jstransformer & Node import resolution errors\n return done(err)\n }\n }\n\n options = Object.assign(normalizeOptions(transform), options)\n\n debug('Running with options %O', options)\n\n const matchedFiles = metalsmith.match(options.pattern)\n\n // Filter files by validity, pass basename to avoid dots in folder path\n const validFiles = matchedFiles.filter((filename) => validate({ filename, files, transform }))\n\n // Let the user know when there are no files to process\n if (validFiles.length === 0) {\n debug.warn('No valid files to process.')\n return done()\n } else {\n debug('Rendering %s files', validFiles.length)\n }\n\n // Map all files that should be processed to an array of promises and call done when finished\n return Promise.all(validFiles.map((filename) => render({ filename, files, metalsmith, options, transform })))\n .then(() => done())\n .catch((error) => done(error))\n }\n}\n\nexport default inPlace\n"],"names":["parseFilepath","filename","isNested","includes","sep","dir","dirname","base","extensions","basename","split","handleExtname","opts","extname","slice","i","length","transform","inputFormats","splice","isLast","push","join","getTransformer","namePathOrTransformer","debug","t","tName","tPath","Promise","resolve","isAbsolute","startsWith","then","default","catch","warn","jstransformer","Error","render","files","metalsmith","options","file","engineOptions","Object","assign","path","source","metadata","locals","contents","toString","renderAsync","rendered","newName","Buffer","from","body","err","message","validate","some","fmt","name","map","isUtf8","normalizeOptions","extMatch","pattern","outputFormat","inPlace","done","Array","isArray","matchedFiles","match","validFiles","filter","all","error"],"mappings":"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"} |
+211
-126
@@ -1,81 +0,162 @@ | ||
| const path = require('path') | ||
| const isUtf8 = require('is-utf8') | ||
| const getTransformer = require('./get-transformer') | ||
| let debug = () => { | ||
| throw new Error('uninstantiated debug') | ||
| } | ||
| import isUtf8 from 'is-utf8'; | ||
| import { isAbsolute, sep, dirname, basename, join } from 'path'; | ||
| import jstransformer from 'jstransformer'; | ||
| /** | ||
| * Parse a filepath into dirname, base & extensions | ||
| * @param {string} filename | ||
| */ | ||
| function parseFilepath(filename) { | ||
| const isNested = filename.includes(path.sep) | ||
| const dirname = isNested ? path.dirname(filename) : '' | ||
| const [base, ...extensions] = path.basename(filename).split('.') | ||
| return { dirname, base, extensions } | ||
| const isNested = filename.includes(sep); | ||
| const dir = isNested ? dirname(filename) : ''; | ||
| const [base, ...extensions] = basename(filename).split('.'); | ||
| return { | ||
| dirname: dir, | ||
| base, | ||
| extensions | ||
| }; | ||
| } | ||
| /** | ||
| * Engine, renders file contents with all available transformers | ||
| * @param {string} filename | ||
| * @param {import('./index').Options} opts | ||
| * @returns {string} | ||
| */ | ||
| function render({ filename, files, metalsmith, settings }) { | ||
| const { dirname, base, extensions } = parseFilepath(filename) | ||
| const file = files[filename] | ||
| const engineOptions = Object.assign({}, settings.engineOptions) | ||
| const metadata = metalsmith.metadata() | ||
| const isLastExtension = extensions.length === 1 | ||
| debug(`rendering ${filename}`) | ||
| const ext = extensions.pop() | ||
| const transform = getTransformer(ext) | ||
| const locals = Object.assign({}, metadata, file) | ||
| // Stop if the current extension can't be transformed | ||
| if (!transform) { | ||
| debug(`no transformer available for ${ext} extension for ${filename}`) | ||
| return Promise.resolve() | ||
| function handleExtname(filename, opts) { | ||
| const { | ||
| dirname, | ||
| base, | ||
| extensions | ||
| } = parseFilepath(filename); | ||
| const extname = opts.extname && opts.extname.slice(1); | ||
| // decouples file extension chaining order from transformer usage order | ||
| for (let i = extensions.length; i--;) { | ||
| if (opts.transform.inputFormats.includes(extensions[i])) { | ||
| extensions.splice(i, 1); | ||
| break; | ||
| } | ||
| } | ||
| const isLast = !extensions.length; | ||
| if (isLast && extname) extensions.push(extname); | ||
| return [join(dirname, base), ...extensions].join('.'); | ||
| } | ||
| // Stringify file contents | ||
| const contents = file.contents.toString() | ||
| /** | ||
| * Get a transformer by name ("jstransformer-ejs"), shortened name ("ejs") or filesystem path | ||
| * @param {string|JsTransformer} namePathOrTransformer | ||
| * @param {import('metalsmith').Debugger} debug | ||
| * @returns {Promise<JsTransformer>} | ||
| */ | ||
| function getTransformer(namePathOrTransformer, debug) { | ||
| let transform = null; | ||
| const t = namePathOrTransformer; | ||
| const tName = t; | ||
| const tPath = t; | ||
| // If this is the last extension, replace it with a new one | ||
| if (isLastExtension) { | ||
| debug(`last extension reached, replacing last extension with ${transform.outputFormat}`) | ||
| extensions.push(transform.outputFormat) | ||
| // let the jstransformer constructor throw errors | ||
| if (typeof t !== 'string') { | ||
| transform = Promise.resolve(t); | ||
| } else { | ||
| if (isAbsolute(tPath) || tPath.startsWith('.') || tName.startsWith('jstransformer-')) { | ||
| debug('Importing transformer: %s', tPath); | ||
| transform = import(tPath).then(t => t.default); | ||
| } else { | ||
| debug('Importing transformer: jstransformer-%s', tName); | ||
| // suppose a shorthand where the jstransformer- prefix is omitted, more likely | ||
| transform = import(`jstransformer-${tName}`).then(t => t.default).catch(() => { | ||
| // else fall back to trying to import the name | ||
| debug.warn('"jstransformer-%s" not found, trying "%s" instead', tName, tName); | ||
| return import(tName).then(t => t.default); | ||
| }); | ||
| } | ||
| } | ||
| return transform.then(t => { | ||
| return jstransformer(t); | ||
| }); | ||
| } | ||
| // Check if the filename should be set in the engine options | ||
| if (settings.setFilename) { | ||
| debug(`setting filename in the engine options`) | ||
| engineOptions.filename = path.join(metalsmith.source(), filename) | ||
| } | ||
| /** | ||
| * @callback Render | ||
| * @param {string} source | ||
| * @param {Object} options | ||
| * @param {Object} locals | ||
| * @returns {string} | ||
| */ | ||
| // Transform the contents | ||
| debug(`rendering ${ext} extension for ${filename}`) | ||
| /** | ||
| * @callback RenderAsync | ||
| * @param {string} source | ||
| * @param {Object} options | ||
| * @param {Object} locals | ||
| * @param {Function} callback | ||
| * @returns {Promise<string>} | ||
| */ | ||
| return transform | ||
| .renderAsync(contents, engineOptions, locals) | ||
| .then((rendered) => { | ||
| // Delete old file | ||
| delete files[filename] // eslint-disable-line no-param-reassign | ||
| /** | ||
| * @callback Compile | ||
| * @param {string} source | ||
| * @param {Object} options | ||
| * @returns {string} | ||
| */ | ||
| // Update files with the newly rendered file | ||
| const newName = [path.join(dirname, base), ...extensions].join('.') | ||
| files[newName] = file // eslint-disable-line no-param-reassign | ||
| files[newName].contents = Buffer.from(rendered.body) // eslint-disable-line no-param-reassign | ||
| /** | ||
| * @callback CompileAsync | ||
| * @param {string} source | ||
| * @param {Object} options | ||
| * @param {Function} callback | ||
| * @returns {Promise<string>} | ||
| */ | ||
| debug(`done rendering ${filename}, renamed to ${newName}`) | ||
| /** | ||
| * @typedef {Object} JsTransformer | ||
| * @property {string} name | ||
| * @property {string[]} inputFormats | ||
| * @property {string} outputFormat | ||
| * @property {Render} [render] | ||
| * @property {RenderAsync} [renderAsync] | ||
| * @property {Compile} [compile] | ||
| * @property {CompileAsync} [compileAsync] | ||
| */ | ||
| // Stop rendering if this was the last extension | ||
| if (isLastExtension) { | ||
| return Promise.resolve() | ||
| } | ||
| /* c8 ignore start */ | ||
| let debug = () => { | ||
| throw new Error('uninstantiated debug'); | ||
| }; | ||
| /* c8 ignore end */ | ||
| // Otherwise, keep rendering until there are no applicable transformers left | ||
| return render({ filename: newName, files, metalsmith, settings }) | ||
| }) | ||
| .catch((err) => { | ||
| err.message = `${filename}: ${err.message}` // eslint-disable-line no-param-reassign | ||
| throw err | ||
| }) | ||
| async function render({ | ||
| filename, | ||
| files, | ||
| metalsmith, | ||
| options, | ||
| transform | ||
| }) { | ||
| const file = files[filename]; | ||
| const engineOptions = Object.assign({}, options.engineOptions); | ||
| if (options.engineOptions.filename) { | ||
| Object.assign(engineOptions, { | ||
| // set the filename in options for jstransformers requiring it (like Pug) | ||
| filename: metalsmith.path(metalsmith.source(), filename) | ||
| }); | ||
| } | ||
| const metadata = metalsmith.metadata(); | ||
| debug(`rendering ${filename}`); | ||
| const locals = Object.assign({}, metadata, file); | ||
| const contents = file.contents.toString(); | ||
| return transform.renderAsync(contents, engineOptions, locals).then(rendered => { | ||
| const newName = handleExtname(filename, { | ||
| ...options, | ||
| transform | ||
| }); | ||
| debug('Done rendering %s', filename); | ||
| debug('Renaming "%s" to "%s"', filename, newName); | ||
| if (newName !== filename) { | ||
| delete files[filename]; | ||
| files[newName] = file; | ||
| } | ||
| files[newName].contents = Buffer.from(rendered.body); | ||
| }).catch(err => { | ||
| err.message = `${filename}: ${err.message}`; | ||
| throw err; | ||
| }); | ||
| } | ||
@@ -87,10 +168,15 @@ | ||
| function validate({ filename, files }) { | ||
| debug(`validating ${filename}`) | ||
| const { extensions } = parseFilepath(filename) | ||
| function validate({ | ||
| filename, | ||
| files, | ||
| transform | ||
| }) { | ||
| const { | ||
| extensions | ||
| } = parseFilepath(filename); | ||
| debug(`validating ${filename} %O %O`, extensions, transform.inputFormats); | ||
| // Files without an extension cannot be processed | ||
| if (!extensions.length) { | ||
| debug(`validation failed, ${filename} does not have an extension`) | ||
| return false | ||
| // IF the transform has inputFormats defined, invalidate the file if it has no matching extname | ||
| if (transform.inputFormats && !extensions.some(fmt => transform.inputFormats.includes(fmt))) { | ||
| debug.warn('Validation failed for file "%s", transformer %s supports extensions %s.', filename, transform.name, transform.inputFormats.map(i => `.${i}`).join(', ')); | ||
| } | ||
@@ -100,15 +186,6 @@ | ||
| if (!isUtf8(files[filename].contents)) { | ||
| debug(`validation failed, ${filename} is not utf-8`) | ||
| return false | ||
| debug.warn(`Validation failed, %s is not utf-8`, filename); | ||
| return false; | ||
| } | ||
| // Files without an applicable jstransformer are ignored | ||
| const extension = extensions[extensions.length - 1] | ||
| const transformer = getTransformer(extension) | ||
| if (!transformer) { | ||
| debug(`validation failed, no jstransformer found for last extension of ${filename}`) | ||
| } | ||
| return transformer | ||
| return true; | ||
| } | ||
@@ -118,14 +195,20 @@ | ||
| * @typedef {Object} Options | ||
| * @property {string} [pattern='**'] (*optional*) Limit the files to process by 1 or more glob patterns. Defaults to `'**'` (all) | ||
| * @property {string|JsTransformer} transform Jstransformer to run: name of a node module or local JS module path (starting with `.`) whose default export is a jstransformer. As a shorthand for existing transformers you can remove the `jstransformer-` prefix: `marked` will be understood as `jstransformer-marked`. Or an actual jstransformer; an object with `name`, `inputFormats`,`outputFormat`, and at least one of the render methods `render`, `renderAsync`, `compile` or `compileAsync` described in the [jstransformer API docs](https://github.com/jstransformers/jstransformer#api) | ||
| * @property {string} [pattern='**\/*.<transform.inputFormats>'] (*optional*) One or more paths or glob patterns to limit the scope of the transform. Defaults to `'**\/*.<transform.inputFormats>*'` | ||
| * @property {Object} [engineOptions={}] (*optional*) Pass options to the jstransformer templating engine that's rendering your files. The default is `{}` | ||
| * @property {boolean} [suppressNoFilesError=false] (*optional*) Decide whether to ignore an error indicating that the plugin didn't find any matching files to process. The default is `false` | ||
| * @property {boolean} [setFilename=false] (*optional*) Some templating engines, like [pug](https://github.com/pugjs/pug), need a `filename` property to be present in the options to be able to process relative includes, extends, etc. Setting this option to `true` will add the current filename to the options passed to each jstransformer. The default is `false` | ||
| * @property {string} [extname] (*optional*) Pass `''` to remove the extension or `'.<extname>'` to keep or rename it. Defaults to `transform.outputFormat` | ||
| **/ | ||
| /** @type {Options} */ | ||
| const defaultOptions = { | ||
| pattern: '**', | ||
| engineOptions: {}, | ||
| suppressNoFilesError: false, | ||
| setFilename: false | ||
| /** | ||
| * Set default options based on jstransformer `transform` | ||
| * @param {JsTransformer} transform | ||
| * @returns {Options} | ||
| */ | ||
| function normalizeOptions(transform) { | ||
| const extMatch = transform.inputFormats.length === 1 ? transform.inputFormats[0] : `{${transform.inputFormats.join(',')}}`; | ||
| return { | ||
| pattern: `**/*.${extMatch}*`, | ||
| extname: `.${transform.outputFormat}`, | ||
| engineOptions: {} | ||
| }; | ||
| } | ||
@@ -138,50 +221,52 @@ | ||
| */ | ||
| function initializeInPlace(options = defaultOptions) { | ||
| const settings = Object.assign({}, defaultOptions, options) | ||
| function inPlace(options = {}) { | ||
| let transform; | ||
| return async function inPlace(files, metalsmith, done) { | ||
| debug = metalsmith.debug('@metalsmith/in-place'); | ||
| return function inPlace(files, metalsmith, done) { | ||
| debug = metalsmith.debug('@metalsmith/in-place') | ||
| debug('Running with options %O', settings) | ||
| // Check whether the pattern option is valid | ||
| if (!(typeof settings.pattern === 'string' || Array.isArray(settings.pattern))) { | ||
| return done( | ||
| new Error( | ||
| 'invalid pattern, the pattern option should be a string or array of strings. See https://www.npmjs.com/package/@metalsmith/in-place#pattern' | ||
| ) | ||
| ) | ||
| if (options.pattern && !(typeof options.pattern === 'string' || Array.isArray(options.pattern))) { | ||
| return done(new Error('invalid pattern, the pattern option should be a string or array of strings. See https://www.npmjs.com/package/@metalsmith/in-place#pattern')); | ||
| } | ||
| // throw update error in case users didn't see the peerDependency warning | ||
| /* istanbul ignore next */ | ||
| if (!metalsmith.match) { | ||
| throw new Error( | ||
| 'This version of @metalsmith/in-place requires metalsmith^2.4.1\'s newly added match method\nPlease update metalsmith"' | ||
| ) | ||
| // skip resolving the transform option on repeat runs | ||
| if (!transform) { | ||
| try { | ||
| transform = await getTransformer(options.transform, debug); | ||
| } catch (err) { | ||
| // pass through jstransformer & Node import resolution errors | ||
| return done(err); | ||
| } | ||
| } | ||
| options = Object.assign(normalizeOptions(transform), options); | ||
| debug('Running with options %O', options); | ||
| const matchedFiles = metalsmith.match(options.pattern); | ||
| const matchedFiles = metalsmith.match(settings.pattern) | ||
| // Filter files by validity, pass basename to avoid dots in folder path | ||
| const validFiles = matchedFiles.filter((filename) => validate({ filename, files })) | ||
| const validFiles = matchedFiles.filter(filename => validate({ | ||
| filename, | ||
| files, | ||
| transform | ||
| })); | ||
| // Let the user know when there are no files to process, usually caused by missing jstransformer | ||
| // Let the user know when there are no files to process | ||
| if (validFiles.length === 0) { | ||
| const message = 'no files to process. See https://www.npmjs.com/package/@metalsmith/in-place#no-files-to-process' | ||
| if (settings.suppressNoFilesError) { | ||
| debug(message) | ||
| return done() | ||
| } | ||
| return done(new Error(message)) | ||
| debug.warn('No valid files to process.'); | ||
| return done(); | ||
| } else { | ||
| debug('Rendering %s files', validFiles.length); | ||
| } | ||
| // Map all files that should be processed to an array of promises and call done when finished | ||
| return Promise.all(validFiles.map((filename) => render({ filename, files, metalsmith, settings }))) | ||
| .then(() => done()) | ||
| .catch(/* istanbul ignore next */ (error) => done(error)) | ||
| } | ||
| return Promise.all(validFiles.map(filename => render({ | ||
| filename, | ||
| files, | ||
| metalsmith, | ||
| options, | ||
| transform | ||
| }))).then(() => done()).catch(error => done(error)); | ||
| }; | ||
| } | ||
| module.exports = initializeInPlace | ||
| export { inPlace as default }; | ||
| //# sourceMappingURL=index.js.map |
+26
-16
| { | ||
| "name": "@metalsmith/in-place", | ||
| "author": "ismay", | ||
@@ -11,4 +12,10 @@ "description": "A metalsmith plugin for in-place templating", | ||
| ], | ||
| "main": "lib/index.js", | ||
| "name": "@metalsmith/in-place", | ||
| "source": "src/index.js", | ||
| "main": "lib/index.cjs", | ||
| "module": "lib/index.js", | ||
| "type": "module", | ||
| "exports": { | ||
| "import": "./lib/index.js", | ||
| "require": "./lib/index.cjs" | ||
| }, | ||
| "repository": { | ||
@@ -22,10 +29,12 @@ "type": "git", | ||
| }, | ||
| "version": "4.6.0", | ||
| "version": "5.0.0", | ||
| "scripts": { | ||
| "changelog": "auto-changelog -u --starting-date 2021-12-01 --sort-commits date-desc --commit-limit false --ignore-commit-pattern '(dev|Release|Merge)'", | ||
| "coverage": "nyc report --reporter=text-lcov > ./coverage.info", | ||
| "changelog": "auto-changelog -u --starting-date 2021-12-01 --commit-limit false --ignore-commit-pattern '^((dev|chore|ci):|Release)'", | ||
| "coverage": "npm test && c8 report --reporter=text-lcov > ./coverage.info", | ||
| "format": "prettier --write \"**/*.{yml,md,js,json}\"", | ||
| "format:check": "prettier --list-different \"**/*.{yml,md,js,json}\"", | ||
| "test": "nyc mocha", | ||
| "test": "c8 mocha", | ||
| "release": "release-it", | ||
| "build": "microbundle --target node -f cjs,esm --strict --generateTypes=false", | ||
| "prepack": "npm run build", | ||
| "lint": "eslint --fix .", | ||
@@ -37,18 +46,19 @@ "lint:check": "eslint --fix-dry-run ." | ||
| "auto-changelog": "^2.4.0", | ||
| "eslint": "^8.29.0", | ||
| "eslint-config-prettier": "^8.5.0", | ||
| "c8": "^7.14.0", | ||
| "eslint": "^8.45.0", | ||
| "eslint-config-prettier": "^8.8.0", | ||
| "eslint-plugin-import": "^2.26.0", | ||
| "eslint-plugin-n": "^15.5.1", | ||
| "husky": "^7.0.4", | ||
| "eslint-plugin-n": "^16.0.1", | ||
| "husky": "^8.0.3", | ||
| "jstransformer-handlebars": "^1.2.0", | ||
| "jstransformer-marked": "^1.2.0", | ||
| "jstransformer-pug": "^0.4.0", | ||
| "metalsmith": "^2.5.1", | ||
| "mocha": "^9.2.2", | ||
| "metalsmith": "^2.6.1", | ||
| "microbundle": "^0.15.1", | ||
| "mocha": "^10.2.0", | ||
| "nyc": "^15.1.0", | ||
| "prettier": "^2.8.0", | ||
| "release-it": "^15.5.1" | ||
| "prettier": "^3.0.0", | ||
| "release-it": "^16.1.2" | ||
| }, | ||
| "dependencies": { | ||
| "inputformat-to-jstransformer": "^1.2.1", | ||
| "is-utf8": "^0.2.1", | ||
@@ -71,4 +81,4 @@ "jstransformer": "^1.0.0" | ||
| "engines": { | ||
| "node": ">=12" | ||
| "node": ">=14.14.0" | ||
| } | ||
| } |
+130
-78
| # @metalsmith/in-place | ||
| A metalsmith plugin for transforming your source files | ||
| A metalsmith plugin for transforming source files' contents. Complements [@metalsmith/layouts](https://github.com/metalsmith/layouts) | ||
@@ -11,5 +11,7 @@ [![metalsmith: core plugin][metalsmith-badge]][metalsmith-url] | ||
| This plugin allows you to render templating syntax in your source files. It uses file extensions to infer which templating engine to use. So files ending in `.njk` will be processed as nunjucks, `.md` as markdown, etc. You can even chain transformations by appending multiple extensions, which will be processed right-to-left. | ||
| ## Features | ||
| If you want to wrap your source files in a common template, you can use [@metalsmith/layouts](https://github.com/metalsmith/metalsmith/layouts). For usage examples check out our [wiki](https://github.com/metalsmith/metalsmith/in-place/wiki). Feel free to contribute an example if anything is missing, or update the existing ones. For templating engine specific questions try the aforementioned channels, as well as the documentation for [jstransformers](https://github.com/jstransformers) and your templating engine of choice. | ||
| - renders source files' `contents` field with any existing or a custom [Jstransformer templating engine](https://github.com/jstransformers/jstransformer) | ||
| - alters file extensions from `transform.inputFormats` to `transform.outputFormat` | ||
| - can be used multiple times with different configs per metalsmith pipeline | ||
@@ -21,3 +23,3 @@ ## Installation | ||
| ```bash | ||
| npm install @metalsmith/in-place | ||
| npm install @metalsmith/in-place jstransformer-handlebars | ||
| ``` | ||
@@ -28,83 +30,92 @@ | ||
| ```bash | ||
| yarn add @metalsmith/in-place | ||
| yarn add @metalsmith/in-place jstransformer-handlebars | ||
| ``` | ||
| This plugin works with [jstransformers](https://github.com/jstransformers/jstransformer) but they should be installed separately. `jstransformer-handlebars` is just an example, you could use any transformer. To render markdown you could install [jstransformer-marked](https://github.com/jstransformers/jstransformer-marked). To render handlebars you would install [jstransformer-handlebars](https://github.com/jstransformers/jstransformer-handlebars). Other popular templating options include: [Nunjucks](https://github.com/jstransformers/jstransformer-nunjucks), [Twig](https://github.com/jstransformers/jstransformer-twig), [Pug](https://github.com/jstransformers/jstransformer-pug), or [EJS](https://github.com/jstransformers/jstransformer-ejs). See also [this map](https://github.com/jstransformers/inputformat-to-jstransformer/blob/master/dictionary.json) to see which extensions map to which jstransformer. | ||
| ## Usage | ||
| This plugin uses [jstransformers](https://github.com/jstransformers/jstransformer) to transform files. Since there are a lot of jstransformers we don't install them automatically, so you'll also need to install the appropriate jstransformers. | ||
| Pass `@metalsmith/in-place` to `metalsmith.use` : | ||
| For example, to render markdown you would install [jstransformer-markdown](https://github.com/jstransformers/jstransformer-markdown). To render handlebars you would install [jstransformer-handlebars](https://github.com/jstransformers/jstransformer-handlebars). Other popular templating options are: Nunjucks, Twig, Pug, EJS. See the [jstransformer organisation](https://github.com/jstransformers) for all available jstransformers and [this dictionary](https://github.com/jstransformers/inputformat-to-jstransformer/blob/master/dictionary.json) to see which extensions map to which jstransformer. | ||
| ```js | ||
| import inPlace from '@metalsmith/in-place' | ||
| ## Options | ||
| // shorthand | ||
| metalsmith.use(inPlace({ transform: 'nunjucks' })) | ||
| You can pass options to `@metalsmith/in-place` with the [Javascript API](https://github.com/segmentio/metalsmith#api) or [CLI](https://github.com/segmentio/metalsmith#cli). The options are: | ||
| // same as shorthand | ||
| metalsmith.use( | ||
| inPlace({ | ||
| transform: jsTransformerNunjucks, // resolved | ||
| extname: '.html', | ||
| pattern: '**/*.{njk,nunjucks}*', | ||
| engineOptions: {} | ||
| }) | ||
| ) | ||
| ``` | ||
| - [pattern](#pattern): optional. Only files that match this pattern will be processed. Accepts a string or an array of strings. The default is `**`. | ||
| - [engineOptions](#engineoptions): optional. Use this to pass options to the jstransformer that's rendering your files. The default is `{}`. | ||
| - [suppressNoFilesError](#suppressnofileserror): optional. The no-files-to-process error will be suppressed. The default is `false`. | ||
| - [setFilename](#setfilename): optional. Some templating engines, like [pug](https://github.com/pugjs/pug), need a `filename` property to be present in the options to be able to process relative includes, extends, etc. Setting this option to `true` will add the current filename to the options passed to each jstransformer. The default is `false`. | ||
| In the transformed file, you have access to `{ ...metalsmith.metadata(), ...fileMetadata }`, so that the following build | ||
| ### `pattern` | ||
| ```js | ||
| metalsmith.metadata({ title: 'Default title', nodeVersion: process.version }).use(inPlace({ transform: 'handlebars' })) | ||
| ``` | ||
| Only files that match this pattern will be processed. So this `metalsmith.json`: | ||
| for a file: | ||
| ```json | ||
| { | ||
| "source": "src", | ||
| "destination": "build", | ||
| "plugins": { | ||
| "@metalsmith/in-place": { | ||
| "pattern": "blog/**/*" | ||
| } | ||
| } | ||
| } | ||
| ```yml | ||
| --- | ||
| title: Article title | ||
| --- | ||
| <h1>{{ title }}</h1>Node v{{ nodeVersion }} | ||
| ``` | ||
| Would only process files within the `./src/blog` folder, because the pattern is | ||
| relative to your source folder. See [Metalsmith#match](https://metalsmith.io/api/#Metalsmith+match) | ||
| for further details. | ||
| would render `<h1>Article title</h1>Node v16.20` | ||
| ### `engineOptions` | ||
| Multiple transforms can be used to target different sets of files, or to reprocess the same files multiple times in the order they are `metalsmith.use`'d: | ||
| Use this to pass options to the jstransformer that's rendering your templates. So this | ||
| `metalsmith.json`: | ||
| ```js | ||
| // this build will apply the marked transform to index.md, the handlebars transform to index.hbs, | ||
| // and handlebars first, marked second to both index.hbs.md, index.md.hbs, and html-minifier to all (only in production) | ||
| metalsmith | ||
| .env('NODE_ENV', process.env.NODE_ENV) | ||
| .use(inPlace({ transform: 'handlebars', extname: null })) | ||
| .use(inPlace({ transform: 'marked' })) | ||
| ```json | ||
| { | ||
| "source": "src", | ||
| "destination": "build", | ||
| "plugins": { | ||
| "@metalsmith/in-place": { | ||
| "engineOptions": { | ||
| "cache": false | ||
| } | ||
| } | ||
| } | ||
| if (metalsmith.env('NODE_ENV') !== 'development') { | ||
| metalsmith.use(inPlace({ transform: 'html-minifier' })) | ||
| } | ||
| ``` | ||
| Would pass `{ "cache": false }` to each used jstransformer. | ||
| ### Options | ||
| ### `suppressNoFilesError` | ||
| In most cases, you will only need to specify the `transform` and `engineOptions` option. | ||
| `@metalsmith/in-place` exits with [an error](#no-files-to-process) if it can’t find any files to process. If you’re doing any kind of incremental builds via something like `metalsmith-watch`, this is problematic as you’re likely only rebuilding files that have changed. This flag allows you to suppress that error. So this `metalsmith.json`: | ||
| - [transform](#transform) (`string|JsTransformer`): **required**. Which transformer to use. The full name of the transformer, e.g. `jstransformer-handlebars`, its shorthand `handlebars`, a relative JS module path starting with `.`, e.g. `./my-transformer.js`, whose default export is a jstransformer or an actual jstransformer: an object with `name`, `inputFormats`,`outputFormat`, and at least one of the render methods `render`, `renderAsync`, `compile` or `compileAsync` described in the [jstransformer API docs](https://github.com/jstransformers/jstransformer#api) | ||
| - [extname](#extension-handling) (`string|false|null`): optional. How to transform a file's extensions: `''|false|null` to remove the last `transform.inputFormat` matching extension, `.<ext>` to force an extension rename. | ||
| - [engineOptions](#engineoptions) (`Object<string, any>`): optional. Pass options to the jstransformer that's rendering the files. The default is `{}`. | ||
| - pattern (`string|string[]`): optional. Override default glob pattern matching `**/*.<transform.inputFormats>*`. Useful to limit the scope of the transform by path or glob to a subfolder, or to include files not matching `transform.inputFormats`. | ||
| ```json | ||
| { | ||
| "source": "src", | ||
| "destination": "build", | ||
| "plugins": { | ||
| "@metalsmith/in-place": { | ||
| "suppressNoFilesError": true | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
| ### Extension handling | ||
| Would suppress the error if there aren't any files to process. Note that when this option is turned on, if you're logging [debug messages](#errors-and-debugging), you’ll still see a message denoting when there aren't any files for metalsmith-layouts to process. | ||
| By default in-place will apply smart default extension handling based on `transform.inputFormats` and `transform.outputFormat`. | ||
| For example, any of the source files below processed through `inPlace({ transform: 'handlebars' })` will yield `index.html`. | ||
| ### `setFilename` | ||
| | source | output | | ||
| | ------------------ | ---------------- | | ||
| | src/index.hbs | build/index.html | | ||
| | src/index.hbs.html | build/index.html | | ||
| | src/index.html.hbs | build/index.html | | ||
| Set this option to `true` if you want to pass the current filename to each jstransformer. The default is `false`. So this `metalsmith.json`: | ||
| The example demonstrates that: | ||
| - order of extensions doesn't matter, _order of plugin execution does!_: you can pick the final extension to match the most suitable editor syntax highlighting | ||
| - a single in-place run only alters the rightmost extension matching `transform.inputFormats` | ||
| - you may choose to include or omit the `transform.outputFormat` in the source file name (.html in this case). | ||
| ### `engineOptions` | ||
| Pass options to the jstransformer that's rendering your templates via `engineOptions`. The | ||
| `metalsmith.json`: | ||
| ```json | ||
@@ -117,3 +128,6 @@ { | ||
| "@metalsmith/in-place": { | ||
| "setFilename": true | ||
| "transform": "ejs", | ||
| "engineOptions": { | ||
| "cache": false | ||
| } | ||
| } | ||
@@ -125,34 +139,72 @@ } | ||
| Would overwrite `engineOptions.filename` with the absolute path for the file that's currently being processed, and pass that to the jstransformer. For now we're just passing `filename`, but if you encounter a jstransformer that requires a different property, like `path` or something else, let us know and we can add it. | ||
| ..would pass `{ "cache": false }` to `jstransformer-ejs`. | ||
| ## Errors and debugging | ||
| If you use [Pug](https://pugjs.org/api/getting-started.html), make sure to pass `engineOptions: { filename: true }`. This will ensure the filename of each processed file is passed to the render method as expected by this engine. | ||
| If you're encountering problems you can use [debug](https://www.npmjs.com/package/debug) to enable verbose logging. To enable `debug` prefix your build command with `DEBUG=@metalsmith/in-place`. So if you normally run `metalsmith` to build, use `DEBUG=@metalsmith/in-place metalsmith` (on windows the syntax is [slightly different](https://www.npmjs.com/package/debug#windows-note)). | ||
| ### Multiple transforms per file | ||
| ### No files to process | ||
| Suppose a file `tags.hbs` that lists all the article tags used on your website | ||
| There are several things that might cause you to get a `no files to process` error: | ||
| ```hbs | ||
| --- | ||
| title: Tags | ||
| description: Browse articles by tag | ||
| --- | ||
| <h1>{{ title }}</h1> | ||
| <p>{{ description }}</p> | ||
| <ul> | ||
| {{#each tags}} | ||
| <li><a href="/tags/{{ . }}">{{ . }}</a></li> | ||
| {{/each}} | ||
| </ul> | ||
| ``` | ||
| - Your [pattern](#pattern) does not match any files | ||
| - None of your files pass validation, validation fails for files that: | ||
| - Have no extension | ||
| - Are not utf-8 | ||
| - Need a jstransformer that hasn't been installed | ||
| To reduce Handlebars noise, you could add `metalsmith.use(inPlace({ transform: 'marked' })` to your build and change the filename to `tags.hbs.md` to generate markdown syntax with Handlebars! | ||
| ### Debug | ||
| ```hbs | ||
| --- | ||
| title: Tags | ||
| description: Browse articles by tag | ||
| --- | ||
| To enable debug logs, set the `DEBUG` environment variable to `@metalsmith/in-place`: | ||
| # {{ title }} | ||
| Linux/Mac: | ||
| {{ description }} | ||
| ```bash | ||
| export DEBUG=@metalsmith/in-place | ||
| {{#each tags}} | ||
| - [{{.}}](/tags/{{ . }}) | ||
| {{/each}} | ||
| More markdown here.. | ||
| ``` | ||
| Windows: | ||
| **Caution**: when using multiple templating transforms per file, make sure there is no conflicting syntax. | ||
| For example markdown will transform blocks indented by 4 spaces to `<pre>` tags, and marked's `smartypants` can potentially garble the result. | ||
| ```bat | ||
| set "DEBUG=@metalsmith/in-place" | ||
| ### Usage with @metalsmith/layouts | ||
| In most cases `@metalsmith/in-place` is intended to be used _before_ `@metalsmith/layouts`. | ||
| You can easily share `engineOptions` configs between both plugins: | ||
| ```js | ||
| import inPlace from '@metalsmith/in-place' | ||
| import layouts from '@metalsmith/layouts' | ||
| const engineOptions = {} | ||
| metalsmith // index.hbs.hbs | ||
| .use(inPlace({ transform: 'handlebars', extname: '', engineOptions })) // -> index.hbs | ||
| .use(layouts({ engineOptions })) // -> index.html | ||
| ``` | ||
| @metalsmith/layouts uses a similar mechanism targeting `transform.inputFormats` file extensions by default. | ||
| The example requires files ending in `.hbs.hbs` extension, but if you don't like this, you can just have a single `.hbs` extension, and change the in-place invocation to `inPlace({ engineOptions, transform, extname: '.hbs' })` for the same result. | ||
| ### Debug | ||
| To enable debug logs, set the `DEBUG` environment variable to `@metalsmith/in-place*`: | ||
| ```js | ||
| metalsmith.env('DEBUG', '@metalsmith/in-place*') | ||
| ``` | ||
| Alternatively you can set `DEBUG` to `@metalsmith/*` to debug all Metalsmith core plugins. | ||
@@ -159,0 +211,0 @@ |
| const jstransformer = require('jstransformer') | ||
| const toTransformer = require('inputformat-to-jstransformer') | ||
| /** | ||
| * Gets jstransformer for an extension, and caches them | ||
| */ | ||
| const cache = {} | ||
| function getTransformer(ext) { | ||
| if (ext in cache) { | ||
| return cache[ext] | ||
| } | ||
| const transformer = toTransformer(ext) | ||
| cache[ext] = transformer ? jstransformer(transformer) : false | ||
| return cache[ext] | ||
| } | ||
| module.exports = getTransformer |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
67076
281.81%3
-25%8
60%569
246.95%227
29.71%Yes
NaN17
13.33%1
Infinity%- Removed
- Removed
- Removed