Skip to content

Commit

Permalink
fix: respect 'use strict' (#77)
Browse files Browse the repository at this point in the history
  • Loading branch information
evilebottnawi committed Jun 17, 2020
1 parent 9e2cec4 commit c7f8799
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 31 deletions.
6 changes: 4 additions & 2 deletions README.md
Expand Up @@ -486,6 +486,8 @@ import $ from 'jquery';
}.call(window, document));
```

> ⚠ Do not use this option if source code contains ES module import(s)
### additionalCode

Type: `String`
Expand All @@ -507,7 +509,7 @@ module.exports = {
moduleName: 'jquery',
name: '$',
},
additionalCode: 'var someVariable = 1;',
additionalCode: 'var define = false;',
},
},
],
Expand All @@ -522,7 +524,7 @@ Generate output:
```js
import $ from 'jquery';

var someVariable = 1;
var define = false;

// ...
// Code
Expand Down
5 changes: 5 additions & 0 deletions package-lock.json

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

3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -43,7 +43,8 @@
"dependencies": {
"loader-utils": "^2.0.0",
"schema-utils": "^2.7.0",
"source-map": "^0.6.1"
"source-map": "^0.6.1",
"strip-comments": "^2.0.1"
},
"devDependencies": {
"@babel/cli": "^7.10.1",
Expand Down
7 changes: 5 additions & 2 deletions src/index.js
Expand Up @@ -9,7 +9,7 @@ import validateOptions from 'schema-utils';

import schema from './options.json';

import { getImports, renderImports } from './utils';
import { getImports, renderImports, sourceHasUseStrict } from './utils';

const HEADER = '/*** IMPORTS FROM imports-loader ***/\n';

Expand Down Expand Up @@ -37,10 +37,13 @@ export default function loader(content, sourceMap) {
return;
}

// We don't need to remove 'use strict' manually, because `terser` do it
const directive = sourceHasUseStrict(content);

importsCode += Object.entries(imports).reduce(
(accumulator, item) =>
`${accumulator}${renderImports(this, type, item[0], item[1])}\n`,
''
directive ? "'use strict';\n" : ''
);
}

Expand Down
49 changes: 23 additions & 26 deletions src/utils.js
@@ -1,4 +1,17 @@
import { stringifyRequest } from 'loader-utils';
import strip from 'strip-comments';

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

function sourceHasUseStrict(source) {
const str = strip(source).trim();

return str.startsWith("'use strict'") || str.startsWith('"use strict"');
}

function resolveImports(type, item) {
const defaultSyntax = type === 'module' ? 'default' : 'single';
Expand Down Expand Up @@ -50,11 +63,7 @@ function resolveImports(type, item) {
throw new Error(
`The "${result.syntax}" syntax does not support "${
result.alias
}" alias in "${
typeof item === 'string'
? item
: `\n${JSON.stringify(item, null, ' ')}\n`
}" value`
}" alias in "${forError(item)}" value`
);
}

Expand All @@ -65,11 +74,7 @@ function resolveImports(type, item) {
throw new Error(
`The "${result.syntax}" syntax does not support "${
result.name
}" name in "${
typeof item === 'string'
? item
: `\n${JSON.stringify(item, null, ' ')}\n`
}" value`
}" name in "${forError(item)}" value`
);
}

Expand All @@ -78,11 +83,9 @@ function resolveImports(type, item) {
type === 'commonjs'
) {
throw new Error(
`The "${type}" type does not support the "${result.syntax}" syntax in "${
typeof item === 'string'
? item
: `\n${JSON.stringify(item, null, ' ')}\n`
}" value`
`The "${type}" type does not support the "${
result.syntax
}" syntax in "${forError(item)}" value`
);
}

Expand All @@ -93,11 +96,7 @@ function resolveImports(type, item) {
throw new Error(
`The "${type}" format does not support the "${
result.syntax
}" syntax in "${
typeof item === 'string'
? item
: `\n${JSON.stringify(item, null, ' ')}\n`
}" value`
}" syntax in "${forError(item)}" value`
);
}

Expand All @@ -106,11 +105,9 @@ function resolveImports(type, item) {
typeof result.name === 'undefined'
) {
throw new Error(
`The "${result.syntax}" syntax needs the "name" option in "${
typeof item === 'string'
? item
: `\n${JSON.stringify(item, null, ' ')}\n`
}" value`
`The "${result.syntax}" syntax needs the "name" option in "${forError(
item
)}" value`
);
}

Expand Down Expand Up @@ -315,4 +312,4 @@ function renderImports(loaderContext, type, moduleName, imports) {
return code;
}

export { getImports, renderImports };
export { sourceHasUseStrict, getImports, renderImports };
82 changes: 82 additions & 0 deletions test/__snapshots__/loader.test.js.snap
Expand Up @@ -649,6 +649,88 @@ var someCode = {

exports[`loader should work with "single" imports without syntax: warnings 1`] = `Array []`;

exports[`loader should work with "use-strict" not in program with CommonJS modules: errors 1`] = `Array []`;

exports[`loader should work with "use-strict" not in program with CommonJS modules: module 1`] = `
"/*** IMPORTS FROM imports-loader ***/
var lib_1 = require(\\"lib_1\\");
var myObject = { foo: 'bar' };
function test() {
'use strict';
return 'test';
}
"
`;

exports[`loader should work with "use-strict" not in program with CommonJS modules: warnings 1`] = `Array []`;

exports[`loader should work with "use-strict" not in program with ES modules: errors 1`] = `Array []`;

exports[`loader should work with "use-strict" not in program with ES modules: module 1`] = `
"/*** IMPORTS FROM imports-loader ***/
import lib_1 from \\"lib_1\\";
var myObject = { foo: 'bar' };
function test() {
'use strict';
return 'test';
}
"
`;

exports[`loader should work with "use-strict" not in program with ES modules: warnings 1`] = `Array []`;

exports[`loader should work with "use-strict" with CommonJS modules: errors 1`] = `Array []`;

exports[`loader should work with "use-strict" with CommonJS modules: module 1`] = `
"/*** IMPORTS FROM imports-loader ***/
'use strict';
var lib_1 = require(\\"lib_1\\");
/* Comment */
'use strict';
var myObject = { foo: 'bar' };
function test() {
'use strict';
return 'test';
}
"
`;

exports[`loader should work with "use-strict" with CommonJS modules: warnings 1`] = `Array []`;

exports[`loader should work with "use-strict" with ES modules: errors 1`] = `Array []`;

exports[`loader should work with "use-strict" with ES modules: module 1`] = `
"/*** IMPORTS FROM imports-loader ***/
'use strict';
import lib_1 from \\"lib_1\\";
/* Comment */
'use strict';
var myObject = { foo: 'bar' };
function test() {
'use strict';
return 'test';
}
"
`;

exports[`loader should work with "use-strict" with ES modules: warnings 1`] = `Array []`;

exports[`loader should work with a string syntax using CommonJS: errors 1`] = `Array []`;

exports[`loader should work with a string syntax using CommonJS: module 1`] = `
Expand Down
7 changes: 7 additions & 0 deletions test/fixtures/use-strict-in-function.js
@@ -0,0 +1,7 @@
var myObject = { foo: 'bar' };

function test() {
'use strict';

return 'test';
}
11 changes: 11 additions & 0 deletions test/fixtures/use-strict.js
@@ -0,0 +1,11 @@
/* Comment */

'use strict';

var myObject = { foo: 'bar' };

function test() {
'use strict';

return 'test';
}
50 changes: 50 additions & 0 deletions test/loader.test.js
Expand Up @@ -149,6 +149,56 @@ describe('loader', () => {
expect(getWarnings(stats)).toMatchSnapshot('warnings');
});

it('should work with "use-strict" with ES modules', async () => {
const compiler = getCompiler('use-strict.js', {
imports: 'lib_1',
});
const stats = await compile(compiler);

expect(getModuleSource('./use-strict.js', stats)).toMatchSnapshot('module');
expect(getErrors(stats)).toMatchSnapshot('errors');
expect(getWarnings(stats)).toMatchSnapshot('warnings');
});

it('should work with "use-strict" with CommonJS modules', async () => {
const compiler = getCompiler('use-strict.js', {
type: 'commonjs',
imports: 'lib_1',
});
const stats = await compile(compiler);

expect(getModuleSource('./use-strict.js', stats)).toMatchSnapshot('module');
expect(getErrors(stats)).toMatchSnapshot('errors');
expect(getWarnings(stats)).toMatchSnapshot('warnings');
});

it('should work with "use-strict" not in program with ES modules', async () => {
const compiler = getCompiler('use-strict-in-function.js', {
imports: 'lib_1',
});
const stats = await compile(compiler);

expect(
getModuleSource('./use-strict-in-function.js', stats)
).toMatchSnapshot('module');
expect(getErrors(stats)).toMatchSnapshot('errors');
expect(getWarnings(stats)).toMatchSnapshot('warnings');
});

it('should work with "use-strict" not in program with CommonJS modules', async () => {
const compiler = getCompiler('use-strict-in-function.js', {
type: 'commonjs',
imports: 'lib_1',
});
const stats = await compile(compiler);

expect(
getModuleSource('./use-strict-in-function.js', stats)
).toMatchSnapshot('module');
expect(getErrors(stats)).toMatchSnapshot('errors');
expect(getWarnings(stats)).toMatchSnapshot('warnings');
});

it('should work with "imports", "wrapper" and "additionalCode" options', async () => {
const compiler = getCompiler('some-library.js', {
imports: {
Expand Down

0 comments on commit c7f8799

Please sign in to comment.