5555 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5656 */
5757
58+ /**
59+ * @import { EnhancedSyntaxError } from "./lib/espree.js";
60+ * @import { EspreeParserCtor, EspreeParserJsxCtor } from "./lib/types.js";
61+ */
62+
63+ // ----------------------------------------------------------------------------
64+ // Types exported from file
65+ // ----------------------------------------------------------------------------
66+ /**
67+ * @typedef {3|5|6|7|8|9|10|11|12|13|14|15|16|17|2015|2016|2017|2018|2019|2020|2021|2022|2023|2024|2025|2026|'latest' } ecmaVersion
68+ */
69+
70+ /**
71+ * @typedef {import('./lib/token-translator.js').EsprimaToken } EspreeToken
72+ */
73+
74+ /**
75+ * @typedef {import('./lib/espree.js').EsprimaComment } EspreeComment
76+ */
77+
78+ /**
79+ * @typedef {{
80+ * comments?: EspreeComment[]
81+ * } & EspreeToken[] } EspreeTokens
82+ */
83+
84+ /**
85+ * `allowReserved` is as in `acorn.Options`
86+ *
87+ * `ecmaVersion` currently as in `acorn.Options` though optional
88+ *
89+ * `sourceType` as in `acorn.Options` but also allows `commonjs`
90+ *
91+ * `ecmaFeatures`, `range`, `loc`, `tokens` are not in `acorn.Options`
92+ *
93+ * `comment` is not in `acorn.Options` and doesn't err without it, but is used
94+ */
95+ /**
96+ * @typedef {{
97+ * allowReserved?: boolean,
98+ * ecmaVersion?: ecmaVersion,
99+ * sourceType?: "script"|"module"|"commonjs",
100+ * ecmaFeatures?: {
101+ * jsx?: boolean,
102+ * globalReturn?: boolean,
103+ * impliedStrict?: boolean
104+ * },
105+ * range?: boolean,
106+ * loc?: boolean,
107+ * tokens?: boolean,
108+ * comment?: boolean,
109+ * }} ParserOptions
110+ */
58111
59112import * as acorn from "acorn" ;
60113import jsx from "acorn-jsx" ;
@@ -66,23 +119,66 @@ import { getLatestEcmaVersion, getSupportedEcmaVersions } from "./lib/options.js
66119
67120// To initialize lazily.
68121const parsers = {
122+
123+ /** @type {EspreeParserCtor|null } */
69124 _regular : null ,
125+
126+ /** @type {EspreeParserJsxCtor|null } */
70127 _jsx : null ,
71128
129+ /**
130+ * Returns regular Parser
131+ * @returns {EspreeParserCtor } Regular Acorn parser
132+ */
72133 get regular ( ) {
73134 if ( this . _regular === null ) {
74- this . _regular = acorn . Parser . extend ( espree ( ) ) ;
135+ const espreeParserFactory = /** @type {unknown } */ ( espree ( ) ) ;
136+
137+ this . _regular = /** @type {EspreeParserCtor } */ (
138+ // Without conversion, types are incompatible, as
139+ // acorn's has a protected constructor
140+ /** @type {unknown } */
141+ ( acorn . Parser . extend (
142+ /**
143+ * @type {(
144+ * BaseParser: typeof acorn.Parser
145+ * ) => typeof acorn.Parser}
146+ */ ( espreeParserFactory )
147+ ) )
148+ ) ;
75149 }
76150 return this . _regular ;
77151 } ,
78152
153+ /**
154+ * Returns JSX Parser
155+ * @returns {EspreeParserJsxCtor } JSX Acorn parser
156+ */
79157 get jsx ( ) {
80158 if ( this . _jsx === null ) {
81- this . _jsx = acorn . Parser . extend ( jsx ( ) , espree ( ) ) ;
159+ const espreeParserFactory = /** @type {unknown } */ ( espree ( ) ) ;
160+ const jsxFactory = jsx ( ) ;
161+
162+ this . _jsx = /** @type {EspreeParserJsxCtor } */ (
163+ // Without conversion, types are incompatible, as
164+ // acorn's has a protected constructor
165+ /** @type {unknown } */
166+ ( acorn . Parser . extend (
167+ jsxFactory ,
168+
169+ /** @type {(BaseParser: typeof acorn.Parser) => typeof acorn.Parser } */
170+ ( espreeParserFactory )
171+ ) )
172+ ) ;
82173 }
83174 return this . _jsx ;
84175 } ,
85176
177+ /**
178+ * Gets the parser object based on the supplied options.
179+ * @param {ParserOptions } options The parser options.
180+ * @returns {EspreeParserJsxCtor|EspreeParserCtor } Regular or JSX Acorn parser
181+ */
86182 get ( options ) {
87183 const useJsx = Boolean (
88184 options &&
@@ -101,9 +197,9 @@ const parsers = {
101197/**
102198 * Tokenizes the given code.
103199 * @param {string } code The code to tokenize.
104- * @param {Object } options Options defining how to tokenize.
105- * @returns {Token[] } An array of tokens.
106- * @throws {SyntaxError } If the input code is invalid.
200+ * @param {ParserOptions } options Options defining how to tokenize.
201+ * @returns {EspreeTokens } An array of tokens.
202+ * @throws {EnhancedSyntaxError } If the input code is invalid.
107203 * @private
108204 */
109205export function tokenize ( code , options ) {
@@ -114,7 +210,7 @@ export function tokenize(code, options) {
114210 options = Object . assign ( { } , options , { tokens : true } ) ; // eslint-disable-line no-param-reassign -- stylistic choice
115211 }
116212
117- return new Parser ( options , code ) . tokenize ( ) ;
213+ return /** @type { EspreeTokens } */ ( new Parser ( options , code ) . tokenize ( ) ) ;
118214}
119215
120216//------------------------------------------------------------------------------
@@ -124,9 +220,9 @@ export function tokenize(code, options) {
124220/**
125221 * Parses the given code.
126222 * @param {string } code The code to tokenize.
127- * @param {Object } options Options defining how to tokenize.
128- * @returns {ASTNode } The "Program" AST node.
129- * @throws {SyntaxError } If the input code is invalid.
223+ * @param {ParserOptions } options Options defining how to tokenize.
224+ * @returns {acorn.Node } The "Program" AST node.
225+ * @throws {EnhancedSyntaxError } If the input code is invalid.
130226 */
131227export function parse ( code , options ) {
132228 const Parser = parsers . get ( options ) ;
@@ -150,6 +246,8 @@ export const VisitorKeys = (function() {
150246/* istanbul ignore next */
151247export const Syntax = ( function ( ) {
152248 let key ,
249+
250+ /** @type {Record<string,string> } */
153251 types = { } ;
154252
155253 if ( typeof Object . create === "function" ) {
0 commit comments