Skip to content
Merged
33 changes: 33 additions & 0 deletions packages/replace/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,39 @@ For example, if you pass `typeof window` in `values` to-be-replaced, then you co
- `typeof window.document` **will not** be replaced due to `(?!\.)` boundary
- `typeof windowSmth` **will not** be replaced due to a `\b` boundary

### `typeofReplacements`

Type: `Boolean`<br>
Default: `false`

When replacing dot-separated object properties like `process.env.NODE_ENV`, will also replace typeof checks against the objects
with `"object"`.

For example:

```js
replace({
values: {
'process.env.NODE_ENV': '"production"'
}
});
```

```js
// Input
if (typeof process !== 'undefined' && process.env.NODE_ENV === 'production') {
console.log('production');
}
// Without `typeofReplacements`
if (typeof process !== 'undefined' && 'production' === 'production') {
console.log('production');
}
// With `typeofReplacements`
if ('object' !== 'undefined' && 'production' === 'production') {
console.log('production');
}
```

### `preventAssignment`

Type: `Boolean`<br>
Expand Down
37 changes: 35 additions & 2 deletions packages/replace/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ function getReplacements(options) {
delete values.exclude;
delete values.sourcemap;
delete values.sourceMap;
delete values.typeofReplacements;
return values;
}

Expand All @@ -35,10 +36,42 @@ function mapToFunctions(object) {
}, {});
}

const objKeyRegEx = /^([_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*)(\.([_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*))+$/;
function expandTypeofReplacements(replacements) {
Object.keys(replacements).forEach((key) => {
const objMatch = key.match(objKeyRegEx);
if (!objMatch) return;
let dotIndex = objMatch[1].length;
let lastIndex = 0;
do {
// eslint-disable-next-line no-param-reassign
replacements[`typeof ${key.slice(lastIndex, dotIndex)} ===`] = '"object" ===';
// eslint-disable-next-line no-param-reassign
replacements[`typeof ${key.slice(lastIndex, dotIndex)} !==`] = '"object" !==';
// eslint-disable-next-line no-param-reassign
replacements[`typeof ${key.slice(lastIndex, dotIndex)}===`] = '"object"===';
// eslint-disable-next-line no-param-reassign
replacements[`typeof ${key.slice(lastIndex, dotIndex)}!==`] = '"object"!==';
// eslint-disable-next-line no-param-reassign
replacements[`typeof ${key.slice(lastIndex, dotIndex)} ==`] = '"object" ===';
// eslint-disable-next-line no-param-reassign
replacements[`typeof ${key.slice(lastIndex, dotIndex)} !=`] = '"object" !==';
// eslint-disable-next-line no-param-reassign
replacements[`typeof ${key.slice(lastIndex, dotIndex)}==`] = '"object"===';
// eslint-disable-next-line no-param-reassign
replacements[`typeof ${key.slice(lastIndex, dotIndex)}!=`] = '"object"!==';
lastIndex = dotIndex + 1;
dotIndex = key.indexOf('.', lastIndex);
} while (dotIndex !== -1);
});
}

export default function replace(options = {}) {
const filter = createFilter(options.include, options.exclude);
const { delimiters, preventAssignment } = options;
const functionValues = mapToFunctions(getReplacements(options));
const { delimiters, preventAssignment, typeofReplacements } = options;
const replacements = getReplacements(options);
if (typeofReplacements) expandTypeofReplacements(replacements);
const functionValues = mapToFunctions(replacements);
const keys = Object.keys(functionValues).sort(longest).map(escape);
const lookahead = preventAssignment ? '(?!\\s*=[^=])' : '';
const pattern = delimiters
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
description: 'Handles process type guards in replacements',
options: {
'process.env.NODE_ENV': '"production"',
preventAssignment: true,
typeofReplacements: true
}
};
3 changes: 3 additions & 0 deletions packages/replace/test/fixtures/form/process-check/input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
if (typeof process !== 'undefined' && process.env.NODE_ENV === 'production') {
console.log('production');
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
process.env.DEBUG = 'test';
8 changes: 8 additions & 0 deletions packages/replace/test/snapshots/form.js.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ Generated by [AVA](https://avajs.dev).
exclude␊
`);`

## process-check: Handles process type guards in replacements

> Snapshot 1

`if (typeof process !== 'undefined' && "production" === 'production') {␊
Copy link

@privatenumber privatenumber Apr 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@guybedford

Shouldn't typeof process be transformed to 'object'? :

if ('object' !== 'undefined' && "production" === 'production') {

console.log('production');␊
}`

## replace-nothing: replaces nothing

> Snapshot 1
Expand Down
Binary file modified packages/replace/test/snapshots/form.js.snap
Binary file not shown.