关于 metalsmith.get/set() 帮助函数的提案

作者: webketje创建于 2022年12月21日更新于 2023年10月1日

Context

It is a frequent requirement for plugins to access and manipulate properties on metalsmith metadata or files. Retrieving and setting these properties is not always worry-free. For example, if a plugin wishes to allow users to specify plugin options to be read from a YAML file inside metalsmith.source(), let's say @metalsmith/layouts:

yaml
# src/layouts.config.yaml
---
directory: 'src/layouts'
pattern: '**/*.html'
engineOptions:
  gfm: true
---

it needs to check if the file is found, and do null-safe gets to nested properties

javascript
const confFile = files['layouts.config.yaml']
if (confFile) {
  if (confFile.engineOptions && confFile.engineOptions.gfm) { /* code */  }
}

This could be shortened to:

javascript
if (metalsmith.get('layouts.config.yaml', 'engineOptions.gfm')) { /* code */  }

Another need (or inflexibility) is that a lot of plugins "dictate" the key path in the file metadata they read config options from. For example using @metalsmith/layouts you must specify the key layout: in metadata. This will be ok for some (if not most) users, but other users may prefer to introduce different namespaces in front-matter (eg. translations, config, seo, content). So if the user would prefer reading the layout value from config.layout they should have a way to do that, without putting the onus of implementing the mechanism on the plugin developer. Building on the @metalsmith/layouts example, this would allow

javascript
Object.keys(files).forEach(path) => {
  metalsmith.set(metalsmith.get(path), 'contents', compiled)
})

// or better
const { get, set } = metalsmith
Object.keys(files).forEach(path => {
  set(get(path), 'contents', compiled)
})

内容来源: metalsmith/metalsmith