Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add/get options #65

Merged
merged 3 commits into from
Feb 20, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 26 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,57 +2,46 @@

## Methods

### `getLoaderConfig`
### getOptions

Recommended way to retrieve the loader config:
Recommended way to retrieve the options of a loader invocation:

```javascript
// inside your loader
config = loaderUtils.getLoaderConfig(this, "myLoader");
const options = loaderUtils.getOptions(this);
```

Tries to read the loader config from the `webpack.config.js` under the given property name (`"myLoader"` in this case) and merges the result with the loader query. For example, if your `webpack.config.js` had this property...
**Please note:** The returned `options` object is *read-only*. It may be re-used across multiple invocations.
If you pass it on to another library, make sure to make a *deep copy* of it:

```javascript
cheesecakeLoader: {
type: "delicious",
slices: 4
}
const options = Object.assign({}, loaderUtils.getOptions(this));
// don't forget nested objects or arrays
options.obj = Object.assign({}, options.obj);
options.arr = options.arr.slice();
someLibrary(options);
```

...and your loader was called with `?slices=8`, `getLoaderConfig(this, "cheesecakeLoader")` would return
[assign-deep](https://www.npmjs.com/package/assign-deep) is a good library to make a deep copy of the options.

```javascript
{
type: "delicious",
slices: 8
}
```

It is recommended that you use the camelCased loader name as your default config property name.
#### Options as query strings

### `parseQuery`

``` javascript
var query = loaderUtils.parseQuery(this.query);
assert(typeof query == "object");
if(query.flag)
// ...
```
If the loader options have been passed as loader query string (`loader?some&params`), the string is parsed like this:

``` text
null -> {}
? -> {}
?flag -> { flag: true }
?+flag -> { flag: true }
?-flag -> { flag: false }
?xyz=test -> { xyz: "test" }
?xyz[]=a -> { xyz: ["a"] }
?flag1&flag2 -> { flag1: true, flag2: true }
?+flag1,-flag2 -> { flag1: true, flag2: false }
?xyz[]=a,xyz[]=b -> { xyz: ["a", "b"] }
?a%2C%26b=c%2C%26d -> { "a,&b": "c,&d" }
?{json:5,data:{a:1}} -> { json: 5, data: { a: 1 } }
null -> {}
? -> {}
?flag -> { flag: true }
?+flag -> { flag: true }
?-flag -> { flag: false }
?xyz=test -> { xyz: "test" }
?xyz=1 -> { xyz: "1" }
?xyz[]=a -> { xyz: ["a"] }
?flag1&flag2 -> { flag1: true, flag2: true }
?+flag1,-flag2 -> { flag1: true, flag2: false }
?xyz[]=a,xyz[]=b -> { xyz: ["a", "b"] }
?a%2C%26b=c%2C%26d -> { "a,&b": "c,&d" }
?{data:{a:1},isJSON5:true} -> { data: { a: 1 }, isJSON5: true }
```

### `stringifyRequest`
Expand Down
17 changes: 0 additions & 17 deletions lib/getLoaderConfig.js

This file was deleted.

13 changes: 13 additions & 0 deletions lib/getOptions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"use strict";

const parseQuery = require("./parseQuery");

function getOptions(loaderContext) {
const query = loaderContext.query;
if(typeof query === "string") {
return parseQuery(loaderContext.query);
}
return query;
}

module.exports = getOptions;
6 changes: 2 additions & 4 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"use strict";

const parseQuery = require("./parseQuery");
const getLoaderConfig = require("./getLoaderConfig");
const getOptions = require("./getOptions");
const stringifyRequest = require("./stringifyRequest");
const getRemainingRequest = require("./getRemainingRequest");
const getCurrentRequest = require("./getCurrentRequest");
Expand All @@ -11,8 +10,7 @@ const parseString = require("./parseString");
const getHashDigest = require("./getHashDigest");
const interpolateName = require("./interpolateName");

exports.parseQuery = parseQuery;
exports.getLoaderConfig = getLoaderConfig;
exports.getOptions = getOptions;
exports.stringifyRequest = stringifyRequest;
exports.getRemainingRequest = getRemainingRequest;
exports.getCurrentRequest = getCurrentRequest;
Expand Down
17 changes: 3 additions & 14 deletions lib/parseQuery.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,22 @@
"use strict";

const JSON5 = require("json5");
const util = require("util");
const os = require("os");

const parseQueryDeprecationWarning = util.deprecate(() => {},
"loaderUtils.parseQuery() received a non-string value which can be problematic, " +
"see https://github.com/webpack/loader-utils/issues/56" + os.EOL +
"parseQuery() will be replaced with getOptions() in the next major version of loader-utils."
);
const specialValues = {
"null": null,
"true": true,
"false": false
};

function parseQuery(query) {
if(!query) return {};
if(typeof query !== "string") {
parseQueryDeprecationWarning();
return query;
if(query.substr(0, 1) !== "?") {
throw new Error("A valid query string passed to parseQuery should begin with '?'");
}
if(query.substr(0, 1) !== "?")
throw new Error("a valid query string passed to parseQuery should begin with '?'");
query = query.substr(1);
if(query.substr(0, 1) === "{" && query.substr(-1) === "}") {
return JSON5.parse(query);
}
const queryArgs = query.split(/[,\&]/g);
const queryArgs = query.split(/[,&]/g);
const result = {};
queryArgs.forEach(arg => {
const idx = arg.indexOf("=");
Expand Down
23 changes: 0 additions & 23 deletions test/getLoaderConfig.test.js

This file was deleted.

112 changes: 112 additions & 0 deletions test/getOptions.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
"use strict";

const assert = require("assert");
const loaderUtils = require("../lib");

describe("getOptions()", () => {
describe("when loaderContext.query is a string", () => {
[{
it: "should parse query params",
query: "?name=cheesecake&slices=8&delicious&warm=false",
expected: {
delicious: true,
name: "cheesecake",
slices: "8", // numbers are still strings with query params
warm: false
}
},
{
it: "should parse query params with arrays",
query: "?ingredients[]=flour&ingredients[]=sugar",
expected: {
ingredients: ["flour", "sugar"]
}
},
{
it: "should parse query params in JSON format",
query: "?" + JSON.stringify({
delicious: true,
name: "cheesecake",
slices: 8,
warm: false
}),
expected: {
delicious: true,
name: "cheesecake",
slices: 8,
warm: false
}
},
{
it: "should use decodeURIComponent",
query: "?%3d",
expected: { "=": true }
},
{
it: "should recognize params starting with + as boolean params with the value true",
query: "?+%3d",
expected: { "=": true }
},
{
it: "should recognize params starting with - as boolean params with the value false",
query: "?-%3d",
expected: { "=": false }
},
{
it: "should not confuse regular equal signs and encoded equal signs",
query: "?%3d=%3D",
expected: { "=": "=" }
}].forEach(test => {
it(test.it, () => {
assert.deepEqual(
loaderUtils.getOptions({
query: test.query
}),
test.expected
);
});
});
describe("and the query string does not start with ?", () => {
it("should throw an error", () => {
assert.throws(
() => loaderUtils.getOptions({ query: "a" }),
"A valid query string passed to parseQuery should begin with '?'"
);
});
});
});
describe("when loaderContext.query is an object", () => {
it("should just return the object", () => {
const query = {};
assert.strictEqual(
loaderUtils.getOptions({
query
}),
query
);
});
});
describe("when loaderContext.query is anything else", () => {
it("should just return it", () => {
const query = [];
assert.strictEqual(
loaderUtils.getOptions({
query
}),
query
);
assert.strictEqual(
loaderUtils.getOptions({
query: undefined
}),
undefined
);
assert.strictEqual(
loaderUtils.getOptions({
query: null
}),
null
);
});
});
});
38 changes: 0 additions & 38 deletions test/parseQuery.test.js

This file was deleted.