Skip to content

Commit

Permalink
fix: improve validation (#44)
Browse files Browse the repository at this point in the history
  • Loading branch information
evilebottnawi committed Jun 17, 2020
1 parent 141d59b commit 0397393
Show file tree
Hide file tree
Showing 4 changed files with 232 additions and 9 deletions.
59 changes: 54 additions & 5 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { interpolateName } from 'loader-utils';

function forError(item) {
return typeof item === 'string'
? item
: `\n${JSON.stringify(item, null, ' ')}\n`;
}

function resolveExports(type, item) {
let result;

Expand Down Expand Up @@ -38,7 +44,7 @@ function resolveExports(type, item) {

if (!['default', 'named', 'single', 'multiple'].includes(result.syntax)) {
throw new Error(
`Unknown "${result.syntax}" syntax export in "${item}" value`
`Unknown "${result.syntax}" syntax export in "${forError(item)}" value`
);
}

Expand All @@ -47,29 +53,49 @@ function resolveExports(type, item) {
typeof result.alias !== 'undefined'
) {
throw new Error(
`The "${result.syntax}" syntax can't have "${result.alias}" alias in "${item}" value`
`The "${result.syntax}" syntax can't have "${
result.alias
}" alias in "${forError(item)}" value`
);
}

if (type === 'commonjs') {
if (result.syntax === 'default' || result.syntax === 'named') {
throw new Error(
`The "${type}" format can't be used with the "${result.syntax}" syntax export in "${item}" value`
`The "${type}" format can't be used with the "${
result.syntax
}" syntax export in "${forError(item)}" value`
);
}
}

if (type === 'module') {
if (result.syntax === 'single' || result.syntax === 'multiple') {
throw new Error(
`The "${type}" format can't be used with the "${result.syntax}" syntax export in "${item}" value`
`The "${type}" format can't be used with the "${
result.syntax
}" syntax export in "${forError(item)}" value`
);
}
}

return result;
}

function getIdentifiers(array) {
return array.reduce((accumulator, item) => {
if (typeof item.alias !== 'undefined') {
accumulator.push({ type: 'alias', value: item.alias });

return accumulator;
}

accumulator.push({ type: 'name', value: item.name });

return accumulator;
}, []);
}

function getExports(type, exports) {
let result;

Expand All @@ -87,13 +113,36 @@ function getExports(type, exports) {
throw new Error(
`The "${type}" format can't have multiple "${
type === 'module' ? 'default' : 'single'
}" exports`
}" exports in "\n${JSON.stringify(exports, null, ' ')}\n" value`
);
}

const identifiers = getIdentifiers(result);
const duplicates = duplicateBy(identifiers, 'value');

if (duplicates.length > 0) {
throw new Error(
`Duplicate ${duplicates
.map((identifier) => `"${identifier.value}" (as "${identifier.type}")`)
.join(', ')} identifiers found in "\n${JSON.stringify(
exports,
null,
' '
)}\n" value`
);
}

return result;
}

function duplicateBy(array, key) {
return array.filter(
(a, aIndex) =>
array.filter((b, bIndex) => b[key] === a[key] && aIndex !== bIndex)
.length > 0
);
}

function renderExports(loaderContext, type, exports) {
let code = '';

Expand Down
148 changes: 146 additions & 2 deletions test/__snapshots__/loader.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1196,6 +1196,24 @@ Object {

exports[`loader should work with the "commonjs" module format for ["Foo","Bar"] export list: warnings 1`] = `Array []`;

exports[`loader should work with the "commonjs" module format for ["multiple Foo Bar","multiple Bar"] export list: errors 1`] = `
Array [
"ModuleBuildError: Module build failed (from \`replaced original path\`):
Error: Duplicate \\"Bar\\" (as \\"alias\\"), \\"Bar\\" (as \\"name\\") identifiers found in \\"",
]
`;

exports[`loader should work with the "commonjs" module format for ["multiple Foo Bar","multiple Bar"] export list: warnings 1`] = `Array []`;

exports[`loader should work with the "commonjs" module format for ["multiple Foo Baz","multiple Bar Baz"] export list: errors 1`] = `
Array [
"ModuleBuildError: Module build failed (from \`replaced original path\`):
Error: Duplicate \\"Baz\\" (as \\"alias\\"), \\"Baz\\" (as \\"alias\\") identifiers found in \\"",
]
`;

exports[`loader should work with the "commonjs" module format for ["multiple Foo Baz","multiple Bar Baz"] export list: warnings 1`] = `Array []`;

exports[`loader should work with the "commonjs" module format for ["multiple Foo FooA","multiple Bar BarA"] export list: errors 1`] = `Array []`;

exports[`loader should work with the "commonjs" module format for ["multiple Foo FooA","multiple Bar BarA"] export list: module 1`] = `
Expand Down Expand Up @@ -1252,6 +1270,15 @@ Object {

exports[`loader should work with the "commonjs" module format for ["multiple Foo FooA","multiple Bar BarA"] export list: warnings 1`] = `Array []`;

exports[`loader should work with the "commonjs" module format for ["multiple Foo","multiple Bar Foo"] export list: errors 1`] = `
Array [
"ModuleBuildError: Module build failed (from \`replaced original path\`):
Error: Duplicate \\"Foo\\" (as \\"name\\"), \\"Foo\\" (as \\"alias\\") identifiers found in \\"",
]
`;

exports[`loader should work with the "commonjs" module format for ["multiple Foo","multiple Bar Foo"] export list: warnings 1`] = `Array []`;

exports[`loader should work with the "commonjs" module format for ["multiple Foo","multiple Bar"] export list: errors 1`] = `Array []`;

exports[`loader should work with the "commonjs" module format for ["multiple Foo","multiple Bar"] export list: module 1`] = `
Expand Down Expand Up @@ -1308,6 +1335,24 @@ Object {

exports[`loader should work with the "commonjs" module format for ["multiple Foo","multiple Bar"] export list: warnings 1`] = `Array []`;

exports[`loader should work with the "commonjs" module format for ["multiple Foo","multiple Foo"] export list: errors 1`] = `
Array [
"ModuleBuildError: Module build failed (from \`replaced original path\`):
Error: Duplicate \\"Foo\\" (as \\"name\\"), \\"Foo\\" (as \\"name\\") identifiers found in \\"",
]
`;

exports[`loader should work with the "commonjs" module format for ["multiple Foo","multiple Foo"] export list: warnings 1`] = `Array []`;

exports[`loader should work with the "commonjs" module format for ["multiple myVariable.myFunction foo.bar","multiple Bar foo.bar"] export list: errors 1`] = `
Array [
"ModuleBuildError: Module build failed (from \`replaced original path\`):
Error: Duplicate \\"foo.bar\\" (as \\"alias\\"), \\"foo.bar\\" (as \\"alias\\") identifiers found in \\"",
]
`;

exports[`loader should work with the "commonjs" module format for ["multiple myVariable.myFunction foo.bar","multiple Bar foo.bar"] export list: warnings 1`] = `Array []`;

exports[`loader should work with the "commonjs" module format for ["multiple myVariable.myFunction myFunction","multiple Bar BarA"] export list: errors 1`] = `Array []`;

exports[`loader should work with the "commonjs" module format for ["multiple myVariable.myFunction myFunction","multiple Bar BarA"] export list: module 1`] = `
Expand Down Expand Up @@ -1362,15 +1407,51 @@ Object {

exports[`loader should work with the "commonjs" module format for ["multiple myVariable.myFunction myFunction","multiple Bar BarA"] export list: warnings 1`] = `Array []`;

exports[`loader should work with the "commonjs" module format for ["multiple myVariable.myFunction","multiple Bar myVariable.myFunction"] export list: errors 1`] = `
Array [
"ModuleBuildError: Module build failed (from \`replaced original path\`):
Error: Duplicate \\"myVariable.myFunction\\" (as \\"name\\"), \\"myVariable.myFunction\\" (as \\"alias\\") identifiers found in \\"",
]
`;

exports[`loader should work with the "commonjs" module format for ["multiple myVariable.myFunction","multiple Bar myVariable.myFunction"] export list: warnings 1`] = `Array []`;

exports[`loader should work with the "commonjs" module format for ["single Foo","single Bar"] export list: errors 1`] = `
Array [
"ModuleBuildError: Module build failed (from \`replaced original path\`):
Error: The \\"commonjs\\" format can't have multiple \\"single\\" exports",
Error: The \\"commonjs\\" format can't have multiple \\"single\\" exports in \\"",
]
`;

exports[`loader should work with the "commonjs" module format for ["single Foo","single Bar"] export list: warnings 1`] = `Array []`;

exports[`loader should work with the "commonjs" module format for {"syntax":"default","name":"Foo"} export list: errors 1`] = `
Array [
"ModuleBuildError: Module build failed (from \`replaced original path\`):
Error: The \\"commonjs\\" format can't be used with the \\"default\\" syntax export in \\"",
]
`;

exports[`loader should work with the "commonjs" module format for {"syntax":"default","name":"Foo"} export list: warnings 1`] = `Array []`;

exports[`loader should work with the "commonjs" module format for {"syntax":"single","name":"Foo","alias":"FooA"} export list: errors 1`] = `
Array [
"ModuleBuildError: Module build failed (from \`replaced original path\`):
Error: The \\"single\\" syntax can't have \\"FooA\\" alias in \\"",
]
`;

exports[`loader should work with the "commonjs" module format for {"syntax":"single","name":"Foo","alias":"FooA"} export list: warnings 1`] = `Array []`;

exports[`loader should work with the "commonjs" module format for {"syntax":"unknown","name":"Foo"} export list: errors 1`] = `
Array [
"ModuleBuildError: Module build failed (from \`replaced original path\`):
ValidationError: Invalid options object. Exports Loader has been initialized using an options object that does not match the API schema.",
]
`;

exports[`loader should work with the "commonjs" module format for {"syntax":"unknown","name":"Foo"} export list: warnings 1`] = `Array []`;

exports[`loader should work with the "module" module format for " " export list: errors 1`] = `
Array [
"ModuleBuildError: Module build failed (from \`replaced original path\`):
Expand Down Expand Up @@ -1994,7 +2075,7 @@ exports[`loader should work with the "module" module format for ["Foo","Bar"] ex
exports[`loader should work with the "module" module format for ["default Foo","default Bar"] export list: errors 1`] = `
Array [
"ModuleBuildError: Module build failed (from \`replaced original path\`):
Error: The \\"module\\" format can't have multiple \\"default\\" exports",
Error: The \\"module\\" format can't have multiple \\"default\\" exports in \\"",
]
`;

Expand Down Expand Up @@ -2173,6 +2254,24 @@ Object {

exports[`loader should work with the "module" module format for ["default Foo","named Bar"] export list: warnings 1`] = `Array []`;

exports[`loader should work with the "module" module format for ["named Foo Bar","named Bar"] export list: errors 1`] = `
Array [
"ModuleBuildError: Module build failed (from \`replaced original path\`):
Error: Duplicate \\"Bar\\" (as \\"alias\\"), \\"Bar\\" (as \\"name\\") identifiers found in \\"",
]
`;

exports[`loader should work with the "module" module format for ["named Foo Bar","named Bar"] export list: warnings 1`] = `Array []`;

exports[`loader should work with the "module" module format for ["named Foo Baz","named Bar Baz"] export list: errors 1`] = `
Array [
"ModuleBuildError: Module build failed (from \`replaced original path\`):
Error: Duplicate \\"Baz\\" (as \\"alias\\"), \\"Baz\\" (as \\"alias\\") identifiers found in \\"",
]
`;

exports[`loader should work with the "module" module format for ["named Foo Baz","named Bar Baz"] export list: warnings 1`] = `Array []`;

exports[`loader should work with the "module" module format for ["named Foo FooA","named Bar BarA"] export list: errors 1`] = `Array []`;

exports[`loader should work with the "module" module format for ["named Foo FooA","named Bar BarA"] export list: module 1`] = `
Expand Down Expand Up @@ -2285,6 +2384,15 @@ Object {

exports[`loader should work with the "module" module format for ["named Foo default","named Bar BarA"] export list: warnings 1`] = `Array []`;

exports[`loader should work with the "module" module format for ["named Foo","named Bar Foo"] export list: errors 1`] = `
Array [
"ModuleBuildError: Module build failed (from \`replaced original path\`):
Error: Duplicate \\"Foo\\" (as \\"name\\"), \\"Foo\\" (as \\"alias\\") identifiers found in \\"",
]
`;

exports[`loader should work with the "module" module format for ["named Foo","named Bar Foo"] export list: warnings 1`] = `Array []`;

exports[`loader should work with the "module" module format for ["named Foo","named Bar"] export list: errors 1`] = `Array []`;

exports[`loader should work with the "module" module format for ["named Foo","named Bar"] export list: module 1`] = `
Expand Down Expand Up @@ -2340,3 +2448,39 @@ Object {
`;

exports[`loader should work with the "module" module format for ["named Foo","named Bar"] export list: warnings 1`] = `Array []`;

exports[`loader should work with the "module" module format for ["named Foo","named Foo"] export list: errors 1`] = `
Array [
"ModuleBuildError: Module build failed (from \`replaced original path\`):
Error: Duplicate \\"Foo\\" (as \\"name\\"), \\"Foo\\" (as \\"name\\") identifiers found in \\"",
]
`;

exports[`loader should work with the "module" module format for ["named Foo","named Foo"] export list: warnings 1`] = `Array []`;

exports[`loader should work with the "module" module format for {"syntax":"single","name":"Foo","alias":"FooA"} export list: errors 1`] = `
Array [
"ModuleBuildError: Module build failed (from \`replaced original path\`):
Error: The \\"single\\" syntax can't have \\"FooA\\" alias in \\"",
]
`;

exports[`loader should work with the "module" module format for {"syntax":"single","name":"Foo","alias":"FooA"} export list: warnings 1`] = `Array []`;

exports[`loader should work with the "module" module format for {"syntax":"single","name":"Foo"} export list: errors 1`] = `
Array [
"ModuleBuildError: Module build failed (from \`replaced original path\`):
Error: The \\"module\\" format can't be used with the \\"single\\" syntax export in \\"",
]
`;

exports[`loader should work with the "module" module format for {"syntax":"single","name":"Foo"} export list: warnings 1`] = `Array []`;

exports[`loader should work with the "module" module format for {"syntax":"unknown","name":"Foo"} export list: errors 1`] = `
Array [
"ModuleBuildError: Module build failed (from \`replaced original path\`):
ValidationError: Invalid options object. Exports Loader has been initialized using an options object that does not match the API schema.",
]
`;

exports[`loader should work with the "module" module format for {"syntax":"unknown","name":"Foo"} export list: warnings 1`] = `Array []`;
32 changes: 31 additions & 1 deletion test/loader.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,17 +214,23 @@ describe('loader', () => {
expect(getWarnings(stats)).toMatchSnapshot('warnings');
});
}

//
createSuccessCase('commonjs', 'Foo');
createSuccessCase('commonjs', ' Foo ');
createSuccessCase('commonjs', '[name]');
createFailedCase('commonjs', 'default');
createFailedCase('commonjs', 'default Foo');
createFailedCase('commonjs', { syntax: 'default', name: 'Foo' });
createFailedCase('commonjs', 'named Foo');
createSuccessCase('commonjs', 'single Foo');
createSuccessCase('commonjs', 'single [name]');
createSuccessCase('commonjs', 'single single');
createFailedCase('commonjs', 'single Foo FooA');
createFailedCase('commonjs', {
syntax: 'single',
name: 'Foo',
alias: 'FooA',
});
createSuccessCase('commonjs', 'multiple Foo');
createSuccessCase('commonjs', 'multiple [name]');
createSuccessCase('commonjs', 'multiple Foo FooA');
Expand All @@ -240,7 +246,20 @@ describe('loader', () => {
]);
createFailedCase('commonjs', 'multiple Foo FooA FooB');
createFailedCase('commonjs', ['single Foo', 'single Bar']);
createFailedCase('commonjs', ['multiple Foo', 'multiple Foo']);
createFailedCase('commonjs', ['multiple Foo', 'multiple Bar Foo']);
createFailedCase('commonjs', ['multiple Foo Bar', 'multiple Bar']);
createFailedCase('commonjs', ['multiple Foo Baz', 'multiple Bar Baz']);
createFailedCase('commonjs', [
'multiple myVariable.myFunction',
'multiple Bar myVariable.myFunction',
]);
createFailedCase('commonjs', [
'multiple myVariable.myFunction foo.bar',
'multiple Bar foo.bar',
]);
createFailedCase('commonjs', 'unknown Foo');
createFailedCase('commonjs', { syntax: 'unknown', name: 'Foo' });
createFailedCase('commonjs', '`invalid`');
createFailedCase('commonjs', ' ');
createFailedCase('commonjs', ' ');
Expand All @@ -252,11 +271,17 @@ describe('loader', () => {
createSuccessCase('module', '[name]');
createFailedCase('module', 'default');
createFailedCase('module', 'single Foo');
createFailedCase('module', { syntax: 'single', name: 'Foo' });
createFailedCase('module', 'multiple Foo');
createSuccessCase('module', 'default Foo');
createSuccessCase('module', 'default [name]');
createFailedCase('module', 'default default');
createFailedCase('module', 'default Foo FooA');
createFailedCase('module', {
syntax: 'single',
name: 'Foo',
alias: 'FooA',
});
createSuccessCase('module', 'named Foo');
createSuccessCase('module', 'named [name]');
createSuccessCase('module', 'named Foo FooA');
Expand All @@ -271,7 +296,12 @@ describe('loader', () => {
createSuccessCase('module', ['default Foo', 'named Bar BarA', 'named Baz']);
createFailedCase('module', 'named Foo FooA FooB');
createFailedCase('module', ['default Foo', 'default Bar']);
createFailedCase('module', ['named Foo', 'named Foo']);
createFailedCase('module', ['named Foo', 'named Bar Foo']);
createFailedCase('module', ['named Foo Bar', 'named Bar']);
createFailedCase('module', ['named Foo Baz', 'named Bar Baz']);
createFailedCase('module', 'unknown Foo');
createFailedCase('module', { syntax: 'unknown', name: 'Foo' });
createFailedCase('module', '`invalid`');
createFailedCase('module', ' ');
createFailedCase('module', ' ');
Expand Down
Loading

0 comments on commit 0397393

Please sign in to comment.