Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: Add sourceType:commonjs support #520

Merged
merged 2 commits into from Nov 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -145,7 +145,7 @@ const options = {
// You can also set "latest" to use the most recently supported version.
ecmaVersion: 5,

// specify which type of script you're parsing ("script" or "module")
// specify which type of script you're parsing ("script", "module", or "commonjs")
sourceType: "script",

// specify additional language features
Expand All @@ -154,7 +154,7 @@ const options = {
// enable JSX parsing
jsx: false,

// enable return in global scope
// enable return in global scope (set to true automatically when sourceType is "commonjs")
globalReturn: false,

// enable implied strict mode (if ecmaVersion >= 5)
Expand Down
13 changes: 10 additions & 3 deletions lib/espree.js
Expand Up @@ -56,6 +56,8 @@ export default () => Parser => {
code = String(code);
}

// save original source type in case of commonjs
const originalSourceType = opts.sourceType;
const options = normalizeOptions(opts);
const ecmaFeatures = options.ecmaFeatures || {};
const tokenTranslator =
Expand All @@ -74,7 +76,7 @@ export default () => Parser => {
allowReserved: options.allowReserved,

// Truthy value is true for backward compatibility.
allowReturnOutsideFunction: Boolean(ecmaFeatures.globalReturn),
allowReturnOutsideFunction: options.allowReturnOutsideFunction,

// Collect tokens
onToken: token => {
Expand All @@ -98,8 +100,13 @@ export default () => Parser => {
}
}, code);

// Initialize internal state.
/*
* Data that is unique to Espree and is not represented internally in
* Acorn. We put all of this data into a symbol property as a way to
* avoid potential naming conflicts with future versions of Acorn.
*/
this[STATE] = {
originalSourceType: originalSourceType || options.sourceType,
tokens: tokenTranslator ? [] : null,
comments: options.comment === true ? [] : null,
impliedStrict: ecmaFeatures.impliedStrict === true && this.options.ecmaVersion >= 5,
Expand Down Expand Up @@ -144,7 +151,7 @@ export default () => Parser => {
const extra = this[STATE];
const program = super.parse();

program.sourceType = this.options.sourceType;
program.sourceType = extra.originalSourceType;

if (extra.comments) {
program.comments = extra.comments;
Expand Down
12 changes: 11 additions & 1 deletion lib/options.js
Expand Up @@ -73,6 +73,11 @@ function normalizeSourceType(sourceType = "script") {
if (sourceType === "script" || sourceType === "module") {
return sourceType;
}

if (sourceType === "commonjs") {
return "script";
}

throw new Error("Invalid sourceType.");
}

Expand All @@ -88,15 +93,20 @@ export function normalizeOptions(options) {
const ranges = options.range === true;
const locations = options.loc === true;
const allowReserved = ecmaVersion === 3 ? "never" : false;
const ecmaFeatures = options.ecmaFeatures || {};
const allowReturnOutsideFunction = options.sourceType === "commonjs" ||
Boolean(ecmaFeatures.globalReturn);

if (sourceType === "module" && ecmaVersion < 6) {
throw new Error("sourceType 'module' is not supported when ecmaVersion < 2015. Consider adding `{ ecmaVersion: 2015 }` to the parser options.");
}

return Object.assign({}, options, {
ecmaVersion,
sourceType,
ranges,
locations,
allowReserved
allowReserved,
allowReturnOutsideFunction
});
}
31 changes: 24 additions & 7 deletions tests/lib/parse.js
Expand Up @@ -41,15 +41,32 @@ describe("parse()", () => {

});

describe("modules", () => {
describe("sourceType", () => {

it("should have correct column number when strict mode error occurs", () => {
describe("module", () => {

try {
espree.parse("function fn(a, a) {\n}", { ecmaVersion: 6, sourceType: "module" });
} catch (err) {
assert.strictEqual(err.column, 16);
}
it("should have correct column number when strict mode error occurs", () => {

try {
espree.parse("function fn(a, a) {\n}", { ecmaVersion: 6, sourceType: "module" });
} catch (err) {
assert.strictEqual(err.column, 16);
}
});

});

describe("commonjs", () => {

it("should parse top-level return", () => {
espree.parse("return;", { sourceType: "commonjs" });
});

it("should have sourceType:commonjs on Program node", () => {
const result = espree.parse("return;", { sourceType: "commonjs" });

assert.strictEqual(result.sourceType, "commonjs");
});
});

});
Expand Down