Skip to content

Commit

Permalink
Merge pull request #14 from naecoo/feat/update
Browse files Browse the repository at this point in the history
Feat/update
  • Loading branch information
naecoo authored Nov 30, 2023
2 parents 0561c45 + 1b7e5ff commit 7878912
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 28 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "esbuild-plugin-replace",
"version": "1.4.0",
"version": "1.5.0",
"description": "Replace strings in files while bundling",
"main": "dist/index.js",
"module": "dist/index.mjs",
Expand Down
58 changes: 35 additions & 23 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@

const fs = require('fs');
const MagicString = require('magic-string');
import fs from "node:fs";
import MagicString from "magic-string";

const toFunction = (functionOrValue) => {
if (typeof functionOrValue === 'function') return functionOrValue;
if (typeof functionOrValue === "function") return functionOrValue;
return () => functionOrValue;
}
};

const escape = (str) => str.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&');
const escape = (str) => str.replace(/[-[\]/{}()*+?.\\^$|]/g, "\\$&");

const longest = (a, b) => b.length - a.length;

const mapToFunctions = (options) => {
const values = options.values ? Object.assign({}, options.values) : Object.assign({}, options);
const values = options.values
? Object.assign({}, options.values)
: Object.assign({}, options);
delete values.delimiters;
delete values.include;
delete values.exclude;
Expand All @@ -22,33 +23,37 @@ const mapToFunctions = (options) => {
functions[key] = toFunction(values[key]);
return functions;
}, {});
}
};

const generateFilter = (options) => {
let include = /.*/;
let exclude = null;
let hasValidInclude = false;

if (options.include) {
if (Object.prototype.toString.call(options.include) !== '[object RegExp]') {
console.warn(`Options.include must be a RegExp object, but gets an '${typeof options.include}' type.`);
if (Object.prototype.toString.call(options.include) !== "[object RegExp]") {
console.warn(
`Options.include must be a RegExp object, but gets an '${typeof options.include}' type.`
);
} else {
hasValidInclude = true;
include = options.include;
}
}

if (options.exclude) {
if (Object.prototype.toString.call(options.exclude) !== '[object RegExp]') {
console.warn(`Options.exclude must be a RegExp object, but gets an '${typeof options.exclude}' type.`);
if (Object.prototype.toString.call(options.exclude) !== "[object RegExp]") {
console.warn(
`Options.exclude must be a RegExp object, but gets an '${typeof options.exclude}' type.`
);
} else if (!hasValidInclude) {
// Only if `options.include` not set, take `options.exclude`
exclude = options.exclude;
}
}

return { include, exclude };
}
};

const replaceCode = (code, id, pattern, functionValues) => {
const magicString = new MagicString(code);
Expand All @@ -61,31 +66,38 @@ const replaceCode = (code, id, pattern, functionValues) => {
magicString.overwrite(start, end, replacement);
}
return magicString.toString();
}
};

// todo: add preventAssignment option & support sourceMap
exports.replace = (options = {}) => {
const replace = (options = {}) => {
const { include, exclude } = generateFilter(options);
const functionValues = mapToFunctions(options);
const empty = Object.keys(functionValues).length === 0;
const keys = Object.keys(functionValues).sort(longest).map(escape);
const { delimiters } = options;
const pattern = delimiters
? new RegExp(`${escape(delimiters[0])}(${keys.join('|')})${escape(delimiters[1])}`, 'g')
: new RegExp(`\\b(${keys.join('|')})\\b`, 'g');
? new RegExp(
`${escape(delimiters[0])}(${keys.join("|")})${escape(delimiters[1])}`,
"g"
)
: new RegExp(`\\b(${keys.join("|")})\\b`, "g");
return {
name: 'replace',
name: "replace",
setup(build) {
build.onLoad({ filter: include }, async (args) => {
// if match exclude, skip
if (exclude && args.path.match(exclude)) {
return;
}
const source = await fs.promises.readFile(args.path, "utf8");
const contents = empty ? source : replaceCode(source, args.path, pattern, functionValues)
return { contents, loader: 'default' };
const contents = empty
? source
: replaceCode(source, args.path, pattern, functionValues);
return { contents, loader: "default" };
});
}
},
};
}
module.exports = exports;
};

export { replace };
export default replace;
8 changes: 6 additions & 2 deletions test/example.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
export const target = {
version: __version__,
author: __author__
};
author: __author__,
};

export const anotherTarget = {
example: $example,
}
12 changes: 10 additions & 2 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,19 @@ test("options.exclude-2", async () => {

test("options.exclude-3", async () => {
const code = await buildExample({
__author__: JSON.stringify("naecoo"),
__author__: JSON.stringify("222"),
include: /\.js$/,
exclude: /\.js$/,
});
expect(code).toMatch(/naecoo/);
expect(code).toMatch(/222/);
expect(code).not.toMatch(/__author__/);
expect(code).toMatch(/__version__/);
});

test("use a key that starts with a $ ", async () => {
const code = await buildExample({
$example: JSON.stringify("Hello World!"),
delimiters: ['', ''],
});
expect(code).toMatch(/Hello World!/);
});

0 comments on commit 7878912

Please sign in to comment.