Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLI: add mechanism to pass callbacks as plugin options through metalsmith.json #370

Open
webketje opened this issue May 1, 2022 · 1 comment

Comments

@webketje
Copy link
Member

webketje commented May 1, 2022

The aim would be to allow function type options to be passed through metalsmith.json, so one is not forced to use the JS approach, say if for example we want to use the slug option of @metalsmith/permalinks: https://github.com/metalsmith/permalinks#custom-slug-function

ms.use(permalinks({ slug(path) { return path } })

There should be a way to refer to functions in another file in Metalsmith directory & its node_modules
we could think of something like:

{
  "plugins": [
     {"@metalsmith/permalinks": { "slug": "file://./config/permalinks" }}
  ]
}

The issue is what will the "marker" be.
file://? function:// ? @.

Also, if something generic is used, like file://, name collision could occur easily, but it would also allow to construct a metalsmith.json from separate config files loaded into placeholders ( a bit like a lot of MVC frameworks allow to split config over multiple files, eg spring boot, laravel)
This feature will add some parsing overhead as it needs to deep-walk all plugin options and replace values matching the marker with their respective exports.

@webketje webketje changed the title CLI: add mechanism to pass callbacks as plugin options through package.json CLI: add mechanism to pass callbacks as plugin options through metalsmith.json May 16, 2022
@webketje
Copy link
Member Author

webketje commented Sep 5, 2023

A custom JSON reviver would be nice, ideally could just do:

JSON.parse(jsonText, async (key, value) => {
  if (value.startsWith('@from:')) {
    const importPath = path.resolve(metalsmith.directory(), value.slice('@from:'.length))
    const resolved = await import(importPath)
    return resolved.default
  }
  return value
})

But the problem is it needs to be async to use dynamic import (not supported by JSON.parse reviver) and have a reference to the full keypath from root to be able to set the resolved import to target later. Example

const imports = []
const config = JSON.parse(jsonText, (key, value) => {
  if (value.startsWith('@from:')) {
    const importPath = path.resolve(metalsmith.directory(), value.slice('@from:'.length))
    imports.push(import(importPath).then(imported => {
      return {
        imported: imported.default,
        keypath: getFullKeyPathSomehow()
      }
    }))
  }
  return value
})

Promise.all(imports).then(({ keypath, imported }) => {
  _.set(config, keypath, imported)
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant