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

Common use case enhancements #179

Closed
webketje opened this issue Jun 3, 2022 · 1 comment
Closed

Common use case enhancements #179

webketje opened this issue Jun 3, 2022 · 1 comment

Comments

@webketje
Copy link
Member

webketje commented Jun 3, 2022

First some observations:

  1. When in-place doesn't find the first transformer for a file (matching the rightmost extension), it leaves it untouched.
  2. Repeating the same extension multiple times will lead to reprocessing = bugs (eg index.njk.njk.md.njk.md)
  3. It is impossible to pass a custom transformer because the logic is handled behind-the-scenes by a hardcoded list of "input-to-jstransformer". As a first step local transformers could be linked in package.json as "jstransformer-local": "file:jstransformer-local"
  4. When more than one transformer is used, engineOptions are a mixed config passed to all transformers, this is less than ideal.
  5. extension chaining: Although technically in-place would process a file index.ejs.md.njk.twig.hbs if all transformers are installed, nobody in their right mind would mix 5 templating languages with conflicting syntaxes.
  6. markdown convenience: When using @metalsmith/markdown or jstransformer-marked with in-place, the desirable extension order is always *.md at the end to enable markdown syntax highlighting in code editors. But running markdown before other transformers is highly likely to garble the intermixed syntax. An alternative to combining markdown is registering a custom markdown helper in the template language of choice
  7. in-place/ layouts interop: There are 2 ways to use both layouts & in-place functionality: the first is to use the 2 plugins (in-place first, then layouts).
    The second is to use in-place only and use templating constructs inside content files with "slots", eg for nunjucks: {% extends 'layout.njk' %}. The first is convenient because layouts can be applied through file frontmatter (or assigned with plugins). The second needs to "wrap" the content in each file. However, both plugins rename the extensions to html, which forces the second one to use a target pattern ending in .html.

Some potential solutions:

  1. Alternative matching algo with noop for unmatched extensions
  2. Filter extensions by unique starting from the right
  3. remove inputformat-to-jstransformer dependency or use as fallback, allow explicitly passing jstransformers through a new option
  4. split engineOptions in subkeys, eg engineOptions: { marked: {...}, nunjucks: {...}
  5. None
  6. When detecting .md, always move it to the last position to be processed (leaky)
  7. Provide an extRename option: false|true|<ext>
@webketje
Copy link
Member Author

webketje commented Jun 4, 2023

On second thought, the multiple file extension in order processing makes the plugin way too complicated. Problems encountered are mainly incompatibilities between multiple parsers, syntax highlighting mismatch for the user, and a harder to follow debug trace for the recursive render function. For example the marked smartypants option transforms double quotes, and marked surrounds every newline with <p></p> tags, making it impossible to use a index.njk.md file, only index.md.njk (somehow) works. Yet this is undesirable as in 99,99% of cases we want the file to be formatted as markdown.

Multiple file extension in order processing should not be an inherent part of a single run of this plugin. The same can be accomplished with 2 runs of in-place and configurable extension handling:

const markedTransformer = require('jstransformer-marked')
const customTransformer = {
  inputFormats: ['html'],
  render(str) {
    return str.replace('Hello', 'Bye')
  }
}

// by default pattern would always be new RegExp(`**/*.{${transformer.inputFormats.join('|')}}*`)
// can still be overwritten with pattern option
// in example below, using the extname option, a file 'index.njk.md'  would first be renamed to 'index.md', then to 'index.html', then the extension would be left untouched.

metalsmith
  .use(inPlace({
    // can do the require/import behind-the-scenes, required for CLI
    // also works with local transformers eg './my-transform.js'
    transform: 'jstransformer-nunjucks',
    extname: 'remove',
    engineOptions: { }
  }))
  .use(inPlace({
    transform: markedTransformer,
    extname: 'replace'
  }))
  .use(inPlace({
    transform: customTransformer,
    extname: 'keep'
  }))

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