Skip to content

Commit 914c9fd

Browse files
authored
Merge pull request #32 from runreflect/4x-file-inclusion
4x file inclusion
2 parents b21fab8 + 841de65 commit 914c9fd

File tree

8 files changed

+89
-8
lines changed

8 files changed

+89
-8
lines changed

README.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ npm install webpack-react-component-name -save-dev
4040

4141
```json
4242
{
43-
"parseDependencies": false
43+
"parseDependencies": false,
44+
"include": [],
45+
"exclude": []
4446
}
4547
```
4648

@@ -51,6 +53,22 @@ Default: `false`
5153

5254
If set true, the plugin will name the components exported from node_modules.
5355

56+
57+
### include
58+
Type: `(string | RegExp | (path: string) => boolean)[]` Default: `[]`
59+
60+
If the path matches any of the elements in this array, it will be included if it isn't explicitly excluded.
61+
62+
If the item is a `string`, it will use standard glob syntax. If the item is a Regular Expression, the path will be tested against it. If the item is a function, the path will be passed into it for testing.
63+
64+
### exclude
65+
Type: `(string | RegExp | (path: string) => boolean)[]` Default: `[]`
66+
67+
If the path matches any of the elements in this array, it will be excluded.
68+
69+
If the item is a `string`, it will use standard glob syntax. If the item is a Regular Expression, the path will be tested against it. If the item is a function, the path will be passed into it for testing.
70+
71+
A truthy result will be excluded.
5472
## Troubleshooting
5573

5674
As you probably know, there is more than one way to define a React component. This

examples/todomvc/src/reducers/useTodos.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { globalReducer } from "react-hook-utils";
2-
31
import { guid } from "../utils";
42

53
export const newTodo = label => ({

index.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@ class WebpackReactComponentNamePlugin {
3737
parser.hooks.program.tap("WebpackReactComponentNamePlugin", ast => {
3838
// Ignore dependency files
3939
if (parser.state.current.resource == null
40-
|| (!this.options.parseDependencies && parser.state.current.resource.indexOf("node_modules") !== -1)
41-
|| !VALID_FILE_SUFFIXES_REGEX.test(parser.state.current.resource.toLowerCase())) {
40+
|| !VALID_FILE_SUFFIXES_REGEX.test(parser.state.current.resource)
41+
|| (this.options.include.length && this.options.include.every(match => !match(parser.state.current.resource)))
42+
|| (this.options.exclude.length && this.options.exclude.some(match => match(parser.state.current.resource)))) {
4243
return
4344
}
4445

lib/options-parser.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,27 @@
1+
const { Minimatch } = require("minimatch")
2+
3+
/**
4+
* Resolves the matchers in an array.
5+
*/
6+
function resolveMatchers(match) {
7+
if (typeof match === 'string') {
8+
const minimatch = new Minimatch(match)
9+
return (path) => minimatch.match(path)
10+
}
11+
if (match instanceof RegExp) return (path) => match.test(path)
12+
if (typeof match === 'function') return match
13+
throw new Error(`Unrecognized parameter: ${match}; expected string, RegExp, or function.`)
14+
}
15+
116
/**
217
* Reads and validates the options passed to the Webpack plugin.
318
*/
419
class OptionsParser {
520
parse(options) {
621
const optionsWithDefaults = {
722
parseDependencies: options?.parseDependencies ?? false,
23+
exclude: options?.exclude ?? [],
24+
include: options?.include ?? []
825
}
926

1027
// Check if caller set any invalid options
@@ -14,8 +31,16 @@ class OptionsParser {
1431
}
1532
}
1633

34+
if (!optionsWithDefaults.parseDependencies) optionsWithDefaults.exclude.push(this.ignoreNodeModules)
35+
optionsWithDefaults.include = optionsWithDefaults.include.map(resolveMatchers)
36+
optionsWithDefaults.exclude = optionsWithDefaults.exclude.map(resolveMatchers)
37+
1738
return optionsWithDefaults
1839
}
40+
41+
ignoreNodeModules(path) {
42+
return path.indexOf("node_modules") !== -1
43+
}
1944
}
2045

2146
module.exports = OptionsParser

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"webpack": "4.x"
6161
},
6262
"dependencies": {
63-
"acorn-walk": "7.2.0"
63+
"acorn-walk": "7.2.0",
64+
"minimatch": "5.1.0"
6465
}
6566
}

test/constants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const path = require('path')
22

33
const OUTPUT_DIR = path.resolve(__dirname, '../dist/examples')
4+
exports.OUTPUT_DIR = OUTPUT_DIR
45

56
const PRODUCTION_MODE = 'production'
67
const BABEL_CONFIG_WITH_PRESENT_ENV = {

test/options-parser.spec.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,19 @@ const optionsParser = new OptionsParser()
44

55
describe('OptionsParser', () => {
66
it('sets default options if undefined', () => {
7-
expect(optionsParser.parse(undefined)).toEqual({ parseDependencies: false })
7+
expect(optionsParser.parse(undefined)).toEqual({
8+
parseDependencies: false,
9+
include: [],
10+
exclude: [optionsParser.ignoreNodeModules]
11+
})
812
})
913

1014
it('sets options passed to parser', () => {
11-
expect(optionsParser.parse({ parseDependencies: true })).toEqual({ parseDependencies: true })
15+
expect(optionsParser.parse({ parseDependencies: true })).toEqual({
16+
parseDependencies: true,
17+
include: [],
18+
exclude: []
19+
})
1220
})
1321

1422
it('throws error if unsupported option is passed', () => {

test/plugin.spec.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const utils = require('./utils')
22
const constants = require('./constants')
33
const _ = require('lodash')
4+
const fs = require('fs')
45

56
const WebpackReactComponentNamePlugin = require('../index.js')
67
const ModuleAppenderDependency = require('../lib/module-appender')
@@ -206,6 +207,30 @@ describe('WebpackReactComponentNamePlugin', () => {
206207
expect(minifiedSource).toContain('.displayName="TodoItem"')
207208
expect(numDisplayNameProperties).toEqual(3)
208209
})
210+
211+
it('handles include / exclude options', async () => {
212+
// Note that this test only works with one flavor of Babel loader, so we're only testing one here
213+
await utils.testWebpackPlugin(_.merge(_.cloneDeep(constants.TODOMVC_WEBPACK_CONFIG), {
214+
plugins: [new WebpackReactComponentNamePlugin({
215+
// Regex expressions work, also strings use minimatch to support glob patterns,
216+
// and functions.
217+
include: ['**/containers/*.js', /App\.js/], // If any of these pass, it will be included if it isn't excluded.
218+
exclude: [i => i.includes('Item')]
219+
})],
220+
output: {
221+
path: constants.OUTPUT_DIR,
222+
filename: 'limitedtodomvc.js'
223+
},
224+
module: constants.DEFAULT_BABEL_CONFIG,
225+
}))
226+
227+
const minifiedSource = readSourceFile('limitedtodomvc.js')
228+
const numDisplayNameProperties = (minifiedSource.match(DISPLAY_NAME_REGEX) || []).length
229+
230+
expect(minifiedSource).toContain('.displayName="App"')
231+
expect(minifiedSource).toContain('.displayName="TodoList"')
232+
expect(numDisplayNameProperties).toEqual(6) // Components plus Provider, Consumer, and Router
233+
})
209234
})
210235

211236
/**
@@ -219,3 +244,7 @@ function generateWebpackConfigs(baseWebpackConfig) {
219244
})
220245
})
221246
}
247+
248+
function readSourceFile(filename) {
249+
return fs.readFileSync(constants.OUTPUT_DIR + '/' + filename).toString()
250+
}

0 commit comments

Comments
 (0)