diff --git a/README.md b/README.md
index 07e4d0f..97d41c6 100644
--- a/README.md
+++ b/README.md
@@ -1,98 +1,444 @@
-[![npm][npm]][npm-url]
-[![deps][deps]][deps-url]
-[![test][test]][test-url]
-[![chat][chat]][chat-url]
-
-
-
+
-
Imports Loader
-
The imports loader allows you to use modules that depend on specific global variables.
+[![npm][npm]][npm-url]
+[![node][node]][node-url]
+[![deps][deps]][deps-url]
+[![tests][tests]][tests-url]
+[![cover][cover]][cover-url]
+[![chat][chat]][chat-url]
+[![size][size]][size-url]
+
+# Imports Loader
+
+The imports loader allows you to use modules that depend on specific global variables.
+
This is useful for third-party modules that rely on global variables like `$` or `this` being the `window` object. The imports loader can add the necessary `require('whatever')` calls, so those modules work with webpack.
-Install
+## Getting Started
-```bash
-npm install imports-loader
-```
+To begin, you'll need to install `imports-loader`:
-
+```console
+$ npm install imports-loader --save-dev
+```
Given you have this file `example.js`
-```javascript
+```js
$('img').doSomeAwesomeJqueryPluginStuff();
```
-then you can inject the `$` variable into the module by configuring the imports-loader like this:
+then you can inject the `jquery` variable into the module by configuring the imports-loader like this:
+
+**index.js**
+
+```js
+require('imports-loader?imports=default%20jquery%20$!./example.js');
+// Adds the following code to the beginning of example.js:
+//
+// `import $ from "jquery";` to `example.js`
+```
+
+> ⚠ By default loader generate ES module named syntax.
+
+### Inline
+
+The `imports` have follow syntax:
+
+```
+?imports=syntax%20moduleName%20name%20alias
+```
+
+The space (`%20`) is the separator between import segments.
-```javascript
-require('imports-loader?$=jquery!./example.js');
+> `syntax` is required.
+
+A `syntax` can be omitted only if one segment is used. In this case, the `moduleName` and `name` will be equal to it.
+
+Description of string values can be found in the documentation below.
+
+#### Examples
+
+**index.js**
+
+```js
+require(`imports-loader?imports[]=default%20jquery%20$&imports[]=angular!./example.js`);
+// Adds the following code to the beginning of example.js:
+//
+// import $ from "jquery";
+// import angular from "angular";
```
-This simply prepends `var $ = require("jquery");` to `example.js`.
+```js
+require(`imports-loader?type=commonjsimports[]=default%20jquery%20$&imports[]=angular!./example.js`);
+// Adds the following code to the beginning of example.js:
+//
+// var $ = require("jquery");
+// var angular = require("angular");
+```
-### Syntax
+```js
+require(`imports-loader?wrapper=window&imports[]=default%20jquery%20$&imports[]=angular!./example.js`);
+// Adds the following code to the example.js:
+//
+// import $ from "jquery";
+// import angular from "angular";
+//
+// (function () {
+// code from example.js
+// }.call(window));
+```
+
+Description of string values can be found in the documentation below.
-| Query value | Equals |
-| ------------------- | ------------------------------------- |
-| `angular` | `var angular = require("angular");` |
-| `$=jquery` | `var $ = require("jquery");` |
-| `define=>false` | `var define = false;` |
-| `config=>{size:50}` | `var config = {size:50};` |
-| `this=>window` | `(function () { ... }).call(window);` |
+### Using Configuration
-### Multiple values
+The loader's signature:
-Multiple values are separated by comma `,`:
+**webpack.config.js**
-```javascript
-require('imports-loader?$=jquery,angular,config=>{size:50}!./file.js');
+```js
+module.exports = {
+ module: {
+ rules: [
+ {
+ test: require.resolve('example.js'),
+ use: [
+ {
+ loader: 'imports-loader',
+ options: {
+ type: 'commonjs',
+ imports: [
+ 'default ./lib_1 $',
+ 'default ./lib_2 lib_2_default',
+ 'named ./lib_2 lib2_method_1',
+ 'named ./lib_2 lib2_method_2 lib_2_method_2_short',
+ 'default ./lib_3 lib_3_defaul',
+ 'namespace ./lib_3 lib_3_all',
+ 'side-effect ./lib_4',
+ 'default jquery $',
+ {
+ moduleName: 'angular',
+ name: 'angular',
+ },
+ ],
+ wrapper: {
+ call: 'window',
+ },
+ additionalCode: 'var someVariable = 1;',
+ },
+ },
+ ],
+ },
+ ],
+ },
+};
```
-### webpack.config.js
+And run `webpack` via your preferred method.
+
+## Options
+
+| Name | Type | Default | Description |
+| :-----------------------: | :---------------------------------------: | :---------: | :-------------------------- |
+| **[`type`](#type)** | `{String}` | `module` | Format of generated exports |
+| **[`imports`](#imports)** | `{String\|Object\|Array}` | `undefined` | List of imports |
+
+### Type
+
+Type: `String`
+Default: `module`
+
+Format of generated exports.
+
+Possible values - `commonjs` (CommonJS module syntax) and `module` (ES module syntax).
+
+#### `commonjs`
+
+**webpack.config.js**
+
+```js
+module.exports = {
+ module: {
+ rules: [
+ {
+ test: require.resolve('example.js'),
+ loader: 'imports-loader',
+ options: {
+ type: 'commonjs',
+ imports: 'Foo',
+ },
+ },
+ ],
+ },
+};
+// Adds the following code to the beginning of example.js:
+//
+// var Foo = require("Foo");
+```
-As always, you should rather configure this in your `webpack.config.js`:
+#### `module`
-```javascript
-// ./webpack.config.js
+**webpack.config.js**
+```js
module.exports = {
- ...
- module: {
- rules: [
- {
- test: require.resolve("some-module"),
- use: "imports-loader?this=>window"
- }
- ]
- }
+ module: {
+ rules: [
+ {
+ test: require.resolve('example.js'),
+ loader: 'imports-loader',
+ options: {
+ type: 'module',
+ imports: 'Foo',
+ },
+ },
+ ],
+ },
};
+// Adds the following code to the beginning of example.js:
+//
+// import Foo from "Foo";
```
-Typical Use Cases
+### Imports
-### jQuery plugins
+Type: `String|Object|Array`
+Default: `undefined`
-`imports-loader?$=jquery`
+List of imports.
-### Custom Angular modules
+#### `String`
-`imports-loader?angular`
+Allows to use a string to describe an export.
-### Disable AMD
+##### `Syntax`
-There are many modules that check for a `define` function before using CommonJS. Since webpack is capable of both, they default to AMD in this case, which can be a problem if the implementation is quirky.
+String values let you specify import syntax, moduleName, name, and alias.
-Then you can easily disable the AMD path by writing
+String syntax - `[[syntax] [moduleName] [name] [alias]]`, where:
-```javascript
-imports-loader?define=>false
+- `[syntax]` - can be `default`, `named`, `namespace` or `side-effect`
+- `[moduleName]` - name of an imported module (**required**)
+- `[name]` - name of an imported value (**required**)
+- `[alias]` - alias of an imported value (**may be omitted**)
+
+Examples:
+
+- `[Foo]` - generates `import Foo from "Foo";`.
+- `[default Foo]` - generates `import Foo from "Foo";`.
+- `[default ./my-lib Foo]` - generates `import Foo from "./my-lib";`.
+- `[named Foo FooA]` - generates `import { FooA } from "Foo";`.
+- `[named Foo FooA Bar]` - generates `import { FooA as Bar } from "Foo";`.
+- `[[default Foo] [named Foo Bar BarA]]` - generates `import Foo, { Bar as BarA } from "Foo";`.
+- `[namespace Foo FooA]` - generates `import * as FooA from "Foo";`.
+- `[[default Foo] [namespace Foo FooA]]` - generates `import Foo, * as FooA from "Foo";`.
+- `[side-effect Foo]` - generates `import "Foo";`.
+
+> ⚠ Aliases can't be used together with `default` or `side-effect` syntax.
+
+###### Examples
+
+**webpack.config.js**
+
+```js
+module.exports = {
+ module: {
+ rules: [
+ {
+ test: require.resolve('example.js'),
+ use: [
+ {
+ loader: 'imports-loader',
+ options: {
+ type: 'commonjs',
+ imports: 'default jquery $',
+ },
+ },
+ ],
+ },
+ ],
+ },
+};
+
+// Adds the following code to the beginning of example.js:
+//
+// import $ from "jquery";
+```
+
+#### `Object`
+
+Allows to use an object to describe an import.
+
+Properties:
+
+- `[syntax]` - can be `default`, `named`, `namespace` or `side-effect`
+- `moduleName` - name of an imported module (**required**)
+- `name` - name of an exported value (**required**)
+- `alias` - alias of an exported value (**may be omitted**)
+
+##### Examples
+
+**webpack.config.js**
+
+```js
+module.exports = {
+ module: {
+ rules: [
+ {
+ test: require.resolve('example.js'),
+ use: [
+ {
+ loader: 'imports-loader',
+ options: {
+ type: 'commonjs',
+ imports: {
+ syntax: 'named',
+ moduleName: './lib_2',
+ name: 'lib2_method_2',
+ alias: 'lib_2_method_2_alias',
+ },
+ },
+ },
+ ],
+ },
+ ],
+ },
+};
+
+// Adds the following code to the beginning of example.js:
+//
+// import { lib2_method_2 as lib_2_method_2_alias } from "./lib_2";
+```
+
+#### `Array`
+
+Allow to specify multiple imports. Each item can be a [`string`](https://github.com/webpack-contrib/imports-loader#string) or an [`object`](https://github.com/webpack-contrib/imports-loader#object).
+
+##### Examples
+
+**webpack.config.js**
+
+```js
+module.exports = {
+ module: {
+ rules: [
+ {
+ test: require.resolve('example.js'),
+ use: [
+ {
+ loader: 'imports-loader',
+ options: {
+ type: 'commonjs',
+ imports: [
+ {
+ moduleName: 'angular',
+ },
+ {
+ syntax: 'default',
+ moduleName: 'jquery',
+ name: '$',
+ },
+ 'default ./lib_2 lib_2_default',
+ 'named ./lib_2 lib2_method_1',
+ 'named ./lib_2 lib2_method_2 lib_2_method_2_alias',
+ 'default ./lib_3 lib_3_default',
+ 'namespace ./lib_3 lib_3_all',
+ 'side-effect ./lib_4',
+ ],
+ },
+ },
+ ],
+ },
+ ],
+ },
+};
+
+// Adds the following code to the beginning of example.js:
+//
+// import angular from "angular";
+// import $ from "jquery";
+// import lib_2_default, { lib2_method_1, lib2_method_2 as lib_2_method_2_alias } from "./lib_2";
+// import lib_3_default, * as lib_3_all from "./lib_3";
+// import "./lib_4";
+```
+
+### wrapper
+
+Type: `String|Array`
+Default: `undefined`
+
+Closes the module code in a function with a given `this` (`(function () { ... }).call(window);`).
+
+```js
+module.exports = {
+ module: {
+ rules: [
+ {
+ test: require.resolve('example.js'),
+ use: [
+ {
+ loader: 'imports-loader',
+ options: {
+ imports: {
+ moduleName: 'jquery',
+ name: '$',
+ },
+ wrapper: ['window', 'document'],
+ },
+ },
+ ],
+ },
+ ],
+ },
+};
+// Adds the following code to the example.js:
+//
+// import $ from "jquery";
+//
+// (function () {
+// code from example.js
+// }.call(window, document));
+```
+
+### additionalCode
+
+Type: `String`
+Default: `undefined`
+
+Adds custom code.
+
+```js
+module.exports = {
+ module: {
+ rules: [
+ {
+ test: require.resolve('example.js'),
+ use: [
+ {
+ loader: 'imports-loader',
+ options: {
+ imports: {
+ moduleName: 'jquery',
+ name: '$',
+ },
+ additionalCode: 'var someVariable = 1;',
+ },
+ },
+ ],
+ },
+ ],
+ },
+};
+// Adds the following code to the beginning of example.js:
+//
+// import $ from 'jquery';
+// var someVariable = 1;
```
For further hints on compatibility issues, check out [Shimming Modules](https://webpack.js.org/guides/shimming/) of the official docs.
@@ -132,9 +478,15 @@ For further hints on compatibility issues, check out [Shimming Modules](https://
[npm]: https://img.shields.io/npm/v/imports-loader.svg
[npm-url]: https://www.npmjs.com/package/imports-loader
+[node]: https://img.shields.io/node/v/imports-loader.svg
+[node-url]: https://nodejs.org
[deps]: https://david-dm.org/webpack-contrib/imports-loader.svg
[deps-url]: https://david-dm.org/webpack-contrib/imports-loader
+[tests]: https://github.com/webpack-contrib/imports-loader/workflows/imports-loader/badge.svg
+[tests-url]: https://github.com/webpack-contrib/imports-loader/actions
+[cover]: https://codecov.io/gh/webpack-contrib/imports-loader/branch/master/graph/badge.svg
+[cover-url]: https://codecov.io/gh/webpack-contrib/imports-loader
[chat]: https://img.shields.io/badge/gitter-webpack%2Fwebpack-brightgreen.svg
[chat-url]: https://gitter.im/webpack/webpack
-[test]: http://img.shields.io/travis/webpack-contrib/imports-loader.svg
-[test-url]: https://travis-ci.org/webpack-contrib/imports-loader
+[size]: https://packagephobia.now.sh/badge?p=imports-loader
+[size-url]: https://packagephobia.now.sh/result?p=imports-loader
diff --git a/src/index.js b/src/index.js
index cb51833..f2048a3 100644
--- a/src/index.js
+++ b/src/index.js
@@ -3,74 +3,71 @@
Author Tobias Koppers @sokra
*/
+import { SourceNode, SourceMapConsumer } from 'source-map';
import { getOptions, getCurrentRequest } from 'loader-utils';
-// import validateOptions from 'schema-utils';
-//
-// import schema from './options.json';
+import validateOptions from 'schema-utils';
-const { SourceNode } = require('source-map');
-const { SourceMapConsumer } = require('source-map');
+import schema from './options.json';
-const HEADER = '/*** IMPORTS FROM imports-loader ***/\n';
+import { getImports, renderImports } from './utils';
export default function loader(content, sourceMap) {
const options = getOptions(this) || {};
- // validateOptions(schema, options, 'Loader');
+ validateOptions(schema, options, {
+ name: 'Imports loader',
+ baseDataPath: 'options',
+ });
+ const type = options.type || 'module';
const callback = this.async();
- if (this.cacheable) this.cacheable();
- const query = options;
- const imports = [];
- const postfixes = [];
- Object.keys(query).forEach((name) => {
- let value;
- if (typeof query[name] === 'string' && query[name].substr(0, 1) === '>') {
- value = query[name].substr(1);
- } else {
- let mod = name;
- if (typeof query[name] === 'string') {
- mod = query[name];
- }
- value = `require(${JSON.stringify(mod)})`;
- }
- if (name === 'this') {
- imports.push('(function() {');
- postfixes.unshift(`}.call(${value}));`);
- } else if (name.indexOf('.') !== -1) {
- name.split('.').reduce((previous, current, index, names) => {
- const expr = previous + current;
-
- if (previous.length === 0) {
- imports.push(`var ${expr} = (${current} || {});`);
- } else if (index < names.length - 1) {
- imports.push(`${expr} = ${expr} || {};`);
- } else {
- imports.push(`${expr} = ${value};`);
- }
-
- return `${previous}${current}.`;
- }, '');
- } else {
- imports.push(`var ${name} = ${value};`);
+ let importsCode = `/*** IMPORTS FROM imports-loader ***/\n`;
+
+ let imports;
+
+ if (options.imports) {
+ try {
+ imports = getImports(type, options.imports);
+ } catch (error) {
+ callback(error);
+
+ return;
}
- });
- const prefix = `${HEADER}${imports.join('\n')}\n\n`;
- const postfix = `\n${postfixes.join('\n')}`;
- if (sourceMap) {
+
+ importsCode += Object.entries(imports).reduce((acc, item) => {
+ return `${acc}${renderImports(this, type, item[1])}\n`;
+ }, '');
+ }
+
+ if (options.additionalCode) {
+ importsCode += `\n${options.additionalCode}`;
+ }
+
+ let codeAfterModule = '';
+
+ if (options.wrapper) {
+ importsCode += '\n(function() {';
+ codeAfterModule += `\n}.call(${options.wrapper.toString()}));`;
+ }
+
+ if (this.sourceMap && sourceMap) {
const node = SourceNode.fromStringWithSourceMap(
content,
new SourceMapConsumer(sourceMap)
);
- node.prepend(prefix);
- node.add(postfix);
+
+ node.prepend(`${importsCode}\n`);
+ node.add(codeAfterModule);
+
const result = node.toStringWithSourceMap({
file: getCurrentRequest(this),
});
+
callback(null, result.code, result.map.toJSON());
+
return;
}
- callback(null, `${prefix}${content}${postfix}`, sourceMap);
+ callback(null, `${importsCode}\n${content}${codeAfterModule}`, sourceMap);
}
diff --git a/src/options.json b/src/options.json
index 4a7c07d..501ab28 100644
--- a/src/options.json
+++ b/src/options.json
@@ -1,5 +1,85 @@
{
+ "definitions": {
+ "ObjectPattern": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "syntax": {
+ "enum": ["default", "named", "namespace", "side-effect"]
+ },
+ "moduleName": {
+ "type": "string",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "minLength": 1
+ },
+ "alias": {
+ "type": "string",
+ "minLength": 1
+ }
+ }
+ },
+ "ImportsStringPattern": {
+ "type": "string",
+ "minLength": 1
+ }
+ },
"type": "object",
- "properties": {},
+ "properties": {
+ "type": {
+ "enum": ["module", "commonjs"]
+ },
+ "imports": {
+ "anyOf": [
+ {
+ "$ref": "#/definitions/ImportsStringPattern"
+ },
+ {
+ "$ref": "#/definitions/ObjectPattern"
+ },
+ {
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "anyOf": [
+ {
+ "$ref": "#/definitions/ImportsStringPattern"
+ },
+ {
+ "$ref": "#/definitions/ObjectPattern"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "wrapper": {
+ "anyOf": [
+ {
+ "type": "string",
+ "minLength": 1
+ },
+ {
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "type": "string",
+ "minLength": 1
+ }
+ }
+ ]
+ },
+ "additionalCode": {
+ "type": "string",
+ "minLength": 1
+ }
+ },
+ "anyOf": [
+ { "required": ["imports"] },
+ { "required": ["wrapper"] },
+ { "required": ["additionalCode"] }
+ ],
"additionalProperties": false
}
diff --git a/src/utils.js b/src/utils.js
new file mode 100644
index 0000000..00e7af7
--- /dev/null
+++ b/src/utils.js
@@ -0,0 +1,201 @@
+import { stringifyRequest } from 'loader-utils';
+
+function resolveImports(type, item) {
+ let result;
+
+ if (typeof item === 'string') {
+ const splittedItem = item.split(' ');
+
+ if (splittedItem.length > 4) {
+ throw new Error(`Invalid "${item}" for import`);
+ }
+
+ if (splittedItem.length === 1) {
+ result = {
+ type,
+ syntax: 'default',
+ moduleName: splittedItem[0],
+ name: splittedItem[0],
+ // eslint-disable-next-line no-undefined
+ alias: undefined,
+ };
+ } else {
+ result = {
+ syntax: splittedItem[0],
+ moduleName: splittedItem[1],
+ name: splittedItem[2],
+ // eslint-disable-next-line no-undefined
+ alias: splittedItem[3] ? splittedItem[3] : undefined,
+ };
+ }
+ } else {
+ result = { syntax: 'default', ...item };
+
+ if (result.syntax === 'default' && !result.name) {
+ result.name = result.moduleName;
+ }
+ }
+
+ if (!result.moduleName) {
+ throw new Error(
+ `The import should have "moduleName" option in "${item}" value`
+ );
+ }
+
+ if (
+ ['default', 'side-effect'].includes(result.syntax) &&
+ typeof result.alias !== 'undefined'
+ ) {
+ throw new Error(
+ `The "${result.syntax}" syntax can't have "${result.alias}" alias in "${item}" value`
+ );
+ }
+
+ if (
+ ['side-effect'].includes(result.syntax) &&
+ typeof result.name !== 'undefined'
+ ) {
+ throw new Error(
+ `The "${result.syntax}" syntax can't have "${result.name}" name in "${item}" value`
+ );
+ }
+
+ if (['namespace'].includes(result.syntax) && type === 'commonjs') {
+ throw new Error(
+ `The "commonjs" type not support "namespace" syntax import in "${item}" value`
+ );
+ }
+
+ if (
+ ['namespace', 'named'].includes(result.syntax) &&
+ typeof result.name === 'undefined'
+ ) {
+ throw new Error(
+ `The "${result.syntax}" syntax should have "name" option in "${item}" value`
+ );
+ }
+
+ return result;
+}
+
+function getImports(type, imports) {
+ let result = [];
+
+ if (typeof imports === 'string') {
+ result.push(resolveImports(type, imports));
+ } else {
+ result = [].concat(imports).map((item) => resolveImports(type, item));
+ }
+
+ const sortedResults = {};
+
+ for (const item of result) {
+ if (!sortedResults[item.moduleName]) {
+ sortedResults[item.moduleName] = [];
+ }
+
+ sortedResults[item.moduleName].push(item);
+ }
+
+ for (const item of Object.entries(sortedResults)) {
+ const defaultImports = item[1].filter(
+ (entry) => entry.syntax === 'default'
+ );
+ const namespaceImports = item[1].filter(
+ (entry) => entry.syntax === 'namespace'
+ );
+ const sideEffectImports = item[1].filter(
+ (entry) => entry.syntax === 'side-effect'
+ );
+
+ [defaultImports, namespaceImports, sideEffectImports].forEach(
+ (importsSyntax) => {
+ if (importsSyntax.length > 1) {
+ const [{ syntax }] = importsSyntax;
+
+ throw new Error(
+ `The "${syntax}" syntax format can't have multiple import in "${item}" value`
+ );
+ }
+ }
+ );
+ }
+
+ return sortedResults;
+}
+
+function renderImports(loaderContext, type, imports) {
+ const [{ moduleName }] = imports;
+ const defaultImports = imports.filter((item) => item.syntax === 'default');
+ const namedImports = imports.filter((item) => item.syntax === 'named');
+ const namespaceImports = imports.filter(
+ (item) => item.syntax === 'namespace'
+ );
+ const sideEffectImports = imports.filter(
+ (item) => item.syntax === 'side-effect'
+ );
+ const isModule = type === 'module';
+
+ // 1. Import-side-effect
+ if (sideEffectImports.length > 0) {
+ return isModule
+ ? `import ${stringifyRequest(loaderContext, moduleName)};`
+ : `require(${stringifyRequest(loaderContext, moduleName)});`;
+ }
+
+ let code = isModule ? 'import' : '';
+
+ // 2. Default import
+ if (defaultImports.length > 0) {
+ const [{ name }] = defaultImports;
+
+ code += isModule
+ ? ` ${name}`
+ : `var ${name} = require(${stringifyRequest(
+ loaderContext,
+ moduleName
+ )});`;
+ }
+
+ // 3. Namespace import
+ if (namespaceImports.length > 0) {
+ if (defaultImports.length > 0) {
+ code += `,`;
+ }
+
+ const [{ name }] = namespaceImports;
+
+ code += ` * as ${name}`;
+ }
+
+ // 4. Named import
+ if (namedImports.length > 0) {
+ if (defaultImports.length > 0) {
+ code += isModule ? ', { ' : '\nvar { ';
+ } else {
+ code += isModule ? ' { ' : 'var { ';
+ }
+
+ namedImports.forEach((namedImport, i) => {
+ const comma = i > 0 ? ', ' : '';
+ const { name, alias } = namedImport;
+ const sep = isModule ? ' as ' : ': ';
+
+ code += alias ? `${comma}${name}${sep}${alias}` : `${comma}${name}`;
+ });
+
+ code += isModule
+ ? ' }'
+ : ` } = require(${stringifyRequest(loaderContext, moduleName)});`;
+ }
+
+ if (!isModule) {
+ return code;
+ }
+
+ code += ` from ${stringifyRequest(loaderContext, moduleName)};`;
+
+ return code;
+}
+
+export { getImports, renderImports };
diff --git a/test/__snapshots__/loader.test.js.snap b/test/__snapshots__/loader.test.js.snap
index 7496454..53ee8ed 100644
--- a/test/__snapshots__/loader.test.js.snap
+++ b/test/__snapshots__/loader.test.js.snap
@@ -1,21 +1,428 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`loader should set a variable: errors 1`] = `Array []`;
+exports[`loader should emit error inline: errors 1`] = `
+Array [
+ "ModuleBuildError: Module build failed (from \`replaced original path\`):
+Error: Invalid \\"named lib_2 name alias something\\" for import",
+]
+`;
+
+exports[`loader should emit error inline: warnings 1`] = `Array []`;
+
+exports[`loader should emit error when alias don\`t need: errors 1`] = `
+Array [
+ "ModuleBuildError: Module build failed (from \`replaced original path\`):
+Error: The \\"side-effect\\" syntax can't have \\"some_alias\\" alias in \\"[object Object]\\" value",
+]
+`;
+
+exports[`loader should emit error when alias don\`t need: errors 2`] = `
+Array [
+ "ModuleBuildError: Module build failed (from \`replaced original path\`):
+Error: The \\"side-effect\\" syntax can't have \\"some_name\\" name in \\"[object Object]\\" value",
+]
+`;
+
+exports[`loader should emit error when alias don\`t need: warnings 1`] = `Array []`;
+
+exports[`loader should emit error when alias don\`t need: warnings 2`] = `Array []`;
+
+exports[`loader should emit error when invalid arguments for import: errors 1`] = `
+Array [
+ "ModuleBuildError: Module build failed (from \`replaced original path\`):
+Error: The \\"default\\" syntax can't have \\"lib_2_method_2_short\\" alias in \\"[object Object]\\" value",
+]
+`;
+
+exports[`loader should emit error when invalid arguments for import: warnings 1`] = `Array []`;
+
+exports[`loader should emit error when multiple default import: errors 1`] = `
+Array [
+ "ModuleBuildError: Module build failed (from \`replaced original path\`):
+Error: The \\"default\\" syntax format can't have multiple import in \\"./lib_2,[object Object],[object Object]\\" value",
+]
+`;
+
+exports[`loader should emit error when multiple default import: warnings 1`] = `Array []`;
+
+exports[`loader should emit error when multiple namespace import: errors 1`] = `
+Array [
+ "ModuleBuildError: Module build failed (from \`replaced original path\`):
+Error: The \\"namespace\\" syntax format can't have multiple import in \\"./lib_2,[object Object],[object Object]\\" value",
+]
+`;
+
+exports[`loader should emit error when multiple namespace import: warnings 1`] = `Array []`;
+
+exports[`loader should emit error when multiple side-effect import: errors 1`] = `
+Array [
+ "ModuleBuildError: Module build failed (from \`replaced original path\`):
+Error: The \\"side-effect\\" syntax format can't have multiple import in \\"./lib_2,[object Object],[object Object]\\" value",
+]
+`;
+
+exports[`loader should emit error when multiple side-effect import: warnings 1`] = `Array []`;
+
+exports[`loader should emit error when not arguments for import: errors 1`] = `
+Array [
+ "ModuleBuildError: Module build failed (from \`replaced original path\`):
+ValidationError: Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.",
+]
+`;
+
+exports[`loader should emit error when not arguments for import: warnings 1`] = `Array []`;
+
+exports[`loader should emit error when skipped name to import-named: errors 1`] = `
+Array [
+ "ModuleBuildError: Module build failed (from \`replaced original path\`):
+Error: The \\"named\\" syntax should have \\"name\\" option in \\"[object Object]\\" value",
+]
+`;
+
+exports[`loader should emit error when skipped name to import-named: warnings 1`] = `Array []`;
+
+exports[`loader should emit error when try namespace import to commonjs: errors 1`] = `
+Array [
+ "ModuleBuildError: Module build failed (from \`replaced original path\`):
+Error: The \\"commonjs\\" type not support \\"namespace\\" syntax import in \\"[object Object]\\" value",
+]
+`;
+
+exports[`loader should emit error when try namespace import to commonjs: warnings 1`] = `Array []`;
+
+exports[`loader should require when import option is array: errors 1`] = `Array []`;
+
+exports[`loader should require when import option is array: result 1`] = `
+"/*** IMPORTS FROM imports-loader ***/
+import lib_1 from \\"lib_1\\";
+import lib_2 from \\"lib_2\\";
+
+var someCode = {
+ number: 123,
+ object: { existingSubProperty: 123 }
+};
+"
+`;
+
+exports[`loader should require when import option is array: warnings 1`] = `Array []`;
+
+exports[`loader should require when import option is object: errors 1`] = `Array []`;
+
+exports[`loader should require when import option is object: result 1`] = `
+"/*** IMPORTS FROM imports-loader ***/
+import $ from \\"./lib_1\\";
+
+var someCode = {
+ number: 123,
+ object: { existingSubProperty: 123 }
+};
+"
+`;
+
+exports[`loader should require when import option is object: warnings 1`] = `Array []`;
+
+exports[`loader should require when import option is string: errors 1`] = `Array []`;
+
+exports[`loader should require when import option is string: result 1`] = `
+"/*** IMPORTS FROM imports-loader ***/
+import lib_1 from \\"lib_1\\";
+
+var someCode = {
+ number: 123,
+ object: { existingSubProperty: 123 }
+};
+"
+`;
+
+exports[`loader should require when import option is string: warnings 1`] = `Array []`;
+
+exports[`loader should require when import-default: errors 1`] = `Array []`;
+
+exports[`loader should require when import-default: result 1`] = `
+"/*** IMPORTS FROM imports-loader ***/
+import lib_1 from \\"lib_1\\";
+import lib_2 from \\"./lib_2.js\\";
+import defaultExport, { lib_3_method as method } from \\"./lib_3.js\\";
+import lib_4, * as lib_4_all from \\"./lib_4\\";
+
+var someCode = {
+ number: 123,
+ object: { existingSubProperty: 123 }
+};
+"
+`;
+
+exports[`loader should require when import-default: warnings 1`] = `Array []`;
+
+exports[`loader should require when import-side-effect: errors 1`] = `Array []`;
+
+exports[`loader should require when import-side-effect: result 1`] = `
+"/*** IMPORTS FROM imports-loader ***/
+import \\"./lib_1\\";
+
+var someCode = {
+ number: 123,
+ object: { existingSubProperty: 123 }
+};
+"
+`;
+
+exports[`loader should require when import-side-effect: warnings 1`] = `Array []`;
+
+exports[`loader should require when name-space-import: errors 1`] = `Array []`;
+
+exports[`loader should require when name-space-import: result 1`] = `
+"/*** IMPORTS FROM imports-loader ***/
+import * as lib_1_all from \\"./lib_1\\";
+
+var someCode = {
+ number: 123,
+ object: { existingSubProperty: 123 }
+};
+"
+`;
+
+exports[`loader should require when name-space-import: warnings 1`] = `Array []`;
+
+exports[`loader should require when named-imports: errors 1`] = `Array []`;
+
+exports[`loader should require when named-imports: result 1`] = `
+"/*** IMPORTS FROM imports-loader ***/
+import { lib1_method } from \\"./lib_1\\";
+import lib2_default, { lib2_method_1, lib2_method_2 as lib_2_method_2_short } from \\"./lib_2\\";
+
+var someCode = {
+ number: 123,
+ object: { existingSubProperty: 123 }
+};
+"
+`;
+
+exports[`loader should require when named-imports: warnings 1`] = `Array []`;
+
+exports[`loader should work additionalCode option: errors 1`] = `Array []`;
+
+exports[`loader should work additionalCode option: result 1`] = `
+"/*** IMPORTS FROM imports-loader ***/
+
+var someVariable = 1;
+var someCode = {
+ number: 123,
+ object: { existingSubProperty: 123 }
+};
+"
+`;
+
+exports[`loader should work additionalCode option: warnings 1`] = `Array []`;
+
+exports[`loader should work destructuring require: errors 1`] = `Array []`;
+
+exports[`loader should work destructuring require: result 1`] = `
+"/*** IMPORTS FROM imports-loader ***/
+var { lib2_method_1, lib2_method_2: lib_2_method_2_short } = require(\\"./lib_2\\");
+
+var someCode = {
+ number: 123,
+ object: { existingSubProperty: 123 }
+};
+"
+`;
+
+exports[`loader should work destructuring require: warnings 1`] = `Array []`;
+
+exports[`loader should work few require: errors 1`] = `Array []`;
+
+exports[`loader should work few require: result 1`] = `
+"/*** IMPORTS FROM imports-loader ***/
+var $ = require(\\"./lib_1\\");
+var lib_2_all = require(\\"./lib_2\\");
+var { lib2_method_1, lib2_method_2: lib_2_method_2_short } = require(\\"./lib_2\\");
+
+var someCode = {
+ number: 123,
+ object: { existingSubProperty: 123 }
+};
+"
+`;
+
+exports[`loader should work few require: warnings 1`] = `Array []`;
+
+exports[`loader should work import, wrapper and additionalCode option: errors 1`] = `Array []`;
-exports[`loader should set a variable: result 1`] = `
+exports[`loader should work import, wrapper and additionalCode option: result 1`] = `
"/*** IMPORTS FROM imports-loader ***/
+import \\"./lib_1\\";
+
var someVariable = 1;
-var anotherVariable = 2;
-var someVariable = (someVariable || {});
-someVariable.someProperty = someVariable.someProperty || {};
-someVariable.someProperty.someSubProperty = 1;
+(function() {
+var someCode = {
+ number: 123,
+ object: { existingSubProperty: 123 }
+};
+
+}.call(window));"
+`;
+
+exports[`loader should work import, wrapper and additionalCode option: warnings 1`] = `Array []`;
+
+exports[`loader should work inline 1: errors 1`] = `Array []`;
+
+exports[`loader should work inline 1: result 1`] = `
+"/*** IMPORTS FROM imports-loader ***/
+import lib_1 from \\"lib_1\\";
+import lib_2 from \\"lib_2\\";
var someCode = {
number: 123,
object: { existingSubProperty: 123 }
};
+"
+`;
+
+exports[`loader should work inline 1: warnings 1`] = `Array []`;
+exports[`loader should work inline 2: errors 1`] = `Array []`;
+
+exports[`loader should work inline 2: result 1`] = `
+"/*** IMPORTS FROM imports-loader ***/
+var lib_2_all = require(\\"lib_2\\");
+var { lib_2_method: lib_2_method_alias } = require(\\"lib_2\\");
+
+var someCode = {
+ number: 123,
+ object: { existingSubProperty: 123 }
+};
"
`;
-exports[`loader should set a variable: warnings 1`] = `Array []`;
+exports[`loader should work inline 2: warnings 1`] = `Array []`;
+
+exports[`loader should work inline 3: errors 1`] = `Array []`;
+
+exports[`loader should work inline 3: result 1`] = `
+"/*** IMPORTS FROM imports-loader ***/
+import $ from \\"lib_2\\";
+
+(function() {
+var someCode = {
+ number: 123,
+ object: { existingSubProperty: 123 }
+};
+
+}.call(window));"
+`;
+
+exports[`loader should work inline 3: warnings 1`] = `Array []`;
+
+exports[`loader should work pure require: errors 1`] = `Array []`;
+
+exports[`loader should work pure require: result 1`] = `
+"/*** IMPORTS FROM imports-loader ***/
+require(\\"./lib_1\\");
+
+var someCode = {
+ number: 123,
+ object: { existingSubProperty: 123 }
+};
+"
+`;
+
+exports[`loader should work pure require: warnings 1`] = `Array []`;
+
+exports[`loader should work require default: errors 1`] = `Array []`;
+
+exports[`loader should work require default: result 1`] = `
+"/*** IMPORTS FROM imports-loader ***/
+var $ = require(\\"./lib_1\\");
+
+var someCode = {
+ number: 123,
+ object: { existingSubProperty: 123 }
+};
+"
+`;
+
+exports[`loader should work require default: warnings 1`] = `Array []`;
+
+exports[`loader should work require: errors 1`] = `Array []`;
+
+exports[`loader should work require: result 1`] = `
+"/*** IMPORTS FROM imports-loader ***/
+var $ = require(\\"./lib_1\\");
+
+var someCode = {
+ number: 123,
+ object: { existingSubProperty: 123 }
+};
+"
+`;
+
+exports[`loader should work require: warnings 1`] = `Array []`;
+
+exports[`loader should work string syntax when commonjs type: errors 1`] = `Array []`;
+
+exports[`loader should work string syntax when commonjs type: result 1`] = `
+"/*** IMPORTS FROM imports-loader ***/
+var $ = require(\\"./lib_1\\");
+var lib_2_all = require(\\"./lib_2\\");
+var { lib2_method_1, lib2_method_2: lib_2_method_2_short } = require(\\"./lib_2\\");
+require(\\"./lib_3\\");
+
+var someCode = {
+ number: 123,
+ object: { existingSubProperty: 123 }
+};
+"
+`;
+
+exports[`loader should work string syntax when commonjs type: warnings 1`] = `Array []`;
+
+exports[`loader should work string syntax when module type: errors 1`] = `Array []`;
+
+exports[`loader should work string syntax when module type: result 1`] = `
+"/*** IMPORTS FROM imports-loader ***/
+import $ from \\"./lib_1\\";
+import lib_2_all, { lib2_method_1, lib2_method_2 as lib_2_method_2_short } from \\"./lib_2\\";
+import lib_3_defaul, * as lib_3_all from \\"./lib_3\\";
+import \\"./lib_4\\";
+
+var someCode = {
+ number: 123,
+ object: { existingSubProperty: 123 }
+};
+"
+`;
+
+exports[`loader should work string syntax when module type: warnings 1`] = `Array []`;
+
+exports[`loader should work wrapper array: errors 1`] = `Array []`;
+
+exports[`loader should work wrapper array: result 1`] = `
+"/*** IMPORTS FROM imports-loader ***/
+
+(function() {
+var someCode = {
+ number: 123,
+ object: { existingSubProperty: 123 }
+};
+
+}.call(window,document));"
+`;
+
+exports[`loader should work wrapper array: warnings 1`] = `Array []`;
+
+exports[`loader should work wrapper: errors 1`] = `Array []`;
+
+exports[`loader should work wrapper: result 1`] = `
+"/*** IMPORTS FROM imports-loader ***/
+
+(function() {
+var someCode = {
+ number: 123,
+ object: { existingSubProperty: 123 }
+};
+
+}.call(window));"
+`;
+
+exports[`loader should work wrapper: warnings 1`] = `Array []`;
diff --git a/test/__snapshots__/validate-options.test.js.snap b/test/__snapshots__/validate-options.test.js.snap
new file mode 100644
index 0000000..9441de6
--- /dev/null
+++ b/test/__snapshots__/validate-options.test.js.snap
@@ -0,0 +1,237 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`validate options should throw an error on the "additionalCode" option with "/test/" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options.additionalCode should be a non-empty string."
+`;
+
+exports[`validate options should throw an error on the "additionalCode" option with "[""]" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options.additionalCode should be a non-empty string."
+`;
+
+exports[`validate options should throw an error on the "additionalCode" option with "[]" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options.additionalCode should be a non-empty string."
+`;
+
+exports[`validate options should throw an error on the "additionalCode" option with "{}" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options.additionalCode should be a non-empty string."
+`;
+
+exports[`validate options should throw an error on the "additionalCode" option with "false" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options.additionalCode should be a non-empty string."
+`;
+
+exports[`validate options should throw an error on the "additionalCode" option with "true" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options.additionalCode should be a non-empty string."
+`;
+
+exports[`validate options should throw an error on the "imports" option with "" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options.imports should be an non-empty string."
+`;
+
+exports[`validate options should throw an error on the "imports" option with "/test/" value 1`] = `"The import should have \\"moduleName\\" option in \\"/test/\\" value"`;
+
+exports[`validate options should throw an error on the "imports" option with "[""]" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options.imports[0] should be an non-empty string."
+`;
+
+exports[`validate options should throw an error on the "imports" option with "[]" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options.imports should be an non-empty array."
+`;
+
+exports[`validate options should throw an error on the "imports" option with "{"syntax":"default","moduleName":"jQuery","name":"lib","alias":"lib_alias"}" value 1`] = `"The \\"default\\" syntax can't have \\"lib_alias\\" alias in \\"[object Object]\\" value"`;
+
+exports[`validate options should throw an error on the "imports" option with "{"type":"string","moduleName":"jQuery","list":false}" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options.imports should be one of these:
+ non-empty string | object { syntax?, moduleName?, name?, alias? } | [non-empty string | object { syntax?, moduleName?, name?, alias? }, ...] (should not have fewer than 1 item)
+ Details:
+ * options.imports has an unknown property 'type'. These properties are valid:
+ object { syntax?, moduleName?, name?, alias? }
+ * options.imports has an unknown property 'list'. These properties are valid:
+ object { syntax?, moduleName?, name?, alias? }"
+`;
+
+exports[`validate options should throw an error on the "imports" option with "{}" value 1`] = `"The import should have \\"moduleName\\" option in \\"[object Object]\\" value"`;
+
+exports[`validate options should throw an error on the "imports" option with "false" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options.imports should be one of these:
+ non-empty string | object { syntax?, moduleName?, name?, alias? } | [non-empty string | object { syntax?, moduleName?, name?, alias? }, ...] (should not have fewer than 1 item)
+ Details:
+ * options.imports should be a non-empty string.
+ * options.imports should be an object:
+ object { syntax?, moduleName?, name?, alias? }
+ * options.imports should be an array:
+ [non-empty string | object { syntax?, moduleName?, name?, alias? }, ...] (should not have fewer than 1 item)"
+`;
+
+exports[`validate options should throw an error on the "imports" option with "true" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options.imports should be one of these:
+ non-empty string | object { syntax?, moduleName?, name?, alias? } | [non-empty string | object { syntax?, moduleName?, name?, alias? }, ...] (should not have fewer than 1 item)
+ Details:
+ * options.imports should be a non-empty string.
+ * options.imports should be an object:
+ object { syntax?, moduleName?, name?, alias? }
+ * options.imports should be an array:
+ [non-empty string | object { syntax?, moduleName?, name?, alias? }, ...] (should not have fewer than 1 item)"
+`;
+
+exports[`validate options should throw an error on the "type" option with "" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options.type should be one of these:
+ \\"module\\" | \\"commonjs\\""
+`;
+
+exports[`validate options should throw an error on the "type" option with "[]" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options.type should be one of these:
+ \\"module\\" | \\"commonjs\\""
+`;
+
+exports[`validate options should throw an error on the "type" option with "{}" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options.type should be one of these:
+ \\"module\\" | \\"commonjs\\""
+`;
+
+exports[`validate options should throw an error on the "type" option with "string" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options.type should be one of these:
+ \\"module\\" | \\"commonjs\\""
+`;
+
+exports[`validate options should throw an error on the "unknown" option with "/test/" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options should be one of these:
+ object { imports, … } | object { wrapper, … } | object { additionalCode, … }
+ Details:
+ * options has an unknown property 'unknown'. These properties are valid:
+ object { imports, … } | object { wrapper, … } | object { additionalCode, … }
+ * options misses the property 'imports' | should be any non-object.
+ * options misses the property 'wrapper' | should be any non-object.
+ * options misses the property 'additionalCode' | should be any non-object."
+`;
+
+exports[`validate options should throw an error on the "unknown" option with "[]" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options should be one of these:
+ object { imports, … } | object { wrapper, … } | object { additionalCode, … }
+ Details:
+ * options has an unknown property 'unknown'. These properties are valid:
+ object { imports, … } | object { wrapper, … } | object { additionalCode, … }
+ * options misses the property 'imports' | should be any non-object.
+ * options misses the property 'wrapper' | should be any non-object.
+ * options misses the property 'additionalCode' | should be any non-object."
+`;
+
+exports[`validate options should throw an error on the "unknown" option with "{"foo":"bar"}" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options should be one of these:
+ object { imports, … } | object { wrapper, … } | object { additionalCode, … }
+ Details:
+ * options has an unknown property 'unknown'. These properties are valid:
+ object { imports, … } | object { wrapper, … } | object { additionalCode, … }
+ * options misses the property 'imports' | should be any non-object.
+ * options misses the property 'wrapper' | should be any non-object.
+ * options misses the property 'additionalCode' | should be any non-object."
+`;
+
+exports[`validate options should throw an error on the "unknown" option with "{}" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options should be one of these:
+ object { imports, … } | object { wrapper, … } | object { additionalCode, … }
+ Details:
+ * options has an unknown property 'unknown'. These properties are valid:
+ object { imports, … } | object { wrapper, … } | object { additionalCode, … }
+ * options misses the property 'imports' | should be any non-object.
+ * options misses the property 'wrapper' | should be any non-object.
+ * options misses the property 'additionalCode' | should be any non-object."
+`;
+
+exports[`validate options should throw an error on the "unknown" option with "1" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options should be one of these:
+ object { imports, … } | object { wrapper, … } | object { additionalCode, … }
+ Details:
+ * options has an unknown property 'unknown'. These properties are valid:
+ object { imports, … } | object { wrapper, … } | object { additionalCode, … }
+ * options misses the property 'imports' | should be any non-object.
+ * options misses the property 'wrapper' | should be any non-object.
+ * options misses the property 'additionalCode' | should be any non-object."
+`;
+
+exports[`validate options should throw an error on the "unknown" option with "false" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options should be one of these:
+ object { imports, … } | object { wrapper, … } | object { additionalCode, … }
+ Details:
+ * options has an unknown property 'unknown'. These properties are valid:
+ object { imports, … } | object { wrapper, … } | object { additionalCode, … }
+ * options misses the property 'imports' | should be any non-object.
+ * options misses the property 'wrapper' | should be any non-object.
+ * options misses the property 'additionalCode' | should be any non-object."
+`;
+
+exports[`validate options should throw an error on the "unknown" option with "test" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options should be one of these:
+ object { imports, … } | object { wrapper, … } | object { additionalCode, … }
+ Details:
+ * options has an unknown property 'unknown'. These properties are valid:
+ object { imports, … } | object { wrapper, … } | object { additionalCode, … }
+ * options misses the property 'imports' | should be any non-object.
+ * options misses the property 'wrapper' | should be any non-object.
+ * options misses the property 'additionalCode' | should be any non-object."
+`;
+
+exports[`validate options should throw an error on the "unknown" option with "true" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options should be one of these:
+ object { imports, … } | object { wrapper, … } | object { additionalCode, … }
+ Details:
+ * options has an unknown property 'unknown'. These properties are valid:
+ object { imports, … } | object { wrapper, … } | object { additionalCode, … }
+ * options misses the property 'imports' | should be any non-object.
+ * options misses the property 'wrapper' | should be any non-object.
+ * options misses the property 'additionalCode' | should be any non-object."
+`;
+
+exports[`validate options should throw an error on the "wrapper" option with "[""]" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options.wrapper[0] should be an non-empty string."
+`;
+
+exports[`validate options should throw an error on the "wrapper" option with "[]" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options.wrapper should be an non-empty array."
+`;
+
+exports[`validate options should throw an error on the "wrapper" option with "false" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options.wrapper should be one of these:
+ non-empty string | [non-empty string, ...] (should not have fewer than 1 item)
+ Details:
+ * options.wrapper should be a non-empty string.
+ * options.wrapper should be an array:
+ [non-empty string, ...] (should not have fewer than 1 item)"
+`;
+
+exports[`validate options should throw an error on the "wrapper" option with "true" value 1`] = `
+"Invalid options object. Imports loader has been initialized using an options object that does not match the API schema.
+ - options.wrapper should be one of these:
+ non-empty string | [non-empty string, ...] (should not have fewer than 1 item)
+ Details:
+ * options.wrapper should be a non-empty string.
+ * options.wrapper should be an array:
+ [non-empty string, ...] (should not have fewer than 1 item)"
+`;
diff --git a/test/cjs.test.js b/test/cjs.test.js
new file mode 100644
index 0000000..8aba6ba
--- /dev/null
+++ b/test/cjs.test.js
@@ -0,0 +1,8 @@
+import src from '../src';
+import cjs from '../src/cjs';
+
+describe('cjs', () => {
+ it('should exported', () => {
+ expect(cjs).toEqual(src);
+ });
+});
diff --git a/test/fixtures/inline-broken.js b/test/fixtures/inline-broken.js
new file mode 100644
index 0000000..e8d3ab0
--- /dev/null
+++ b/test/fixtures/inline-broken.js
@@ -0,0 +1 @@
+require('../../src/cjs.js?imports=named%20lib_2%20name%20alias%20something!./some-library.js');
diff --git a/test/fixtures/inline.js b/test/fixtures/inline.js
new file mode 100644
index 0000000..12c0b59
--- /dev/null
+++ b/test/fixtures/inline.js
@@ -0,0 +1 @@
+require('../../src/cjs.js?imports[]=lib_1&imports[]=lib_2!./some-library.js');
diff --git a/test/fixtures/inline2.js b/test/fixtures/inline2.js
new file mode 100644
index 0000000..5884ea9
--- /dev/null
+++ b/test/fixtures/inline2.js
@@ -0,0 +1 @@
+require('../../src/cjs.js?type=commonjs&imports[]=default%20lib_2%20lib_2_all&imports[]=named%20lib_2%20lib_2_method%20lib_2_method_alias!./some-library.js');
diff --git a/test/fixtures/inline3.js b/test/fixtures/inline3.js
new file mode 100644
index 0000000..d8a3e41
--- /dev/null
+++ b/test/fixtures/inline3.js
@@ -0,0 +1,2 @@
+require('../../src/cjs.js?wrapper=window&imports=default%20lib_2%20$!./some-library.js');
+
diff --git a/test/fixtures/lib_1.js b/test/fixtures/lib_1.js
new file mode 100644
index 0000000..b77dac7
--- /dev/null
+++ b/test/fixtures/lib_1.js
@@ -0,0 +1 @@
+export default function lib() {}
diff --git a/test/fixtures/lib_2.js b/test/fixtures/lib_2.js
new file mode 100644
index 0000000..b77dac7
--- /dev/null
+++ b/test/fixtures/lib_2.js
@@ -0,0 +1 @@
+export default function lib() {}
diff --git a/test/fixtures/lib_3.js b/test/fixtures/lib_3.js
new file mode 100644
index 0000000..b77dac7
--- /dev/null
+++ b/test/fixtures/lib_3.js
@@ -0,0 +1 @@
+export default function lib() {}
diff --git a/test/fixtures/lib_4.js b/test/fixtures/lib_4.js
new file mode 100644
index 0000000..b77dac7
--- /dev/null
+++ b/test/fixtures/lib_4.js
@@ -0,0 +1 @@
+export default function lib() {}
diff --git a/test/helpers/getCompiler.js b/test/helpers/getCompiler.js
index 0ba5363..89413b3 100644
--- a/test/helpers/getCompiler.js
+++ b/test/helpers/getCompiler.js
@@ -3,7 +3,26 @@ import path from 'path';
import webpack from 'webpack';
import { createFsFromVolume, Volume } from 'memfs';
-export default (fixture, loaderOptions = {}, config = {}) => {
+export default (
+ fixture,
+ loaderOptions = {},
+ config = {},
+ disableLoader = false
+) => {
+ const loaders = [];
+
+ if (!disableLoader) {
+ loaders.push({
+ test: path.resolve(__dirname, '../fixtures', fixture),
+ use: [
+ {
+ loader: path.resolve(__dirname, '../../src'),
+ options: loaderOptions || {},
+ },
+ ],
+ });
+ }
+
const fullConfig = {
mode: 'development',
devtool: config.devtool || false,
@@ -17,19 +36,17 @@ export default (fixture, loaderOptions = {}, config = {}) => {
// libraryTarget: 'var',
},
module: {
- rules: [
- {
- test: /.js/i,
- rules: [
- {
- loader: path.resolve(__dirname, '../../src'),
- options: loaderOptions || {},
- },
- ],
- },
- ],
+ rules: loaders,
},
plugins: [],
+ resolve: {
+ alias: {
+ lib_1: path.resolve(__dirname, '../', 'fixtures', 'lib_1'),
+ lib_2: path.resolve(__dirname, '../', 'fixtures', 'lib_2'),
+ lib_3: path.resolve(__dirname, '../', 'fixtures', 'lib_3'),
+ lib_4: path.resolve(__dirname, '../', 'fixtures', 'lib_4'),
+ },
+ },
...config,
};
diff --git a/test/helpers/getModuleSource.js b/test/helpers/getModuleSource.js
index 27e7cb9..610fc30 100644
--- a/test/helpers/getModuleSource.js
+++ b/test/helpers/getModuleSource.js
@@ -1,6 +1,7 @@
export default (name, stats) => {
const { modules } = stats.toJson({ source: true });
- const module = modules.find((m) => m.name === name);
+
+ const module = modules.find((m) => m.name.indexOf(name) !== -1);
return module.source;
};
diff --git a/test/loader.test.js b/test/loader.test.js
index 25ffa69..73bc5dc 100644
--- a/test/loader.test.js
+++ b/test/loader.test.js
@@ -7,11 +7,9 @@ import {
} from './helpers';
describe('loader', () => {
- it.only('should set a variable', async () => {
+ it('should require when import option is string', async () => {
const compiler = getCompiler('some-library.js', {
- someVariable: '>1',
- anotherVariable: '>2',
- 'someVariable.someProperty.someSubProperty': '>1',
+ imports: 'lib_1',
});
const stats = await compile(compiler);
@@ -21,4 +19,505 @@ describe('loader', () => {
expect(getErrors(stats)).toMatchSnapshot('errors');
expect(getWarnings(stats)).toMatchSnapshot('warnings');
});
+
+ it('should require when import option is object', async () => {
+ const compiler = getCompiler('some-library.js', {
+ imports: {
+ moduleName: './lib_1',
+ name: '$',
+ },
+ });
+ const stats = await compile(compiler);
+
+ expect(getModuleSource('./some-library.js', stats)).toMatchSnapshot(
+ 'result'
+ );
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should require when import option is array', async () => {
+ const compiler = getCompiler('some-library.js', {
+ imports: ['lib_1', 'lib_2'],
+ });
+ const stats = await compile(compiler);
+
+ expect(getModuleSource('./some-library.js', stats)).toMatchSnapshot(
+ 'result'
+ );
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should require when import-default', async () => {
+ const compiler = getCompiler('some-library.js', {
+ imports: [
+ 'lib_1',
+ {
+ syntax: 'default',
+ moduleName: './lib_2.js',
+ name: 'lib_2',
+ },
+ {
+ syntax: 'default',
+ moduleName: './lib_3.js',
+ name: 'defaultExport',
+ },
+ {
+ syntax: 'named',
+ moduleName: './lib_3.js',
+ name: 'lib_3_method',
+ alias: 'method',
+ },
+ {
+ syntax: 'default',
+ moduleName: './lib_4',
+ name: 'lib_4',
+ },
+ {
+ syntax: 'namespace',
+ moduleName: './lib_4',
+ name: 'lib_4_all',
+ },
+ ],
+ });
+ const stats = await compile(compiler);
+
+ expect(getModuleSource('./some-library.js', stats)).toMatchSnapshot(
+ 'result'
+ );
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should require when name-space-import', async () => {
+ const compiler = getCompiler('some-library.js', {
+ imports: [
+ {
+ moduleName: './lib_1',
+ name: 'lib_1_all',
+ syntax: 'namespace',
+ },
+ ],
+ });
+ const stats = await compile(compiler);
+
+ expect(getModuleSource('./some-library.js', stats)).toMatchSnapshot(
+ 'result'
+ );
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should require when named-imports', async () => {
+ const compiler = getCompiler('some-library.js', {
+ imports: [
+ {
+ syntax: 'named',
+ moduleName: './lib_1',
+ name: 'lib1_method',
+ },
+ {
+ moduleName: './lib_2',
+ name: 'lib2_default',
+ },
+ {
+ syntax: 'named',
+ moduleName: './lib_2',
+ name: 'lib2_method_1',
+ },
+ {
+ syntax: 'named',
+ moduleName: './lib_2',
+ name: 'lib2_method_2',
+ alias: 'lib_2_method_2_short',
+ },
+ ],
+ });
+ const stats = await compile(compiler);
+
+ expect(getModuleSource('./some-library.js', stats)).toMatchSnapshot(
+ 'result'
+ );
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should require when import-side-effect', async () => {
+ const compiler = getCompiler('some-library.js', {
+ imports: {
+ moduleName: './lib_1',
+ syntax: 'side-effect',
+ },
+ });
+ const stats = await compile(compiler);
+
+ expect(getModuleSource('./some-library.js', stats)).toMatchSnapshot(
+ 'result'
+ );
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should work wrapper', async () => {
+ const compiler = getCompiler('some-library.js', {
+ wrapper: 'window',
+ });
+ const stats = await compile(compiler);
+
+ expect(getModuleSource('./some-library.js', stats)).toMatchSnapshot(
+ 'result'
+ );
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should work wrapper array', async () => {
+ const compiler = getCompiler('some-library.js', {
+ wrapper: ['window', 'document'],
+ });
+ const stats = await compile(compiler);
+
+ expect(getModuleSource('./some-library.js', stats)).toMatchSnapshot(
+ 'result'
+ );
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should work additionalCode option', async () => {
+ const compiler = getCompiler('some-library.js', {
+ additionalCode: 'var someVariable = 1;',
+ });
+ const stats = await compile(compiler);
+
+ expect(getModuleSource('./some-library.js', stats)).toMatchSnapshot(
+ 'result'
+ );
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should work import, wrapper and additionalCode option', async () => {
+ const compiler = getCompiler('some-library.js', {
+ imports: {
+ moduleName: './lib_1',
+ syntax: 'side-effect',
+ },
+ wrapper: 'window',
+ additionalCode: 'var someVariable = 1;',
+ });
+ const stats = await compile(compiler);
+
+ expect(getModuleSource('./some-library.js', stats)).toMatchSnapshot(
+ 'result'
+ );
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should work require', async () => {
+ const compiler = getCompiler('some-library.js', {
+ type: 'commonjs',
+ imports: {
+ moduleName: './lib_1',
+ name: '$',
+ },
+ });
+ const stats = await compile(compiler);
+
+ expect(getModuleSource('./some-library.js', stats)).toMatchSnapshot(
+ 'result'
+ );
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should work require default', async () => {
+ const compiler = getCompiler('some-library.js', {
+ type: 'commonjs',
+ imports: {
+ moduleName: './lib_1',
+ name: '$',
+ syntax: 'default',
+ },
+ });
+ const stats = await compile(compiler);
+
+ expect(getModuleSource('./some-library.js', stats)).toMatchSnapshot(
+ 'result'
+ );
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should work destructuring require', async () => {
+ const compiler = getCompiler('some-library.js', {
+ type: 'commonjs',
+ imports: [
+ {
+ syntax: 'named',
+ moduleName: './lib_2',
+ name: 'lib2_method_1',
+ },
+ {
+ syntax: 'named',
+ moduleName: './lib_2',
+ name: 'lib2_method_2',
+ alias: 'lib_2_method_2_short',
+ },
+ ],
+ });
+ const stats = await compile(compiler);
+
+ expect(getModuleSource('./some-library.js', stats)).toMatchSnapshot(
+ 'result'
+ );
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should work few require', async () => {
+ const compiler = getCompiler('some-library.js', {
+ type: 'commonjs',
+ imports: [
+ {
+ moduleName: './lib_1',
+ name: '$',
+ },
+ {
+ moduleName: './lib_2',
+ name: 'lib_2_all',
+ },
+ {
+ syntax: 'named',
+ moduleName: './lib_2',
+ name: 'lib2_method_1',
+ },
+ {
+ syntax: 'named',
+ moduleName: './lib_2',
+ name: 'lib2_method_2',
+ alias: 'lib_2_method_2_short',
+ },
+ ],
+ });
+ const stats = await compile(compiler);
+
+ expect(getModuleSource('./some-library.js', stats)).toMatchSnapshot(
+ 'result'
+ );
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should work pure require', async () => {
+ const compiler = getCompiler('some-library.js', {
+ type: 'commonjs',
+ imports: {
+ syntax: 'side-effect',
+ moduleName: './lib_1',
+ },
+ });
+ const stats = await compile(compiler);
+
+ expect(getModuleSource('./some-library.js', stats)).toMatchSnapshot(
+ 'result'
+ );
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should work string syntax when commonjs type', async () => {
+ const compiler = getCompiler('some-library.js', {
+ type: 'commonjs',
+ imports: [
+ 'default ./lib_1 $',
+ 'default ./lib_2 lib_2_all',
+ 'named ./lib_2 lib2_method_1',
+ 'named ./lib_2 lib2_method_2 lib_2_method_2_short',
+ 'side-effect ./lib_3',
+ ],
+ });
+ const stats = await compile(compiler);
+
+ expect(getModuleSource('./some-library.js', stats)).toMatchSnapshot(
+ 'result'
+ );
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should work string syntax when module type', async () => {
+ const compiler = getCompiler('some-library.js', {
+ imports: [
+ 'default ./lib_1 $',
+ 'default ./lib_2 lib_2_all',
+ 'named ./lib_2 lib2_method_1',
+ 'named ./lib_2 lib2_method_2 lib_2_method_2_short',
+ 'default ./lib_3 lib_3_defaul',
+ 'namespace ./lib_3 lib_3_all',
+ 'side-effect ./lib_4',
+ ],
+ });
+ const stats = await compile(compiler);
+
+ expect(getModuleSource('./some-library.js', stats)).toMatchSnapshot(
+ 'result'
+ );
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should emit error when alias don`t need', async () => {
+ const compiler = getCompiler('some-library.js', {
+ imports: {
+ moduleName: './lib_1',
+ syntax: 'side-effect',
+ alias: 'some_alias',
+ },
+ });
+ const stats = await compile(compiler);
+
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should emit error when alias don`t need', async () => {
+ const compiler = getCompiler('some-library.js', {
+ imports: {
+ moduleName: './lib_1',
+ syntax: 'side-effect',
+ name: 'some_name',
+ },
+ });
+ const stats = await compile(compiler);
+
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should emit error when skipped name to import-named', async () => {
+ const compiler = getCompiler('some-library.js', {
+ imports: {
+ moduleName: './lib_2.js',
+ syntax: 'named',
+ },
+ });
+ const stats = await compile(compiler);
+
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should emit error when try namespace import to commonjs', async () => {
+ const compiler = getCompiler('some-library.js', {
+ type: 'commonjs',
+ imports: [
+ {
+ moduleName: './lib_4',
+ name: 'lib_4_all',
+ syntax: 'namespace',
+ },
+ ],
+ });
+ const stats = await compile(compiler);
+
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should emit error when invalid arguments for import', async () => {
+ const compiler = getCompiler('some-library.js', {
+ imports: [
+ {
+ moduleName: './lib_2',
+ alias: 'lib_2_method_2_short',
+ },
+ ],
+ });
+ const stats = await compile(compiler);
+
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should emit error when multiple default import', async () => {
+ const compiler = getCompiler('some-library.js', {
+ imports: ['default ./lib_2 lib_2', 'default ./lib_2 lib_3'],
+ });
+ const stats = await compile(compiler);
+
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should emit error when multiple namespace import', async () => {
+ const compiler = getCompiler('some-library.js', {
+ imports: ['namespace ./lib_2 lib_2', 'namespace ./lib_2 lib_3'],
+ });
+ const stats = await compile(compiler);
+
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should emit error when multiple side-effect import', async () => {
+ const compiler = getCompiler('some-library.js', {
+ imports: ['side-effect ./lib_2', 'side-effect ./lib_2'],
+ });
+ const stats = await compile(compiler);
+
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should emit error when not arguments for import', async () => {
+ const compiler = getCompiler('some-library.js', {});
+ const stats = await compile(compiler);
+
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should work inline 1', async () => {
+ const compiler = getCompiler('inline.js', {}, {}, true);
+ const stats = await compile(compiler);
+
+ expect(getModuleSource('./some-library.js', stats)).toMatchSnapshot(
+ 'result'
+ );
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should work inline 2', async () => {
+ const compiler = getCompiler('inline2.js', {}, {}, true);
+ const stats = await compile(compiler);
+
+ expect(getModuleSource('./some-library.js', stats)).toMatchSnapshot(
+ 'result'
+ );
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should work inline 3', async () => {
+ const compiler = getCompiler('inline3.js', {}, {}, true);
+ const stats = await compile(compiler);
+
+ expect(getModuleSource('./some-library.js', stats)).toMatchSnapshot(
+ 'result'
+ );
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
+
+ it('should emit error inline', async () => {
+ const compiler = getCompiler('inline-broken.js', {}, {}, true);
+ const stats = await compile(compiler);
+
+ expect(getErrors(stats)).toMatchSnapshot('errors');
+ expect(getWarnings(stats)).toMatchSnapshot('warnings');
+ });
});
diff --git a/test/validate-options.test.js b/test/validate-options.test.js
new file mode 100644
index 0000000..b72f93a
--- /dev/null
+++ b/test/validate-options.test.js
@@ -0,0 +1,129 @@
+import { getCompiler, compile } from './helpers';
+
+describe('validate options', () => {
+ const tests = {
+ type: {
+ success: ['module', 'commonjs'],
+ failure: ['string', '', {}, []],
+ },
+ imports: {
+ success: [
+ 'lib_1',
+ 'globalObject1.foo',
+ ['globalObject1'],
+ ['globalObject1.foo'],
+ {
+ moduleName: 'jQuery',
+ name: '$',
+ },
+ {
+ syntax: 'named',
+ moduleName: 'jQuery',
+ name: 'lib',
+ alias: 'lib_alias',
+ },
+ {
+ syntax: 'default',
+ moduleName: 'jQuery',
+ name: 'lib',
+ },
+ ],
+ failure: [
+ false,
+ true,
+ /test/,
+ '',
+ [],
+ [''],
+ {},
+ {
+ type: 'string',
+ moduleName: 'jQuery',
+ list: false,
+ },
+ {
+ syntax: 'default',
+ moduleName: 'jQuery',
+ name: 'lib',
+ alias: 'lib_alias',
+ },
+ ],
+ },
+ wrapper: {
+ success: ['window', ['window', 'document']],
+ failure: [false, true, [], ['']],
+ },
+ additionalCode: {
+ success: ['var x = 2;'],
+ failure: [false, true, /test/, [], [''], {}],
+ },
+ unknown: {
+ success: [],
+ failure: [1, true, false, 'test', /test/, [], {}, { foo: 'bar' }],
+ },
+ };
+
+ function stringifyValue(value) {
+ if (
+ Array.isArray(value) ||
+ (value && typeof value === 'object' && value.constructor === Object)
+ ) {
+ return JSON.stringify(value);
+ }
+
+ return value;
+ }
+
+ async function createTestCase(key, value, type) {
+ it(`should ${
+ type === 'success' ? 'successfully validate' : 'throw an error on'
+ } the "${key}" option with "${stringifyValue(value)}" value`, async () => {
+ let compiler;
+
+ if (key === 'type') {
+ compiler = getCompiler('some-library.js', {
+ [key]: value,
+ wrapper: 'window',
+ });
+ } else {
+ compiler = getCompiler('some-library.js', {
+ [key]: value,
+ });
+ }
+
+ let stats;
+
+ try {
+ stats = await compile(compiler);
+ } finally {
+ if (type === 'success') {
+ const validationErrors = [];
+
+ stats.compilation.errors.forEach((error) => {
+ if (error.message.indexOf('ValidationError') !== -1) {
+ validationErrors.push(error);
+ }
+ });
+ expect(validationErrors.length).toBe(0);
+ } else if (type === 'failure') {
+ const {
+ compilation: { errors },
+ } = stats;
+
+ expect(errors).toHaveLength(1);
+ expect(() => {
+ throw new Error(errors[0].error.message);
+ }).toThrowErrorMatchingSnapshot();
+ }
+ }
+ });
+ }
+
+ for (const [key, values] of Object.entries(tests)) {
+ for (const type of Object.keys(values)) {
+ for (const value of values[type]) {
+ createTestCase(key, value, type);
+ }
+ }
+ }
+});