Skip to content

Commit

Permalink
feat/#379 - use lodash.clonedeepwith instead, document watch type, fi…
Browse files Browse the repository at this point in the history
…x issues in CLI
  • Loading branch information
webketje committed May 28, 2023
1 parent 9d40674 commit e12537f
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 63 deletions.
50 changes: 26 additions & 24 deletions bin/metalsmith
Expand Up @@ -121,33 +121,35 @@ async function buildCommand({ config, ...cliOptions }) {
* Plugins.
*/

normalize(spec.plugins).forEach(function (plugin) {
for (const name in plugin) {
const opts = plugin[name]
let mod

try {
const local = resolve(confRelativeDir, name)
const npm = resolve(confRelativeDir, 'node_modules', name)

if (exists(local) || exists(`${local}.js`)) {
mod = require(local)
} else if (exists(npm)) {
mod = require(npm)
} else {
mod = require(name)
if (!(spec instanceof Metalsmith)) {
normalize(spec.plugins).forEach(function (plugin) {
for (const name in plugin) {
const opts = plugin[name]
let mod

try {
const local = resolve(confRelativeDir, name)
const npm = resolve(confRelativeDir, 'node_modules', name)

if (exists(local) || exists(`${local}.js`)) {
mod = require(local)
} else if (exists(npm)) {
mod = require(npm)
} else {
mod = require(name)
}
} catch (e) {
fatal(`failed to require plugin "${name}".`)
}
} catch (e) {
fatal(`failed to require plugin "${name}".`)
}

try {
metalsmith.use(mod(opts))
} catch (e) {
fatal(`error using plugin "${name}"...`, `${e.message}\n\n${e.stack}`)
try {
metalsmith.use(mod(opts))
} catch (e) {
fatal(`error using plugin "${name}"...`, `${e.message}\n\n${e.stack}`)
}
}
}
})
})
}

function onBuild(message) {
return (err) => {
Expand Down
49 changes: 34 additions & 15 deletions lib/index.js
Expand Up @@ -433,22 +433,41 @@ Metalsmith.prototype.build = function (callback) {
}
})
}
return Promise.resolve()
})
.then(
this.process.bind(this, (err, files) => {
if (err) throw err
return this.write(files)
.then(() => {
if (this[symbol.log]) this[symbol.log].end()
if (isFunction(callback)) callback(null, files)
})
.catch(callback)
.catch((err) => {
if (isFunction(callback)) {
callback(err)
}
return Promise.reject(err)
})
.then(() => {
return new Promise((resolve, reject) => {
this.process((err, files) => {
if (err) {
if (isFunction(callback)) {
callback(err)
}
reject(err)
return
}

this.write(files)
.catch((err) => {
if (isFunction(callback)) callback(err)
reject(err)
})
.then(() => {
if (this[symbol.log]) this[symbol.log].end()
if (isFunction(callback)) callback(null, files)
resolve(files)
})
})
})
)
})

/* block required for Metalsmith 2.x callback-flow compat */
if (isFunction(callback)) {
result.then((files) => callback(null, files), callback)
} else {
if (!isFunction(callback)) {
return result
}
}
Expand Down Expand Up @@ -528,7 +547,7 @@ Metalsmith.prototype.watch = function (options) {
*/

Metalsmith.prototype.process = function (callback) {
const result = this.read(this.source())
let result = this.read(this.source())

if (this.watch()) {
return result.then((files) => {
Expand All @@ -538,7 +557,7 @@ Metalsmith.prototype.process = function (callback) {
})
})
} else {
result.then((files) => this.run(files, this.plugins))
result = result.then((files) => this.run(files, this.plugins))

/* block required for Metalsmith 2.x callback-flow compat */
if (callback) {
Expand Down
12 changes: 5 additions & 7 deletions lib/watcher.js
@@ -1,6 +1,6 @@
const chokidar = require('chokidar')
// to be replaced in distant future by native structuredClone when dropping Node <17 support
const cloneDeep = require('lodash.clonedeep')
const cloneDeepWith = require('lodash.clonedeepwith')
const crypto = require('crypto')
const { relative } = require('path')
const { rm } = require('./helpers')
Expand Down Expand Up @@ -40,7 +40,10 @@ module.exports = function watchable(files, metalsmith) {
let lastHashmap

function rerun() {
return metalsmith.metadata(meta).run(cloneDeep(fileCache), metalsmith.plugins)
const originalFiles = cloneDeepWith(fileCache, (value) => {
if (Buffer.isBuffer(value)) return Buffer.from(value)
})
return metalsmith.metadata(meta).run(originalFiles, metalsmith.plugins)
}

function transformFilesObj(evt, p, metalsmith) {
Expand Down Expand Up @@ -78,9 +81,6 @@ module.exports = function watchable(files, metalsmith) {
let run

watcher.on('all', (evt, p) => {
// eslint-disable-next-line no-console
console.log(evt, p)

// the metalsmith Files object does not output empty dirs,
// wait for the file add/change events instead
if (evt === 'addDir') return
Expand Down Expand Up @@ -120,8 +120,6 @@ module.exports = function watchable(files, metalsmith) {
return all
}, {})
lastHashmap = newHashMap
// eslint-disable-next-line no-console
console.log({ addedFiles, removedFiles, changedFiles })

Promise.all(removedFiles.map((f) => rm(f)))
.then(() => onRebuild(null, output), onRebuild)
Expand Down
16 changes: 8 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -66,7 +66,7 @@
"debug": "^4.3.4",
"gray-matter": "^4.0.3",
"is-utf8": "~0.2.0",
"lodash.clonedeep": "^4.5.0",
"lodash.clonedeepwith": "^4.5.0",
"micromatch": "^4.0.5",
"stat-mode": "^1.0.0",
"ware": "^1.3.0"
Expand Down
26 changes: 18 additions & 8 deletions types/index.d.ts
@@ -1,12 +1,5 @@
// Type definitions for metalsmith 2.6
// Project: https://github.com/metalsmith/metalsmith
// Definitions by: Brian Lagerman <https://github.com/brian-lagerman>, Kevin Van Lierde <https://github.com/webketje>
// Definitions: https://github.com/metalsmith/metalsmith
// TypeScript Version: 3.1

/// <reference types="node" />
/// <reference types="micromatch" />
/// <reference types="debug" />

import { Stats } from 'fs';
import { Mode } from 'stat-mode';
import { Debugger as DebugDebugger } from 'debug';
Expand Down Expand Up @@ -160,6 +153,23 @@ declare class Metalsmith {
* const on = metalsmith.frontmatter() // true or false
*/
frontmatter(): boolean;
/**
* Set the list of paths to watch and trigger rebuilds on. The watch method will skip files ignored with {@linkcode Metalsmith.ignore}
* and will do partial (true) or full (false) rebuilds depending on the {@linkcode Metalsmith.clean} setting.
* It can be used both for rebuilding in-memory with {@linkcode Metalsmith.process} or writing to file system with {@linkcode Metalsmith.build},
* [API Docs](https://metalsmith.io/api/#Metalsmith+watch) | [Source code](https://github.com/metalsmith/metalsmith/blob/v2.6.0/lib/index.js#L352)
* @default false
* @example
* metalsmith
* .ignore(['wont-be-watched']) // ignored
* .clean(false) // do partial rebuilds
* .watch(true) // watch all files in metalsmith.source()
* .watch(['lib','src']) // or watch files in directories 'lib' and 'src'
*/
watch(
/** `true` or `false` to watch {@linkcode Metalsmith.source}, or one or more paths/ globs */
watch: boolean|string|string[]
): Metalsmith;
/**
* Get a single metalsmith environment variable. Metalsmith env vars are case-insensitive.
* [API Docs](https://metalsmith.io/api/#Metalsmith+env) | [Source code](https://github.com/metalsmith/metalsmith/blob/v2.6.0/lib/index.js#L352)
Expand Down

0 comments on commit e12537f

Please sign in to comment.