Skip to content

Commit

Permalink
refactor: move to ESM and require Node 18
Browse files Browse the repository at this point in the history
BREAKING CHANGE: The plugin is now pure ESM
BREAKING CHANGE: Requires Node 18
  • Loading branch information
thomasvantuycom committed Sep 28, 2023
1 parent 3cc22fc commit ce3b418
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 62 deletions.
20 changes: 9 additions & 11 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
'use strict';

const path = require('path');
const PluginError = require('plugin-error');
const {Transform} = require('stream');

const replace = require('./lib/replace.js');
import path from 'node:path';
import {Buffer} from 'node:buffer';
import {Transform} from 'node:stream';
import PluginError from 'plugin-error';
import replace from './lib/replace.js';

function relativePath(from, to) {
return path.relative(from, to).replace(/\\/g, '/');
return path.relative(from, to).replaceAll('\\', '/');
}

module.exports = function (options = {}) {
export default function plugin(options = {}) {
const renames = [];
const cache = [];

Expand All @@ -29,7 +27,7 @@ module.exports = function (options = {}) {
if (file.revOrigPath) {
renames.push({
unreved: relativePath(file.revOrigBase, file.revOrigPath),
reved: relativePath(file.base, file.path)
reved: relativePath(file.base, file.path),
});
}

Expand Down Expand Up @@ -60,4 +58,4 @@ module.exports = function (options = {}) {

callback();
}});
};
}
14 changes: 6 additions & 8 deletions lib/replace.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
'use strict';
import escapeStringRegexp from 'escape-string-regexp';

const escapeRegExp = require('lodash.escaperegexp');

module.exports = function (string, manifest) {
export default function replace(string, manifest) {
let newString = string;
for (const entry of manifest) {
const {unreved, reved} = entry;
Expand All @@ -11,14 +9,14 @@ module.exports = function (string, manifest) {
const BACK_DELIMITERS = ['"', '\'', '\\s', ',', '\\)', '\\\\', '\\?', '#', '$', '&', '>'];

const regexp = new RegExp(
`(?<=${FRONT_DELIMITERS.join('|')})${escapeRegExp(
unreved
`(?<=${FRONT_DELIMITERS.join('|')})${escapeStringRegexp(
unreved,
)}(?=${BACK_DELIMITERS.join('|')})`,
'g'
'g',
);

newString = newString.replace(regexp, reved);
}

return newString;
};
}
25 changes: 9 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,34 +22,27 @@
"index.js",
"lib"
],
"type": "module",
"exports": "./index.js",
"author": {
"name": "Thomas Vantuycom",
"email": "thomasvantuycom@protonmail.com",
"url": "https://github.com/TheDancingCode"
},
"engines": {
"node": ">=12"
"node": ">=18"
},
"license": "MIT",
"dependencies": {
"lodash.escaperegexp": "^4.1.2",
"escape-string-regexp": "^5.0.0",
"plugin-error": "^2.0.0"
},
"devDependencies": {
"@ava/babel": "^2.0.0",
"ava": "^3.0.0",
"gulp-rev": "^9.0.0",
"p-event": "^4.1.0",
"semantic-release": "^21.0.0",
"ava": "^5.0.0",
"gulp-rev": "^10.0.0",
"p-event": "^6.0.0",
"semantic-release": "^22.0.0",
"vinyl": "^3.0.0",
"xo": "0.39.1"
},
"ava": {
"babel": true
},
"xo": {
"rules": {
"unicorn/string-content": "off"
}
"xo": "^0.56.0"
}
}
31 changes: 17 additions & 14 deletions test/index.spec.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import {Buffer} from 'node:buffer';
import test from 'ava';
import Vinyl from 'vinyl';
import pEvent from 'p-event';
import {pEvent, pEventIterator} from 'p-event';
import rev from 'gulp-rev';
import revRewrite from '..';
import revRewrite from '../index.js';

const htmlFileBody =
'<link rel="stylesheet" href="/css/style.css"><img src="image.png">';
const htmlFileBody
= '<link rel="stylesheet" href="/css/style.css"><img src="image.png">';
const cssFileBody = 'body { background: url("image.png"); }';
const pngFileBody = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=';

const createFile = (path, contents, encoding = 'utf8') =>
new Vinyl({
path,
contents: Buffer.from(contents, encoding)
contents: Buffer.from(contents, encoding),
});

const createManifest = () => {
const manifest = {
'image.png': 'image-d41d8cd98f.png',
'css/style.css': 'css/style-81a53f7d04.css'
'css/style.css': 'css/style-81a53f7d04.css',
};
return Buffer.from(JSON.stringify(manifest, null, 4));
};
Expand All @@ -28,15 +29,16 @@ test('identifies and replaces reved filenames in the stream', async t => {

const revStream = rev();
const revRewriteStream = revRewrite();
const data = pEvent.multiple(revRewriteStream, 'data', {count: 2});
const data = pEventIterator(revRewriteStream, 'data', {
resolutionEvents: ['finish']
});

revStream.pipe(revRewriteStream);

revStream.write(createFile('index.html', htmlFileBody));
revStream.end(createFile('style.css', cssFileBody));

const files = await data;
for (const file of files) {
for await (const file of data) {
const contents = file.contents.toString();
if (file.extname === '.html') {
t.regex(contents, /css\/style-[a-z\d]{10}\.css/);
Expand All @@ -49,15 +51,16 @@ test('works with Windows-style paths', async t => {

const revStream = rev();
const revRewriteStream = revRewrite();
const data = pEvent.multiple(revRewriteStream, 'data', {count: 2});
const data = pEventIterator(revRewriteStream, 'data', {
resolutionEvents: ['finish']
});

revStream.pipe(revRewriteStream);

revStream.write(createFile('css\\style.css', cssFileBody));
revStream.end(createFile('index.html', htmlFileBody));

const files = await data;
for (const file of files) {
for await (const file of data) {
const contents = file.contents.toString();
if (file.extname === '.html') {
t.true(contents.includes('css/style-81a53f7d04.css'));
Expand All @@ -82,7 +85,7 @@ test('does not replace false positives', async t => {
t.plan(1);

const stream = revRewrite({
manifest: createManifest()
manifest: createManifest(),
});
const data = pEvent(stream, 'data');

Expand All @@ -91,7 +94,7 @@ test('does not replace false positives', async t => {
'<img src="not_image.png">',
'<img src="notimage.png">',
'<img src="image.png.not">',
'<img src="image.pngnot">'
'<img src="image.pngnot">',
];
stream.end(createFile('index.html', falsePositives.join('')));

Expand Down
26 changes: 13 additions & 13 deletions test/replace.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import replace from '../lib/replace.js';
const renames = [
{
unreved: 'images/icon.svg',
reved: 'images/icon-d41d8cd98f.svg'
reved: 'images/icon-d41d8cd98f.svg',
},
{
unreved: 'style.css.map',
reved: 'style-98adc164tm.css.map'
}
reved: 'style-98adc164tm.css.map',
},
];

test('single quotes', t => {
Expand Down Expand Up @@ -46,27 +46,27 @@ test('spaces', t => {

test('slashes', t => {
const input = 'body { background: url("path/images/icon.svg"); }';
const expected =
'body { background: url("path/images/icon-d41d8cd98f.svg"); }';
const expected
= 'body { background: url("path/images/icon-d41d8cd98f.svg"); }';
const output = replace(input, renames);

t.is(output, expected);
});

test('backslashes', t => {
const input =
'document.querySelector("*[style*=\'background-image: url(\\"images/icon.svg\\")\']");';
const expected =
'document.querySelector("*[style*=\'background-image: url(\\"images/icon-d41d8cd98f.svg\\")\']");';
const input
= 'document.querySelector("*[style*=\'background-image: url(\\"images/icon.svg\\")\']");';
const expected
= 'document.querySelector("*[style*=\'background-image: url(\\"images/icon-d41d8cd98f.svg\\")\']");';
const output = replace(input, renames);

t.is(output, expected);
});

test('query strings', t => {
const input = 'body { background: url("images/icon.svg?query=string"); }';
const expected =
'body { background: url("images/icon-d41d8cd98f.svg?query=string"); }';
const expected
= 'body { background: url("images/icon-d41d8cd98f.svg?query=string"); }';
const output = replace(input, renames);

t.is(output, expected);
Expand All @@ -83,8 +83,8 @@ test('query parameters', t => {

test('fragment identifiers', t => {
const input = 'body { background: url("images/icon.svg#fragment"); }';
const expected =
'body { background: url("images/icon-d41d8cd98f.svg#fragment"); }';
const expected
= 'body { background: url("images/icon-d41d8cd98f.svg#fragment"); }';
const output = replace(input, renames);

t.is(output, expected);
Expand Down

0 comments on commit ce3b418

Please sign in to comment.