From bb97b2794f8e5b6dfae411c6ca1d66f2c1c840c0 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sat, 9 Jun 2018 08:00:46 +0200 Subject: [PATCH] Require Node.js 18 and move to ESM --- .gitattributes | 3 +- .github/workflows/main.yml | 21 +++ .travis.yml | 5 - index.js | 43 ++---- license | 2 +- package.json | 31 +++-- readme.md | 66 +++++---- test.js | 266 +++++++++++-------------------------- 8 files changed, 176 insertions(+), 261 deletions(-) create mode 100644 .github/workflows/main.yml delete mode 100644 .travis.yml diff --git a/.gitattributes b/.gitattributes index 391f0a4..6313b56 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1 @@ -* text=auto -*.js text eol=lf +* text=auto eol=lf diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..346585c --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,21 @@ +name: CI +on: + - push + - pull_request +jobs: + test: + name: Node.js ${{ matrix.node-version }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node-version: + - 20 + - 18 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + - run: npm install + - run: npm test diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 7d69d74..0000000 --- a/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -language: node_js -node_js: - - '8' - - '6' - - '4' diff --git a/index.js b/index.js index 8513359..e193195 100644 --- a/index.js +++ b/index.js @@ -1,34 +1,19 @@ -'use strict'; -const PluginError = require('plugin-error'); -const through = require('through2'); -const _ = require('lodash'); -const Buffer = require('safe-buffer').Buffer; - -const template = _.template; +import {Buffer} from 'node:buffer'; +import _ from 'lodash'; +import {gulpPlugin} from 'gulp-plugin-extras'; function compile(options, data, render) { - return through.obj(function (file, enc, cb) { - if (file.isNull()) { - cb(null, file); - return; - } - - if (file.isStream()) { - cb(new PluginError('gulp-template', 'Streaming not supported')); - return; - } - - try { - const tpl = template(file.contents.toString(), options); - file.contents = Buffer.from(render ? tpl(_.merge({}, file.data, data)) : tpl.toString()); - this.push(file); - } catch (err) { - this.emit('error', new PluginError('gulp-template', err, {fileName: file.path})); - } - - cb(); + return gulpPlugin('gulp-template', file => { + const template = _.template(file.contents.toString(), options); + file.contents = Buffer.from(render ? template(_.merge({}, file.data, data)) : template.toString()); + return file; }); } -module.exports = (data, options) => compile(options, data, true); -module.exports.precompile = options => compile(options); +export default function gulpTemplate(data, options) { + return compile(options, data, true); +} + +export function precompile(options) { + return compile(options); +} diff --git a/license b/license index e7af2f7..fa7ceba 100644 --- a/license +++ b/license @@ -1,6 +1,6 @@ MIT License -Copyright (c) Sindre Sorhus (sindresorhus.com) +Copyright (c) Sindre Sorhus (https://sindresorhus.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/package.json b/package.json index 320a24f..6fe9790 100644 --- a/package.json +++ b/package.json @@ -4,16 +4,19 @@ "description": "Render/precompile Lodash/Underscore templates", "license": "MIT", "repository": "sindresorhus/gulp-template", + "funding": "https://github.com/sponsors/sindresorhus", "author": { "name": "Sindre Sorhus", "email": "sindresorhus@gmail.com", - "url": "sindresorhus.com" + "url": "https://sindresorhus.com" }, + "type": "module", + "exports": "./index.js", "engines": { - "node": ">=4" + "node": ">=18" }, "scripts": { - "test": "xo && mocha" + "test": "xo && ava" }, "files": [ "index.js" @@ -30,15 +33,21 @@ "precompile" ], "dependencies": { - "lodash": "^4.8.2", - "plugin-error": "^0.1.2", - "safe-buffer": "^5.1.1", - "through2": "^2.0.0" + "gulp-plugin-extras": "^0.2.2", + "lodash": "^4.17.21" }, "devDependencies": { - "gulp-data": "^1.0.2", - "mocha": "*", - "vinyl": "^2.1.0", - "xo": "*" + "ava": "^5.3.1", + "gulp-data": "^1.3.1", + "vinyl": "^3.0.0", + "xo": "^0.56.0" + }, + "peerDependencies": { + "gulp": ">=4" + }, + "peerDependenciesMeta": { + "gulp": { + "optional": true + } } } diff --git a/readme.md b/readme.md index 2024253..6d328e0 100644 --- a/readme.md +++ b/readme.md @@ -1,16 +1,14 @@ -# gulp-template [![Build Status](https://travis-ci.org/sindresorhus/gulp-template.svg?branch=master)](https://travis-ci.org/sindresorhus/gulp-template) +# gulp-template -> Render/precompile [Lodash/Underscore templates](http://lodash.com/docs#template) +> Render/precompile [Lodash/Underscore templates](https://lodash.com/docs#template) *Issues with the output should be reported on the Lodash [issue tracker](https://github.com/lodash/lodash/issues).* - ## Install +```sh +npm install --save-dev gulp-template ``` -$ npm install --save-dev gulp-template -``` - ## Usage @@ -23,10 +21,10 @@ $ npm install --save-dev gulp-template ### `gulpfile.js` ```js -const gulp = require('gulp'); -const template = require('gulp-template'); +import gulp from 'gulp'; +import template from 'gulp-template'; -gulp.task('default', () => +export default () => ( gulp.src('src/greeting.html') .pipe(template({name: 'Sindre'})) .pipe(gulp.dest('dist')) @@ -36,11 +34,11 @@ gulp.task('default', () => You can alternatively use [gulp-data](https://github.com/colynb/gulp-data) to inject the data: ```js -const gulp = require('gulp'); -const template = require('gulp-template'); -const data = require('gulp-data'); +import gulp from 'gulp'; +import template from 'gulp-template'; +import data from 'gulp-data'; -gulp.task('default', () => +export default () => ( gulp.src('src/greeting.html') .pipe(data(() => ({name: 'Sindre'}))) .pipe(template()) @@ -54,35 +52,57 @@ gulp.task('default', () =>

Hello Sindre

``` - ## API -### template(data, [options]) +### template(data, options?) Render a template using the provided `data`. -### template.precompile([options]) +### template.precompile(options?) Precompile a template for rendering dynamically at a later time. #### data -Type: `Object` +Type: `object` Data object used to populate the text. #### options -Type: `Object` +Type: `object` -[Lodash `_.template` options](http://lodash.com/docs#template). +[Lodash `_.template` options](https://lodash.com/docs#template). +## Tip -## Related +You can also provide your own [interpolation string](https://lodash.com/docs#template) for custom templates. -- [grunt-template](https://github.com/mathiasbynens/grunt-template) - Grunt version +### `src/greeting.html` +```html +

Hello {{ name }}

+``` -## License +### `gulpfile.js` -MIT © [Sindre Sorhus](https://sindresorhus.com) +```js +import gulp from 'gulp'; +import template from 'gulp-template'; +import data from 'gulp-data'; + +export default () => ( + gulp.src('src/greeting.html') + .pipe(data(() => ({name: 'Sindre'}))) + .pipe(template(null, { + interpolate: /{{(.+?)}}/gs + })) + .pipe(gulp.dest('dist')) +); +``` + +### `dist/greeting.html` + +```html +

Hello Sindre

+``` diff --git a/test.js b/test.js index 7def4b1..c70a8c1 100644 --- a/test.js +++ b/test.js @@ -1,219 +1,105 @@ -'use strict'; -/* eslint-env mocha */ -const assert = require('assert'); -const Vinyl = require('vinyl'); -const data = require('gulp-data'); -const template = require('.'); - -it('should compile Lodash templates', cb => { - const stream = template({people: ['foo', 'bar']}); - - stream.on('data', data => { - assert.equal(data.contents.toString(), '
  • foo
  • bar
  • '); - }); - - stream.on('end', cb); - - stream.write(new Vinyl({ - contents: Buffer.from('<% _.forEach(people, function (name) { %>
  • <%- name %>
  • <% }); %>') - })); - +import {Buffer} from 'node:buffer'; +import test from 'ava'; +import {pEvent} from 'p-event'; +import Vinyl from 'vinyl'; +import gulpData from 'gulp-data'; +import gulpTemplate, {precompile} from './index.js'; + +test('should compile Lodash templates', async t => { + const stream = gulpTemplate({people: ['foo', 'bar']}); + const promise = pEvent(stream, 'data'); + stream.write(new Vinyl({contents: Buffer.from('<% _.forEach(people, function (name) { %>
  • <%- name %>
  • <% }); %>')})); stream.end(); -}); - -it('should support data via gulp-data', cb => { - const dl = []; - - const stream = data(file => { - return { - dd: file.path - }; - }); - - stream.pipe(template({dt: 'path'})); - - stream.on('data', chunk => { - dl.push(chunk.contents.toString()); - }); - stream.on('end', () => { - const expected = '
    path
    bar.txt
    path
    foo.txt
    '; - assert.equal(dl.sort().join(''), expected); - cb(); - }); - - stream.write(new Vinyl({ - path: 'foo.txt', - contents: Buffer.from('
    <%- dt %>
    <%- dd %>
    ') - })); - - stream.write(new Vinyl({ - path: 'bar.txt', - contents: Buffer.from('
    <%- dt %>
    <%- dd %>
    ') - })); - - stream.end(); + const data = await promise; + t.is(data.contents.toString(), '
  • foo
  • bar
  • '); }); -it('should support Lo-Dash options with gulp-data', cb => { - const options = { - variable: 'data', - imports: { - dt: 'path' - } - }; - - const dl = []; - - const stream = data(file => { - return { - dd: file.path - }; - }); - - stream.pipe(template(null, options)); - - stream.on('data', chunk => { - dl.push(chunk.contents.toString()); - }); - - stream.on('end', () => { - const expected = '
    path
    bar.txt
    path
    foo.txt
    '; - assert.equal(dl.sort().join(''), expected); - cb(); - }); - - stream.write(new Vinyl({ - path: 'foo.txt', - contents: Buffer.from('
    <%- dt %>
    <%- data.dd %>
    ') - })); - - stream.write(new Vinyl({ - path: 'bar.txt', - contents: Buffer.from('
    <%- dt %>
    <%- data.dd %>
    ') - })); +test('should support data via gulp-data', async t => { + const stream = gulpData(file => ({dd: file.path})); + const finalStream = stream.pipe(gulpTemplate({dt: 'path'})); + stream.write(new Vinyl({path: 'foo.txt', contents: Buffer.from('
    <%- dt %>
    <%- dd %>
    ')})); + stream.write(new Vinyl({path: 'bar.txt', contents: Buffer.from('
    <%- dt %>
    <%- dd %>
    ')})); stream.end(); -}); -it('should merge gulp-data and data parameter', cb => { - const stream = data(() => { - return { - people: ['foo', 'bar'], - nested: { - a: 'one', - b: 'two' - } - }; - }); - - stream.pipe(template({ - heading: 'people', - nested: { - a: 'three', - c: 'four' - } - })); - - stream.on('data', data => { - assert.equal(data.contents.toString(), '

    people

  • foo
  • bar
  • three,two,four'); - }); - - stream.on('end', cb); - - stream.write(new Vinyl({ - contents: Buffer.from('

    <%= heading %>

    <% _.forEach(people, function (name) { %>
  • <%- name %>
  • <% }); %><%= nested.a %>,<%= nested.b %>,<%= nested.c %>') - })); + const result = await finalStream.toArray(); - stream.end(); + t.deepEqual( + result.map(file => file.contents.toString()).sort(), + ['
    path
    bar.txt
    ', '
    path
    foo.txt
    '].sort(), + ); }); -it('should not alter gulp-data or data parameter', cb => { - const chunks = []; - - const stream = data(file => { - return { - contents: file.contents.toString() - }; - }); - - const parameter = { - foo: 'foo', - bar: 'bar', - foobar: ['foo', 'bar'] - }; - - stream.pipe(template(parameter)); - - stream.on('data', chunk => { - chunks.push(chunk); - }); - - stream.on('end', () => { - assert.deepEqual(chunks[0].data, {contents: 'foo'}); - assert.deepEqual(parameter, { - foo: 'foo', - bar: 'bar', - foobar: ['foo', 'bar'] - }); - cb(); - }); - - stream.write(new Vinyl({ - contents: Buffer.from('foo') - })); +test('should support Lo-Dash options with gulp-data', async t => { + const options = {variable: 'data', imports: {dt: 'path'}}; + const stream = gulpData(file => ({dd: file.path})); + const finalStream = stream.pipe(gulpTemplate(null, options)); + stream.write(new Vinyl({path: 'foo.txt', contents: Buffer.from('
    <%- dt %>
    <%- data.dd %>
    ')})); + stream.write(new Vinyl({path: 'bar.txt', contents: Buffer.from('
    <%- dt %>
    <%- data.dd %>
    ')})); stream.end(); -}); -it('should work with no data supplied', cb => { - const stream = template(); + const result = await finalStream.toArray(); - stream.on('data', data => { - assert.equal(data.contents.toString(), ''); - }); - - stream.on('end', cb); - - stream.write(new Vinyl({ - contents: Buffer.from('') - })); + t.deepEqual( + result.map(file => file.contents.toString()).sort(), + ['
    path
    bar.txt
    ', '
    path
    foo.txt
    '].sort(), + ); +}); +test('should merge gulp-data and data parameter', async t => { + const stream = gulpData(() => ({people: ['foo', 'bar'], nested: {a: 'one', b: 'two'}})); + const promise = pEvent(stream, 'data'); + stream.pipe(gulpTemplate({heading: 'people', nested: {a: 'three', c: 'four'}})); + stream.write(new Vinyl({contents: Buffer.from('

    <%= heading %>

    <% _.forEach(people, function (name) { %>
  • <%- name %>
  • <% }); %><%= nested.a %>,<%= nested.b %>,<%= nested.c %>')})); stream.end(); -}); -it('should precompile Lodash templates', cb => { - const stream = template.precompile(); + const data = await promise; + t.is(data.contents.toString(), '

    people

  • foo
  • bar
  • three,two,four'); +}); - stream.on('data', data => { - assert.ok(data.contents.toString().indexOf('function (obj)') === 0); - }); +test('should not alter gulp-data or data parameter', async t => { + const stream = gulpData(file => ({contents: file.contents.toString()})); + const parameter = {foo: 'foo', bar: 'bar', foobar: ['foo', 'bar']}; + const finalStream = stream.pipe(gulpTemplate(parameter)); - stream.on('end', cb); + stream.write(new Vinyl({contents: Buffer.from('foo')})); + stream.end(); - stream.write(new Vinyl({ - contents: Buffer.from('

    <%= heading %>

    ') - })); + const result = await finalStream.toArray(); - stream.end(); + t.deepEqual(result.map(x => x.data), [{contents: 'foo'}]); + t.deepEqual(parameter, {foo: 'foo', bar: 'bar', foobar: ['foo', 'bar']}); }); -it('should support Lo-Dash options when precompiling', cb => { - const options = { - variable: 'data' - }; - - const stream = template.precompile(options); +test('should work with no data supplied', async t => { + const stream = gulpTemplate(); + const promise = pEvent(stream, 'data'); + stream.write(new Vinyl({contents: Buffer.from('')})); + stream.end(); - stream.on('data', data => { - assert.ok(data.contents.toString().indexOf('function (data)') === 0); - }); + const data = await promise; + t.is(data.contents.toString(), ''); +}); - stream.on('end', cb); +test('should precompile Lodash templates', async t => { + const stream = precompile(); + const promise = pEvent(stream, 'data'); + stream.write(new Vinyl({contents: Buffer.from('

    <%= heading %>

    ')})); + stream.end(); - stream.write(new Vinyl({ - contents: Buffer.from('

    <%= heading %>

    ') - })); + const data = await promise; + t.true(data.contents.toString().includes('function')); +}); +test('should support Lo-Dash options when precompiling', async t => { + const options = {variable: 'data'}; + const stream = precompile(options); + const promise = pEvent(stream, 'data'); + stream.write(new Vinyl({contents: Buffer.from('

    <%= heading %>

    ')})); stream.end(); + + const data = await promise; + t.true(data.contents.toString().includes('function')); });