Skip to content

Commit

Permalink
feat(replace): typeofReplacements option (#1084)
Browse files Browse the repository at this point in the history
  • Loading branch information
guybedford authored Feb 11, 2022
1 parent 9874740 commit 2d769ac
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 2 deletions.
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

### `objectGuards`

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

When replacing dot-separated object properties like `process.env.NODE_ENV`, will also replace `typeof process` object guard
checks against the objects with the string `"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 `objectGuards`
if (typeof process !== 'undefined' && 'production' === 'production') {
console.log('production');
}
// With `objectGuards`
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.objectGuards;
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, objectGuards } = options;
const replacements = getReplacements(options);
if (objectGuards) expandTypeofReplacements(replacements);
const functionValues = mapToFunctions(replacements);
const keys = Object.keys(functionValues).sort(longest).map(escape);
const lookahead = preventAssignment ? '(?!\\s*=[^=])' : '';
const pattern = delimiters
Expand Down
8 changes: 8 additions & 0 deletions packages/replace/test/fixtures/form/process-check/_config.js
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,
objectGuards: 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') {␊
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.

0 comments on commit 2d769ac

Please sign in to comment.