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

Add set filename option #169

Merged
merged 2 commits into from
Apr 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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