Skip to content

Commit

Permalink
Add set filename option (#169)
Browse files Browse the repository at this point in the history
* Add set filename option

* Update readme
  • Loading branch information
ismay committed Apr 14, 2019
1 parent 1c00ac9 commit c2e4a15
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 18 deletions.
35 changes: 33 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ You can pass options to `metalsmith-in-place` with the [Javascript API](https://
* [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`.

### `pattern`

Expand Down Expand Up @@ -71,9 +72,39 @@ Would pass `{ "cache": false }` to each used jstransformer.

### `suppressNoFilesError`

`metalsmith-in-place` throws [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 ([more info](https://github.com/metalsmith/metalsmith-in-place/pull/151)).
`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`:

Note that if you have [debugging](#errors-and-debugging) turned on, you’ll see a message denoting that no files are present for processing.
```json
{
"source": "src",
"destination": "build",
"plugins": {
"metalsmith-in-place": {
"suppressNoFilesError": true
}
}
}
```

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.

### `setFilename`

Set this option to `true` if you want to pass the current filename to each jstransformer. The default is `false`. So this `metalsmith.json`:

```json
{
"source": "src",
"destination": "build",
"plugins": {
"metalsmith-in-place": {
"setFilename": true
}
}
}
```

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.

## Errors and debugging

Expand Down
37 changes: 21 additions & 16 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const path = require('path');
const debug = require('debug')('metalsmith-in-place');
const match = require('multimatch');
const isUtf8 = require('is-utf8');
Expand All @@ -7,9 +8,11 @@ const getTransformer = require('./get-transformer');
* Engine, renders file contents with all available transformers
*/

function render({ filename, files, metadata, engineOptions }) {
function render({ filename, files, metalsmith, settings }) {
const [base, ...extensions] = filename.split('.');
const file = files[filename];
const engineOptions = Object.assign({}, settings.engineOptions);
const metadata = metalsmith.metadata();

debug(`rendering ${filename}`);

Expand All @@ -24,32 +27,38 @@ function render({ filename, files, metadata, engineOptions }) {
}

// Stringify file contents
file.contents = file.contents.toString();
const contents = file.contents.toString();

// If this is the last extension, replace it with a new one
if (extensions.length === 0) {
debug(`last extension reached, replacing last extension with ${transform.outputFormat}`);
extensions.push(transform.outputFormat);
}

// 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);
}

// Transform the contents
debug(`rendering ${ext} extension for ${filename}`);

return transform
.renderAsync(file.contents, engineOptions, locals)
.renderAsync(contents, engineOptions, locals)
.then(rendered => {
// Update contents and delete old file
file.contents = Buffer.from(rendered.body);
// Delete old file
delete files[filename]; // eslint-disable-line no-param-reassign

// Update files with the newly rendered file
const newName = [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

debug(`done rendering ${filename}, renamed to ${newName}`);

// Keep rendering until there are no applicable transformers left
return render({ filename: newName, files, metadata, engineOptions });
return render({ filename: newName, files, metalsmith, settings });
})
.catch(err => {
err.message = `${filename}: ${err.message}`; // eslint-disable-line no-param-reassign
Expand Down Expand Up @@ -95,10 +104,10 @@ module.exports = options => (files, metalsmith, done) => {
const defaults = {
pattern: '**',
engineOptions: {},
suppressNoFilesError: false
suppressNoFilesError: false,
setFilename: false
};
const settings = Object.assign({}, defaults, options);
const metadata = metalsmith.metadata();

// Check whether the pattern option is valid
if (!(typeof settings.pattern === 'string' || Array.isArray(settings.pattern))) {
Expand All @@ -116,22 +125,18 @@ module.exports = options => (files, metalsmith, done) => {

// Let the user know when there are no files to process, usually caused by missing jstransformer
if (validFiles.length === 0) {
const msg =
const message =
'no files to process. See https://www.npmjs.com/package/metalsmith-in-place#no-files-to-process';
if (settings.suppressNoFilesError) {
debug(msg);
debug(message);
done();
} else {
done(new Error(msg));
done(new Error(message));
}
}

// Map all files that should be processed to an array of promises and call done when finished
Promise.all(
validFiles.map(filename =>
render({ filename, files, metadata, engineOptions: settings.engineOptions })
)
)
Promise.all(validFiles.map(filename => render({ filename, files, metalsmith, settings })))
.then(() => done())
.catch(/* istanbul ignore next */ error => done(error));
};
17 changes: 17 additions & 0 deletions lib/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,4 +236,21 @@ describe('metalsmith-in-place', () => {
done();
});
});

it('should accept an option to set the filename in engine options', done => {
const base = path.join(process.cwd(), 'test', 'fixtures', 'set-filename');
const actual = path.join(base, 'build');
const expected = path.join(base, 'expected');
const metalsmith = new Metalsmith(base);

rimraf.sync(actual);

return metalsmith.use(plugin({ setFilename: true })).build(err => {
if (err) {
return done(err);
}
expect(() => equal(actual, expected)).not.toThrow();
return done();
});
});
});
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"inputformat-to-jstransformer": "^1.2.1",
"is-utf8": "^0.2.1",
"jstransformer": "^1.0.0",
"jstransformer-pug": "^0.3.0",
"multimatch": "^3.0.0"
}
}
1 change: 1 addition & 0 deletions test/fixtures/set-filename/expected/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!doctype html><html lang="en"><body><h1>This is a heading</h1></body></html>
4 changes: 4 additions & 0 deletions test/fixtures/set-filename/src/index.pug
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
extends ../templates/base.pug

block content
h1 This is a heading
4 changes: 4 additions & 0 deletions test/fixtures/set-filename/templates/base.pug
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<!doctype html>
html(lang="en")
body
block content

0 comments on commit c2e4a15

Please sign in to comment.