Skip to content
Closed
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
4 changes: 4 additions & 0 deletions declarations/getLoaderOptions.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export function getLoaderOptions(
options: string | object | null | undefined,
schema: import('./validate').Schema | null | undefined
): object;
3 changes: 2 additions & 1 deletion declarations/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { getLoaderOptions } from './getLoaderOptions';
import { validate } from './validate';
import { ValidationError } from './validate';
export { validate, ValidationError };
export { getLoaderOptions, validate, ValidationError };
8 changes: 6 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,11 @@
"declarations"
],
"dependencies": {
"@types/json-parse-better-errors": "^1.0.0",
"@types/json-schema": "^7.0.7",
"ajv": "^6.12.5",
"ajv-keywords": "^3.5.2",
"@types/json-schema": "^7.0.7"
"json-parse-better-errors": "^1.0.2"
},
"devDependencies": {
"@babel/cli": "^7.12.13",
Expand Down
53 changes: 53 additions & 0 deletions src/getLoaderOptions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/* eslint-disable no-param-reassign */

const querystring = require('querystring');

const parseJson = require('json-parse-better-errors');

const { validate } = require('./validate');

/**
* Parses the loader option if necessary, and validates it.
*
* @param {string | object | null | undefined} options a raw object, a JSON string, or a query string representing a loader option
* @param {import("./validate").Schema | null | undefined} schema a schema to validate the option against
* @return {object} the parsed loader option
*/
module.exports.getLoaderOptions = function getLoaderOptions(options, schema) {
if (typeof options === 'string') {
if (options.substr(0, 1) === '{' && options.substr(-1) === '}') {
try {
options = parseJson(options);
} catch (e) {
throw new Error(`Cannot parse string options: ${e.message}`);
}
} else {
options = querystring.parse(options, '&', '=', {
maxKeys: 0,
});
}
}

// eslint-disable-next-line no-undefined
if (options === null || options === undefined) {
options = {};
}

if (schema) {
let name = 'Loader';
let baseDataPath = 'options';
let match;
// eslint-disable-next-line no-cond-assign
if (schema.title && (match = /^(.+) (.+)$/.exec(schema.title))) {
[, name, baseDataPath] = match;
}
// @ts-expect-error
validate(schema, options, {
name,
baseDataPath,
});
}

// @ts-expect-error
return options;
};
3 changes: 2 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const { validate, ValidationError } = require('./validate');
const { getLoaderOptions } = require('./getLoaderOptions');

module.exports = { validate, ValidationError };
module.exports = { getLoaderOptions, validate, ValidationError };
21 changes: 21 additions & 0 deletions test/__snapshots__/getLoaderOptions.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`getLoaderOptions parses and validates given JSON string 1`] = `
"Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema.
- options has an unknown property 'namee'. These properties are valid:
object { name? }"
`;

exports[`getLoaderOptions parses and validates given query string 1`] = `
"Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema.
- options has an unknown property 'namee'. These properties are valid:
object { name? }"
`;

exports[`getLoaderOptions returns and validates given object as-is 1`] = `
"Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema.
- options has an unknown property 'namee'. These properties are valid:
object { name? }"
`;

exports[`getLoaderOptions throws an error for invalid JSON 1`] = `"Cannot parse string options: Unexpected token u in JSON at position 10 while parsing near '{\\"name\\":faulse}'"`;
59 changes: 59 additions & 0 deletions test/getLoaderOptions.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { getLoaderOptions } from '../src';

import schemaTitle from './fixtures/schema-title.json';

describe('getLoaderOptions', () => {
it('returns given object as-is', () => {
const options = getLoaderOptions({ name: false });
expect(options).toEqual({ name: false });
});

it('returns and validates given object as-is', () => {
const options = getLoaderOptions({ name: false }, schemaTitle);
expect(options).toEqual({ name: false }, schemaTitle);
expect(() =>
getLoaderOptions({ namee: false }, schemaTitle)
).toThrowErrorMatchingSnapshot();
});

it('parses given JSON string', () => {
const options = getLoaderOptions('{"name":false}');
expect(options).toEqual({ name: false });
});

it('parses and validates given JSON string', () => {
const options = getLoaderOptions('{"name":false}', schemaTitle);
expect(options).toEqual({ name: false }, schemaTitle);
expect(() =>
getLoaderOptions('{"namee":false}', schemaTitle)
).toThrowErrorMatchingSnapshot();
});

it('throws an error for invalid JSON', () => {
expect(() =>
getLoaderOptions('{"name":faulse}')
).toThrowErrorMatchingSnapshot();
});

it('parses given query string', () => {
const options = getLoaderOptions('name=false');
expect(options).toEqual({ name: 'false' });
});

it('parses and validates given query string', () => {
expect(() =>
getLoaderOptions('namee=false', schemaTitle)
).toThrowErrorMatchingSnapshot();
});

it('returns an empty object for null', () => {
const options = getLoaderOptions(null);
expect(options).toEqual({});
});

it('returns an empty object for undefined', () => {
// eslint-disable-next-line no-undefined
const options = getLoaderOptions(undefined);
expect(options).toEqual({});
});
});