Skip to content

Commit d396c62

Browse files
authored
Merge pull request #68 from webpack/fix/get-options
Fix/get options
2 parents 8cda6ab + 2524200 commit d396c62

File tree

4 files changed

+63
-15
lines changed

4 files changed

+63
-15
lines changed

README.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,21 @@ Recommended way to retrieve the options of a loader invocation:
1111
const options = loaderUtils.getOptions(this);
1212
```
1313

14+
1. If `this.query` is a string:
15+
- Tries to parse the query string and returns a new object
16+
- Throws if it's not a valid query string
17+
2. If `this.query` is object-like, it just returns `this.query`
18+
3. In any other case, it just returns `null`
19+
1420
**Please note:** The returned `options` object is *read-only*. It may be re-used across multiple invocations.
1521
If you pass it on to another library, make sure to make a *deep copy* of it:
1622

1723
```javascript
18-
const options = Object.assign({}, loaderUtils.getOptions(this));
24+
const options = Object.assign(
25+
{},
26+
loaderUtils.getOptions(this), // it is safe to pass null to Object.assign()
27+
defaultOptions
28+
);
1929
// don't forget nested objects or arrays
2030
options.obj = Object.assign({}, options.obj);
2131
options.arr = options.arr.slice();
@@ -29,13 +39,13 @@ someLibrary(options);
2939
If the loader options have been passed as loader query string (`loader?some&params`), the string is parsed like this:
3040

3141
``` text
32-
null -> {}
42+
-> null
3343
? -> {}
3444
?flag -> { flag: true }
3545
?+flag -> { flag: true }
3646
?-flag -> { flag: false }
3747
?xyz=test -> { xyz: "test" }
38-
?xyz=1 -> { xyz: "1" }
48+
?xyz=1 -> { xyz: "1" } // numbers are NOT parsed
3949
?xyz[]=a -> { xyz: ["a"] }
4050
?flag1&flag2 -> { flag1: true, flag2: true }
4151
?+flag1,-flag2 -> { flag1: true, flag2: false }

lib/getOptions.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@ const parseQuery = require("./parseQuery");
44

55
function getOptions(loaderContext) {
66
const query = loaderContext.query;
7-
if(typeof query === "string") {
7+
if(typeof query === "string" && query !== "") {
88
return parseQuery(loaderContext.query);
99
}
10+
if(!query || typeof query !== "object") {
11+
// Not object-like queries are not supported.
12+
return null;
13+
}
1014
return query;
1115
}
1216

lib/parseQuery.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ function parseQuery(query) {
1313
throw new Error("A valid query string passed to parseQuery should begin with '?'");
1414
}
1515
query = query.substr(1);
16+
if(!query) {
17+
return {};
18+
}
1619
if(query.substr(0, 1) === "{" && query.substr(-1) === "}") {
1720
return JSON5.parse(query);
1821
}

test/getOptions.test.js

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,13 @@ const assert = require("assert");
44
const loaderUtils = require("../lib");
55

66
describe("getOptions()", () => {
7-
describe("when loaderContext.query is a string", () => {
7+
describe("when loaderContext.query is a query string starting with ?", () => {
88
[{
9+
it: "should return an empty object by default",
10+
query: "?",
11+
expected: {}
12+
},
13+
{
914
it: "should parse query params",
1015
query: "?name=cheesecake&slices=8&delicious&warm=false",
1116
expected: {
@@ -66,17 +71,27 @@ describe("getOptions()", () => {
6671
);
6772
});
6873
});
69-
describe("and the query string does not start with ?", () => {
70-
it("should throw an error", () => {
71-
assert.throws(
72-
() => loaderUtils.getOptions({ query: "a" }),
73-
"A valid query string passed to parseQuery should begin with '?'"
74-
);
75-
});
74+
});
75+
describe("when loaderContext.query is an empty string", () => {
76+
it("should return null", () => {
77+
assert.strictEqual(
78+
loaderUtils.getOptions({
79+
query: ""
80+
}),
81+
null
82+
);
83+
});
84+
});
85+
describe("when loaderContext.query is any other string not starting with ?", () => {
86+
it("should throw an error", () => {
87+
assert.throws(
88+
() => loaderUtils.getOptions({ query: "a" }),
89+
"A valid query string passed to parseQuery should begin with '?'"
90+
);
7691
});
7792
});
7893
describe("when loaderContext.query is an object", () => {
79-
it("should just return the object", () => {
94+
it("should just return it", () => {
8095
const query = {};
8196
assert.strictEqual(
8297
loaderUtils.getOptions({
@@ -86,7 +101,7 @@ describe("getOptions()", () => {
86101
);
87102
});
88103
});
89-
describe("when loaderContext.query is anything else", () => {
104+
describe("when loaderContext.query is an array", () => {
90105
it("should just return it", () => {
91106
const query = [];
92107
assert.strictEqual(
@@ -95,18 +110,34 @@ describe("getOptions()", () => {
95110
}),
96111
query
97112
);
113+
});
114+
});
115+
describe("when loaderContext.query is anything else", () => {
116+
it("should return null", () => {
98117
assert.strictEqual(
99118
loaderUtils.getOptions({
100119
query: undefined
101120
}),
102-
undefined
121+
null
103122
);
104123
assert.strictEqual(
105124
loaderUtils.getOptions({
106125
query: null
107126
}),
108127
null
109128
);
129+
assert.strictEqual(
130+
loaderUtils.getOptions({
131+
query: 1
132+
}),
133+
null
134+
);
135+
assert.strictEqual(
136+
loaderUtils.getOptions({
137+
query: 0
138+
}),
139+
null
140+
);
110141
});
111142
});
112143
});

0 commit comments

Comments
 (0)