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

Update: add latestEcmaVersion & supportedEcmaVersions #430

Merged
merged 3 commits into from
Feb 19, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions espree.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const acorn = require("acorn");
const jsx = require("acorn-jsx");
const astNodeTypes = require("./lib/ast-node-types");
const espree = require("./lib/espree");
const { latestEcmaVersion, supportedEcmaVersions } = require("./lib/options");

// To initialize lazily.
const parsers = {
Expand Down Expand Up @@ -170,3 +171,7 @@ exports.Syntax = (function() {
exports.VisitorKeys = (function() {
return require("eslint-visitor-keys").KEYS;
}());

exports.latestEcmaVersion = latestEcmaVersion;

exports.supportedEcmaVersions = supportedEcmaVersions;
68 changes: 1 addition & 67 deletions lib/espree.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,77 +2,11 @@

/* eslint-disable no-param-reassign*/
const TokenTranslator = require("./token-translator");
const { normalizeOptions } = require("./options");

const DEFAULT_ECMA_VERSION = 5;
const STATE = Symbol("espree's internal state");
const ESPRIMA_FINISH_NODE = Symbol("espree's esprimaFinishNode");

/**
* Normalize ECMAScript version from the initial config
* @param {number} ecmaVersion ECMAScript version from the initial config
* @throws {Error} throws an error if the ecmaVersion is invalid.
* @returns {number} normalized ECMAScript version
*/
function normalizeEcmaVersion(ecmaVersion = DEFAULT_ECMA_VERSION) {
if (typeof ecmaVersion !== "number") {
throw new Error(`ecmaVersion must be a number. Received value of type ${typeof ecmaVersion} instead.`);
}

let version = ecmaVersion;

// Calculate ECMAScript edition number from official year version starting with
// ES2015, which corresponds with ES6 (or a difference of 2009).
if (version >= 2015) {
version -= 2009;
}

switch (version) {
case 3:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
return version;

// no default
}

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

/**
* Normalize sourceType from the initial config
* @param {string} sourceType to normalize
* @throws {Error} throw an error if sourceType is invalid
* @returns {string} normalized sourceType
*/
function normalizeSourceType(sourceType = "script") {
if (sourceType === "script" || sourceType === "module") {
return sourceType;
}
throw new Error("Invalid sourceType.");
}

/**
* Normalize parserOptions
* @param {Object} options the parser options to normalize
* @throws {Error} throw an error if found invalid option.
* @returns {Object} normalized options
*/
function normalizeOptions(options) {
const ecmaVersion = normalizeEcmaVersion(options.ecmaVersion);
const sourceType = normalizeSourceType(options.sourceType);
const ranges = options.range === true;
const locations = options.loc === true;

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 });
}

/**
* Converts an Acorn comment to a Esprima comment.
Expand Down
105 changes: 105 additions & 0 deletions lib/options.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/**
* @fileoverview A collection of methods for processing Espree's options.
* @author Kai Cataldo
*/

"use strict";

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------

const DEFAULT_ECMA_VERSION = 5;
const SUPPORTED_VERSIONS = [
3,
5,
6,
7,
8,
9,
10,
11
];

/**
* Normalize ECMAScript version from the initial config
* @param {number} ecmaVersion ECMAScript version from the initial config
* @throws {Error} throws an error if the ecmaVersion is invalid.
* @returns {number} normalized ECMAScript version
*/
function normalizeEcmaVersion(ecmaVersion = DEFAULT_ECMA_VERSION) {
if (typeof ecmaVersion !== "number") {
throw new Error(`ecmaVersion must be a number. Received value of type ${typeof ecmaVersion} instead.`);
}

let version = ecmaVersion;

// Calculate ECMAScript edition number from official year version starting with
// ES2015, which corresponds with ES6 (or a difference of 2009).
if (version >= 2015) {
version -= 2009;
}

if (!SUPPORTED_VERSIONS.includes(version)) {
throw new Error("Invalid ecmaVersion.");
}

return version;
}

/**
* Normalize sourceType from the initial config
* @param {string} sourceType to normalize
* @throws {Error} throw an error if sourceType is invalid
* @returns {string} normalized sourceType
*/
function normalizeSourceType(sourceType = "script") {
if (sourceType === "script" || sourceType === "module") {
return sourceType;
}
throw new Error("Invalid sourceType.");
}

/**
* Normalize parserOptions
* @param {Object} options the parser options to normalize
* @throws {Error} throw an error if found invalid option.
* @returns {Object} normalized options
*/
function normalizeOptions(options) {
const ecmaVersion = normalizeEcmaVersion(options.ecmaVersion);
const sourceType = normalizeSourceType(options.sourceType);
const ranges = options.range === true;
const locations = options.loc === true;

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 });
}

/**
* Get the latest ECMAScript version supported by Espree.
* @returns {number} The latest ECMAScript version.
*/
function latestEcmaVersion() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’d suggest calling this getLatestEcmaVersion to indicate a value is being retrieved (verb as opposed to noun).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call! I was initially thinking of it being more of a static property (like version), but that makes more sense with this iteration 👍

return Math.max(...SUPPORTED_VERSIONS);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can avoid a calculation here by using SUPPORTED_VERSIONS[SUPPORTED_VERSIONS.length - 1]

}

/**
* Get the list of ECMAScript versions supported by Espree.
* @returns {number[]} An array containing the supported ECMAScript versions.
*/
function supportedEcmaVersions() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, getSupportedEcmaVersions.

return [...SUPPORTED_VERSIONS];
}

//------------------------------------------------------------------------------
// Public
//------------------------------------------------------------------------------

module.exports = {
normalizeOptions,
latestEcmaVersion,
supportedEcmaVersions
};
40 changes: 40 additions & 0 deletions tests/lib/supported-ecmaversions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* @fileoverview Tests for latestEcmaVersion() & supportedEcmaVersions().
* @author Kai Cataldo
*/

"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

const assert = require("assert"),
espree = require("../../espree");

//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------

describe("latestEcmaVersion()", () => {
it("should return the latest supported ecmaVersion", () => {
assert.strictEqual(espree.latestEcmaVersion(), 11);
});
});

describe("supportedEcmaVersions()", () => {
it("should return an array of all supported versions", () => {
assert.deepStrictEqual(
espree.supportedEcmaVersions(),
[3, 5, 6, 7, 8, 9, 10, 11]
);
});

it("the array of supported versions should not be mutable by reference", () => {
const supportedVersions = espree.supportedEcmaVersions();
const originalValue = [...supportedVersions];

supportedVersions.push("a", "b", "c");
assert.deepStrictEqual(espree.supportedEcmaVersions(), originalValue);
});
});