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: Programmatic building of type-checkable JS and declaration files #544

Closed
wants to merge 24 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
784bfb0
feat: Programmatic building of type-checkable JS and declaration files
brettz9 Apr 21, 2022
fbe13b3
refactor: fix type
brettz9 Apr 26, 2022
403c952
refactor: drop undesired types
brettz9 Apr 26, 2022
5b86bcc
refactor: simplify since method is not returning a value
brettz9 Apr 28, 2022
4309e52
refactor: move out tool to own repo and utilize
brettz9 Apr 28, 2022
deae6c6
refactor: export to single declaration file
brettz9 Apr 21, 2022
0f1e2a1
docs: add file header
brettz9 May 4, 2022
2376f8a
refactor: convert number to `int` type
brettz9 May 4, 2022
41e0dd0
refactor: revert change to use `outFile`; cannot be used with ESM
brettz9 May 4, 2022
855af29
refactor: move notes on types out of typedef blocks
brettz9 May 5, 2022
b4e7aa7
docs: switch to interface expectation for `AcornJsxParser` per change…
brettz9 May 9, 2022
894537f
fix: `tokens` not allowed as `null`
brettz9 May 9, 2022
9b0348c
refactor: resume using `acorn.Parser.extend`
brettz9 May 10, 2022
616deb4
refactor: point to own `ecmaVersion` independent of Acorn
brettz9 May 10, 2022
968d5d9
docs: avoid return type of `null` for tokenize
brettz9 May 10, 2022
4680aec
docs: indicate return of EspreeTokens from `tokenize`
brettz9 May 11, 2022
6f9cdad
docs: simplify types and remove unneeded type casts
brettz9 May 11, 2022
5e4ccb9
docs: add more descriprtive comments
brettz9 May 12, 2022
9b80802
refactor: update per current acorn-jsx PR update
brettz9 May 12, 2022
ce0bf22
ensure type files are all included
brettz9 May 12, 2022
90e11f5
refactor: remove committed dist files (dist is already gitignored)
brettz9 May 12, 2022
5d69eef
refactor: add `allowSyntheticDefaultImports: true` per latest acorn-j…
brettz9 May 12, 2022
84cc0ed
refactor: update types per latest acorn-jsx PR; remove unused local t…
brettz9 May 15, 2022
86f5690
chore: update devDeps.
brettz9 May 19, 2022
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
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
/tests/fixtures
/dist
tools/create-test-example.js
tmp
9 changes: 7 additions & 2 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module.exports = {
}
},
parserOptions: {
ecmaVersion: 2020,
ecmaVersion: 2022,
sourceType: "module"
},
overrides: [
Expand All @@ -34,5 +34,10 @@ module.exports = {
"no-console": "off"
}
}
]
],
rules: {
"jsdoc/check-tag-names": ["error", {
definedTags: ["local", "export"]
}]
}
};
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ _test.js
.eslint-release-info.json
yarn.lock
package-lock.json
tmp
123 changes: 107 additions & 16 deletions espree.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,68 @@
*/
/* eslint no-undefined:0, no-use-before-define: 0 */

// ----------------------------------------------------------------------------
// Types exported from file
// ----------------------------------------------------------------------------
/**
* @typedef {3|5|6|7|8|9|10|11|12|13|2015|2016|2017|2018|2019|2020|2021|2022|'latest'} ecmaVersion
*/

/**
* @typedef {import('./lib/token-translator').EsprimaToken} EspreeToken
*/

/**
* @typedef {import('./lib/espree').EsprimaComment} EspreeComment
*/

/**
* @typedef {{
* comments?: EspreeComment[]
* } & EspreeToken[]} EspreeTokens
*/

/**
* `jsx.Options` gives us 2 optional properties, so extend it
*
* `allowReserved`, `ranges`, `locations`, `allowReturnOutsideFunction`,
* `onToken`, and `onComment` are as in `acorn.Options`
*
* `ecmaVersion` currently 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,
* ecmaVersion?: ecmaVersion,
* sourceType?: "script"|"module"|"commonjs",
* ecmaFeatures?: {
* jsx?: boolean,
* globalReturn?: boolean,
* impliedStrict?: boolean
* },
* range?: boolean,
* loc?: boolean,
* tokens?: boolean,
* comment?: boolean,
* }} ParserOptions
*/

// ----------------------------------------------------------------------------
// Local type imports
// ----------------------------------------------------------------------------
/**
* @local
* @typedef {import('acorn')} acorn
* @typedef {import('./lib/espree').EnhancedSyntaxError} EnhancedSyntaxError
* @typedef {typeof import('./lib/espree').EspreeParser} IEspreeParser
*/

import * as acorn from "acorn";
import jsx from "acorn-jsx";
import espree from "./lib/espree.js";
Expand All @@ -66,23 +128,54 @@ 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 = /** @type {unknown} */ (espree());

this._regular = /** @type {IEspreeParser} */ (
acorn.Parser.extend(

/** @type {(BaseParser: typeof acorn.Parser) => typeof acorn.Parser} */
(espreeParserFactory)
)
);
}
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 = /** @type {unknown} */ (espree());
const jsxFactory = jsx();

this._jsx = /** @type {IEspreeParser} */ (
acorn.Parser.extend(
jsxFactory,

/** @type {(BaseParser: typeof acorn.Parser) => typeof acorn.Parser} */
(espreeParserFactory)
)
);
}
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 +194,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 {EspreeTokens} An array of tokens.
* @throws {EnhancedSyntaxError} If the input code is invalid.
* @private
*/
export function tokenize(code, options) {
Expand All @@ -114,7 +207,7 @@ export function tokenize(code, options) {
options = Object.assign({}, options, { tokens: true }); // eslint-disable-line no-param-reassign
}

return new Parser(options, code).tokenize();
return /** @type {EspreeTokens} */ (new Parser(options, code).tokenize());
}

//------------------------------------------------------------------------------
Expand All @@ -124,9 +217,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 +241,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