Skip to content

Commit

Permalink
INCOMPLETE:
Browse files Browse the repository at this point in the history
0. depends on acorn and acorn-jsx being updated per PRs
    a. acornjs/acorn#1104 (merged but not yet released)
    b. acornjs/acorn#1105 (merged but not yet released)
    c. acornjs/acorn-jsx#130
1. Refactor to avoid `typedef` shortcuts when not desired for export
2. Avoid dummy class, so parse JavaScript with https://github.com/es-joy/jsdoc-eslint-parser

feat: Adds JSDoc-based TypeScript declaration file

Also:
1. chore: adds `editorconfig`
2. refactor: Removes unused esprima
3. refactor: changes to force EspreeParser constructor to convert `new String` to plain string (for typing)
4. refactor: switches to `Object.keys` to avoid `hasOwnProperty` and easier for typing
5. refactor: drops a use of `acorn.Parser.extend` for typing purposes
6. refactor: checks for existence of `tokens` in `tokenize` (as may be absent)
7. refactor: checks for existence of `firstNode.range` and `firstNode.loc`  in `parse` (as may be absent)
8. refactor: checks for existence of `extra.lastToken.range` and `extra.lastToken.loc` in `parse` (as may be absent)
7. feat: throws specific error if `jsx_readString` superclass undefined
8. refactor: checks for existence of `lastTemplateToken.loc` and `lastTemplateToken.range` in `token-translator.js` (as may be absent)
  • Loading branch information
brettz9 committed Mar 10, 2022
1 parent b578a66 commit 8b84e83
Show file tree
Hide file tree
Showing 8 changed files with 696 additions and 291 deletions.
15 changes: 15 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
; EditorConfig file: https://EditorConfig.org
; Install the "EditorConfig" plugin into your editor to use

root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true

[*.md]
indent_size = 2
92 changes: 77 additions & 15 deletions espree.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,50 @@
*/
/* eslint no-undefined:0, no-use-before-define: 0 */

/**
* @typedef {import('acorn')} acorn
* @typedef {typeof import('acorn-jsx').AcornJsxParser} AcornJsxParser
* @typedef {import('./lib/espree').EnhancedSyntaxError} EnhancedSyntaxError
* @typedef {typeof import('./lib/espree').EspreeParser} IEspreeParser
* @typedef {acorn.ecmaVersion} ecmaVersion
*/
/**
* `jsx.Options` gives us 2 optional properties, so extend it
*
* `allowReserved`, `ranges`, `locations`, `allowReturnOutsideFunction`,
* `onToken`, and `onComment` are as in `acorn.Options`
*
* `ecmaVersion` as in `acorn.Options` though optional
*
* `sourceType` as in `acorn.Options` but also allows `commonjs`
*
* `ecmaFeatures`, `range`, `loc`, `tokens` are not in `acorn.Options`
*
* `comment` is not in `acorn.Options` and doesn't err without it, but is used
* @typedef {{
* allowReserved?: boolean | "never",
* ranges?: boolean,
* locations?: boolean,
* allowReturnOutsideFunction?: boolean,
* onToken?: ((token: acorn.Token) => any) | acorn.Token[]
* onComment?: ((
* isBlock: boolean, text: string, start: number, end: number, startLoc?: acorn.Position,
* endLoc?: acorn.Position
* ) => void) | acorn.Comment[]
* ecmaVersion?: ecmaVersion,
* sourceType?: "script"|"module"|"commonjs",
* ecmaFeatures?: {
* jsx?: boolean,
* globalReturn?: boolean,
* impliedStrict?: boolean
* },
* range?: boolean,
* loc?: boolean,
* tokens?: boolean | null
* comment?: boolean,
* } & jsx.Options} ParserOptions
*/

import * as acorn from "acorn";
import jsx from "acorn-jsx";
import espree from "./lib/espree.js";
Expand All @@ -66,23 +110,43 @@ import { getLatestEcmaVersion, getSupportedEcmaVersions } from "./lib/options.js

// To initialize lazily.
const parsers = {
_regular: null,
_jsx: null,
_regular: /** @type {IEspreeParser|null} */ (null),
_jsx: /** @type {IEspreeParser|null} */ (null),

/**
* Returns regular Parser
* @returns {IEspreeParser} Regular Acorn parser
*/
get regular() {
if (this._regular === null) {
this._regular = acorn.Parser.extend(espree());
const espreeParserFactory = espree();

// Cast the `acorn.Parser` to our own for required properties not specified in *.d.ts
this._regular = espreeParserFactory(/** @type {AcornJsxParser} */ (acorn.Parser));
}
return this._regular;
},

/**
* Returns JSX Parser
* @returns {IEspreeParser} JSX Acorn parser
*/
get jsx() {
if (this._jsx === null) {
this._jsx = acorn.Parser.extend(jsx(), espree());
const espreeParserFactory = espree();
const jsxFactory = jsx();

// Cast the `acorn.Parser` to our own for required properties not specified in *.d.ts
this._jsx = espreeParserFactory(jsxFactory(acorn.Parser));
}
return this._jsx;
},

/**
* Returns Regular or JSX Parser
* @param {ParserOptions} options Parser options
* @returns {IEspreeParser} Regular or JSX Acorn parser
*/
get(options) {
const useJsx = Boolean(
options &&
Expand All @@ -101,9 +165,9 @@ const parsers = {
/**
* Tokenizes the given code.
* @param {string} code The code to tokenize.
* @param {Object} options Options defining how to tokenize.
* @returns {Token[]} An array of tokens.
* @throws {SyntaxError} If the input code is invalid.
* @param {ParserOptions} options Options defining how to tokenize.
* @returns {acorn.Token[]|null} An array of tokens.
* @throws {EnhancedSyntaxError} If the input code is invalid.
* @private
*/
export function tokenize(code, options) {
Expand All @@ -124,9 +188,9 @@ export function tokenize(code, options) {
/**
* Parses the given code.
* @param {string} code The code to tokenize.
* @param {Object} options Options defining how to tokenize.
* @returns {ASTNode} The "Program" AST node.
* @throws {SyntaxError} If the input code is invalid.
* @param {ParserOptions} options Options defining how to tokenize.
* @returns {acorn.Node} The "Program" AST node.
* @throws {EnhancedSyntaxError} If the input code is invalid.
*/
export function parse(code, options) {
const Parser = parsers.get(options);
Expand All @@ -148,17 +212,15 @@ export const VisitorKeys = (function() {
// Derive node types from VisitorKeys
/* istanbul ignore next */
export const Syntax = (function() {
let name,
let /** @type {Object<string,string>} */
types = {};

if (typeof Object.create === "function") {
types = Object.create(null);
}

for (name in VisitorKeys) {
if (Object.hasOwnProperty.call(VisitorKeys, name)) {
types[name] = name;
}
for (const name of Object.keys(VisitorKeys)) {
types[name] = name;
}

if (typeof Object.freeze === "function") {
Expand Down
Loading

0 comments on commit 8b84e83

Please sign in to comment.