update
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
# @babel/core
|
||||
|
||||
> Babel compiler core.
|
||||
|
||||
See our website [@babel/core](https://babeljs.io/docs/babel-core) for more information or the [issues](https://github.com/babel/babel/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22pkg%3A%20core%22+is%3Aopen) associated with this package.
|
||||
|
||||
## Install
|
||||
|
||||
Using npm:
|
||||
|
||||
```sh
|
||||
npm install --save-dev @babel/core
|
||||
```
|
||||
|
||||
or using yarn:
|
||||
|
||||
```sh
|
||||
yarn add @babel/core --dev
|
||||
```
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,12 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.setupKeyword }}
|
||||
{{# def.$data }}
|
||||
|
||||
{{# def.numberKeyword }}
|
||||
|
||||
{{ var $op = $keyword == 'maxProperties' ? '>' : '<'; }}
|
||||
if ({{# def.$dataNotType:'number' }} Object.keys({{=$data}}).length {{=$op}} {{=$schemaValue}}) {
|
||||
{{ var $errorKeyword = $keyword; }}
|
||||
{{# def.error:'_limitProperties' }}
|
||||
} {{? $breakOnError }} else { {{?}}
|
||||
@@ -0,0 +1,252 @@
|
||||
"use strict";
|
||||
'use client';
|
||||
var __rest = (this && this.__rest) || function (s, e) {
|
||||
var t = {};
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
||||
t[p] = s[p];
|
||||
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
||||
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
||||
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
||||
t[p[i]] = s[p[i]];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.default = Page;
|
||||
const jsx_runtime_1 = require("react/jsx-runtime");
|
||||
const react_1 = require("react");
|
||||
const make_cancellable_promise_1 = __importDefault(require("make-cancellable-promise"));
|
||||
const make_event_props_1 = __importDefault(require("make-event-props"));
|
||||
const clsx_1 = __importDefault(require("clsx"));
|
||||
const merge_refs_1 = __importDefault(require("merge-refs"));
|
||||
const tiny_invariant_1 = __importDefault(require("tiny-invariant"));
|
||||
const warning_1 = __importDefault(require("warning"));
|
||||
const PageContext_js_1 = __importDefault(require("./PageContext.js"));
|
||||
const Message_js_1 = __importDefault(require("./Message.js"));
|
||||
const Canvas_js_1 = __importDefault(require("./Page/Canvas.js"));
|
||||
const TextLayer_js_1 = __importDefault(require("./Page/TextLayer.js"));
|
||||
const AnnotationLayer_js_1 = __importDefault(require("./Page/AnnotationLayer.js"));
|
||||
const utils_js_1 = require("./shared/utils.js");
|
||||
const useDocumentContext_js_1 = __importDefault(require("./shared/hooks/useDocumentContext.js"));
|
||||
const useResolver_js_1 = __importDefault(require("./shared/hooks/useResolver.js"));
|
||||
const defaultScale = 1;
|
||||
/**
|
||||
* Displays a page.
|
||||
*
|
||||
* Should be placed inside `<Document />`. Alternatively, it can have `pdf` prop passed, which can be obtained from `<Document />`'s `onLoadSuccess` callback function, however some advanced functions like linking between pages inside a document may not be working correctly.
|
||||
*/
|
||||
function Page(props) {
|
||||
const documentContext = (0, useDocumentContext_js_1.default)();
|
||||
const mergedProps = Object.assign(Object.assign({}, documentContext), props);
|
||||
const { _className = 'react-pdf__Page', _enableRegisterUnregisterPage = true, canvasBackground, canvasRef, children, className, customRenderer: CustomRenderer, customTextRenderer, devicePixelRatio, error = 'Failed to load the page.', height, inputRef, loading = 'Loading page…', noData = 'No page specified.', onGetAnnotationsError: onGetAnnotationsErrorProps, onGetAnnotationsSuccess: onGetAnnotationsSuccessProps, onGetStructTreeError: onGetStructTreeErrorProps, onGetStructTreeSuccess: onGetStructTreeSuccessProps, onGetTextError: onGetTextErrorProps, onGetTextSuccess: onGetTextSuccessProps, onLoadError: onLoadErrorProps, onLoadSuccess: onLoadSuccessProps, onRenderAnnotationLayerError: onRenderAnnotationLayerErrorProps, onRenderAnnotationLayerSuccess: onRenderAnnotationLayerSuccessProps, onRenderError: onRenderErrorProps, onRenderSuccess: onRenderSuccessProps, onRenderTextLayerError: onRenderTextLayerErrorProps, onRenderTextLayerSuccess: onRenderTextLayerSuccessProps, pageIndex: pageIndexProps, pageNumber: pageNumberProps, pdf, registerPage, renderAnnotationLayer: renderAnnotationLayerProps = true, renderForms = false, renderMode = 'canvas', renderTextLayer: renderTextLayerProps = true, rotate: rotateProps, scale: scaleProps = defaultScale, unregisterPage, width } = mergedProps, otherProps = __rest(mergedProps, ["_className", "_enableRegisterUnregisterPage", "canvasBackground", "canvasRef", "children", "className", "customRenderer", "customTextRenderer", "devicePixelRatio", "error", "height", "inputRef", "loading", "noData", "onGetAnnotationsError", "onGetAnnotationsSuccess", "onGetStructTreeError", "onGetStructTreeSuccess", "onGetTextError", "onGetTextSuccess", "onLoadError", "onLoadSuccess", "onRenderAnnotationLayerError", "onRenderAnnotationLayerSuccess", "onRenderError", "onRenderSuccess", "onRenderTextLayerError", "onRenderTextLayerSuccess", "pageIndex", "pageNumber", "pdf", "registerPage", "renderAnnotationLayer", "renderForms", "renderMode", "renderTextLayer", "rotate", "scale", "unregisterPage", "width"]);
|
||||
const [pageState, pageDispatch] = (0, useResolver_js_1.default)();
|
||||
const { value: page, error: pageError } = pageState;
|
||||
const pageElement = (0, react_1.useRef)(null);
|
||||
(0, tiny_invariant_1.default)(pdf, 'Attempted to load a page, but no document was specified. Wrap <Page /> in a <Document /> or pass explicit `pdf` prop.');
|
||||
const pageIndex = (0, utils_js_1.isProvided)(pageNumberProps) ? pageNumberProps - 1 : (pageIndexProps !== null && pageIndexProps !== void 0 ? pageIndexProps : null);
|
||||
const pageNumber = pageNumberProps !== null && pageNumberProps !== void 0 ? pageNumberProps : ((0, utils_js_1.isProvided)(pageIndexProps) ? pageIndexProps + 1 : null);
|
||||
const rotate = rotateProps !== null && rotateProps !== void 0 ? rotateProps : (page ? page.rotate : null);
|
||||
const scale = (0, react_1.useMemo)(() => {
|
||||
if (!page) {
|
||||
return null;
|
||||
}
|
||||
// Be default, we'll render page at 100% * scale width.
|
||||
let pageScale = 1;
|
||||
// Passing scale explicitly null would cause the page not to render
|
||||
const scaleWithDefault = scaleProps !== null && scaleProps !== void 0 ? scaleProps : defaultScale;
|
||||
// If width/height is defined, calculate the scale of the page so it could be of desired width.
|
||||
if (width || height) {
|
||||
const viewport = page.getViewport({ scale: 1, rotation: rotate });
|
||||
if (width) {
|
||||
pageScale = width / viewport.width;
|
||||
}
|
||||
else if (height) {
|
||||
pageScale = height / viewport.height;
|
||||
}
|
||||
}
|
||||
return scaleWithDefault * pageScale;
|
||||
}, [height, page, rotate, scaleProps, width]);
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: useEffect intentionally triggered on pdf change
|
||||
(0, react_1.useEffect)(function hook() {
|
||||
return () => {
|
||||
if (!(0, utils_js_1.isProvided)(pageIndex)) {
|
||||
// Impossible, but TypeScript doesn't know that
|
||||
return;
|
||||
}
|
||||
if (_enableRegisterUnregisterPage && unregisterPage) {
|
||||
unregisterPage(pageIndex);
|
||||
}
|
||||
};
|
||||
}, [_enableRegisterUnregisterPage, pdf, pageIndex, unregisterPage]);
|
||||
/**
|
||||
* Called when a page is loaded successfully
|
||||
*/
|
||||
function onLoadSuccess() {
|
||||
if (onLoadSuccessProps) {
|
||||
if (!page || !scale) {
|
||||
// Impossible, but TypeScript doesn't know that
|
||||
return;
|
||||
}
|
||||
onLoadSuccessProps((0, utils_js_1.makePageCallback)(page, scale));
|
||||
}
|
||||
if (_enableRegisterUnregisterPage && registerPage) {
|
||||
if (!(0, utils_js_1.isProvided)(pageIndex) || !pageElement.current) {
|
||||
// Impossible, but TypeScript doesn't know that
|
||||
return;
|
||||
}
|
||||
registerPage(pageIndex, pageElement.current);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Called when a page failed to load
|
||||
*/
|
||||
function onLoadError() {
|
||||
if (!pageError) {
|
||||
// Impossible, but TypeScript doesn't know that
|
||||
return;
|
||||
}
|
||||
(0, warning_1.default)(false, pageError.toString());
|
||||
if (onLoadErrorProps) {
|
||||
onLoadErrorProps(pageError);
|
||||
}
|
||||
}
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: useEffect intentionally triggered on pdf and pageIndex change
|
||||
(0, react_1.useEffect)(function resetPage() {
|
||||
pageDispatch({ type: 'RESET' });
|
||||
}, [pageDispatch, pdf, pageIndex]);
|
||||
(0, react_1.useEffect)(function loadPage() {
|
||||
if (!pdf || !pageNumber) {
|
||||
return;
|
||||
}
|
||||
const cancellable = (0, make_cancellable_promise_1.default)(pdf.getPage(pageNumber));
|
||||
const runningTask = cancellable;
|
||||
cancellable.promise
|
||||
.then((nextPage) => {
|
||||
pageDispatch({ type: 'RESOLVE', value: nextPage });
|
||||
})
|
||||
.catch((error) => {
|
||||
pageDispatch({ type: 'REJECT', error });
|
||||
});
|
||||
return () => (0, utils_js_1.cancelRunningTask)(runningTask);
|
||||
}, [pageDispatch, pdf, pageNumber]);
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: Ommitted callbacks so they are not called every time they change
|
||||
(0, react_1.useEffect)(() => {
|
||||
if (page === undefined) {
|
||||
return;
|
||||
}
|
||||
if (page === false) {
|
||||
onLoadError();
|
||||
return;
|
||||
}
|
||||
onLoadSuccess();
|
||||
}, [page, scale]);
|
||||
const childContext = (0, react_1.useMemo)(() =>
|
||||
// Technically there cannot be page without pageIndex, pageNumber, rotate and scale, but TypeScript doesn't know that
|
||||
page && (0, utils_js_1.isProvided)(pageIndex) && pageNumber && (0, utils_js_1.isProvided)(rotate) && (0, utils_js_1.isProvided)(scale)
|
||||
? {
|
||||
_className,
|
||||
canvasBackground,
|
||||
customTextRenderer,
|
||||
devicePixelRatio,
|
||||
onGetAnnotationsError: onGetAnnotationsErrorProps,
|
||||
onGetAnnotationsSuccess: onGetAnnotationsSuccessProps,
|
||||
onGetStructTreeError: onGetStructTreeErrorProps,
|
||||
onGetStructTreeSuccess: onGetStructTreeSuccessProps,
|
||||
onGetTextError: onGetTextErrorProps,
|
||||
onGetTextSuccess: onGetTextSuccessProps,
|
||||
onRenderAnnotationLayerError: onRenderAnnotationLayerErrorProps,
|
||||
onRenderAnnotationLayerSuccess: onRenderAnnotationLayerSuccessProps,
|
||||
onRenderError: onRenderErrorProps,
|
||||
onRenderSuccess: onRenderSuccessProps,
|
||||
onRenderTextLayerError: onRenderTextLayerErrorProps,
|
||||
onRenderTextLayerSuccess: onRenderTextLayerSuccessProps,
|
||||
page,
|
||||
pageIndex,
|
||||
pageNumber,
|
||||
renderForms,
|
||||
renderTextLayer: renderTextLayerProps,
|
||||
rotate,
|
||||
scale,
|
||||
}
|
||||
: null, [
|
||||
_className,
|
||||
canvasBackground,
|
||||
customTextRenderer,
|
||||
devicePixelRatio,
|
||||
onGetAnnotationsErrorProps,
|
||||
onGetAnnotationsSuccessProps,
|
||||
onGetStructTreeErrorProps,
|
||||
onGetStructTreeSuccessProps,
|
||||
onGetTextErrorProps,
|
||||
onGetTextSuccessProps,
|
||||
onRenderAnnotationLayerErrorProps,
|
||||
onRenderAnnotationLayerSuccessProps,
|
||||
onRenderErrorProps,
|
||||
onRenderSuccessProps,
|
||||
onRenderTextLayerErrorProps,
|
||||
onRenderTextLayerSuccessProps,
|
||||
page,
|
||||
pageIndex,
|
||||
pageNumber,
|
||||
renderForms,
|
||||
renderTextLayerProps,
|
||||
rotate,
|
||||
scale,
|
||||
]);
|
||||
const eventProps = (0, react_1.useMemo)(() => (0, make_event_props_1.default)(otherProps, () => page ? (scale ? (0, utils_js_1.makePageCallback)(page, scale) : undefined) : page),
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: FIXME
|
||||
[otherProps, page, scale]);
|
||||
const pageKey = `${pageIndex}@${scale}/${rotate}`;
|
||||
function renderMainLayer() {
|
||||
switch (renderMode) {
|
||||
case 'custom': {
|
||||
(0, tiny_invariant_1.default)(CustomRenderer, `renderMode was set to "custom", but no customRenderer was passed.`);
|
||||
return (0, jsx_runtime_1.jsx)(CustomRenderer, {}, `${pageKey}_custom`);
|
||||
}
|
||||
case 'none':
|
||||
return null;
|
||||
case 'canvas':
|
||||
default:
|
||||
return (0, jsx_runtime_1.jsx)(Canvas_js_1.default, { canvasRef: canvasRef }, `${pageKey}_canvas`);
|
||||
}
|
||||
}
|
||||
function renderTextLayer() {
|
||||
if (!renderTextLayerProps) {
|
||||
return null;
|
||||
}
|
||||
return (0, jsx_runtime_1.jsx)(TextLayer_js_1.default, {}, `${pageKey}_text`);
|
||||
}
|
||||
function renderAnnotationLayer() {
|
||||
if (!renderAnnotationLayerProps) {
|
||||
return null;
|
||||
}
|
||||
return (0, jsx_runtime_1.jsx)(AnnotationLayer_js_1.default, {}, `${pageKey}_annotations`);
|
||||
}
|
||||
function renderChildren() {
|
||||
return ((0, jsx_runtime_1.jsxs)(PageContext_js_1.default.Provider, { value: childContext, children: [renderMainLayer(), renderTextLayer(), renderAnnotationLayer(), children] }));
|
||||
}
|
||||
function renderContent() {
|
||||
if (!pageNumber) {
|
||||
return (0, jsx_runtime_1.jsx)(Message_js_1.default, { type: "no-data", children: typeof noData === 'function' ? noData() : noData });
|
||||
}
|
||||
if (pdf === null || page === undefined || page === null) {
|
||||
return ((0, jsx_runtime_1.jsx)(Message_js_1.default, { type: "loading", children: typeof loading === 'function' ? loading() : loading }));
|
||||
}
|
||||
if (pdf === false || page === false) {
|
||||
return (0, jsx_runtime_1.jsx)(Message_js_1.default, { type: "error", children: typeof error === 'function' ? error() : error });
|
||||
}
|
||||
return renderChildren();
|
||||
}
|
||||
return ((0, jsx_runtime_1.jsx)("div", Object.assign({ className: (0, clsx_1.default)(_className, className), "data-page-number": pageNumber,
|
||||
// Assertion is needed for React 18 compatibility
|
||||
ref: (0, merge_refs_1.default)(inputRef, pageElement), style: {
|
||||
['--scale-factor']: `${scale}`,
|
||||
backgroundColor: canvasBackground || 'white',
|
||||
position: 'relative',
|
||||
minWidth: 'min-content',
|
||||
minHeight: 'min-content',
|
||||
} }, eventProps, { children: renderContent() })));
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "commonjs"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/* eslint-disable no-console */
|
||||
'use strict'
|
||||
|
||||
let printed = {}
|
||||
|
||||
module.exports = function warnOnce(message) {
|
||||
if (printed[message]) return
|
||||
printed[message] = true
|
||||
|
||||
if (typeof console !== 'undefined' && console.warn) {
|
||||
console.warn(message)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
# type-check [](https://travis-ci.org/gkz/type-check)
|
||||
|
||||
<a name="type-check" />
|
||||
|
||||
`type-check` is a library which allows you to check the types of JavaScript values at runtime with a Haskell like type syntax. It is great for checking external input, for testing, or even for adding a bit of safety to your internal code. It is a major component of [levn](https://github.com/gkz/levn). MIT license. Version 0.4.0. Check out the [demo](http://gkz.github.io/type-check/).
|
||||
|
||||
For updates on `type-check`, [follow me on twitter](https://twitter.com/gkzahariev).
|
||||
|
||||
npm install type-check
|
||||
|
||||
## Quick Examples
|
||||
|
||||
```js
|
||||
// Basic types:
|
||||
var typeCheck = require('type-check').typeCheck;
|
||||
typeCheck('Number', 1); // true
|
||||
typeCheck('Number', 'str'); // false
|
||||
typeCheck('Error', new Error); // true
|
||||
typeCheck('Undefined', undefined); // true
|
||||
|
||||
// Comment
|
||||
typeCheck('count::Number', 1); // true
|
||||
|
||||
// One type OR another type:
|
||||
typeCheck('Number | String', 2); // true
|
||||
typeCheck('Number | String', 'str'); // true
|
||||
|
||||
// Wildcard, matches all types:
|
||||
typeCheck('*', 2) // true
|
||||
|
||||
// Array, all elements of a single type:
|
||||
typeCheck('[Number]', [1, 2, 3]); // true
|
||||
typeCheck('[Number]', [1, 'str', 3]); // false
|
||||
|
||||
// Tuples, or fixed length arrays with elements of different types:
|
||||
typeCheck('(String, Number)', ['str', 2]); // true
|
||||
typeCheck('(String, Number)', ['str']); // false
|
||||
typeCheck('(String, Number)', ['str', 2, 5]); // false
|
||||
|
||||
// Object properties:
|
||||
typeCheck('{x: Number, y: Boolean}', {x: 2, y: false}); // true
|
||||
typeCheck('{x: Number, y: Boolean}', {x: 2}); // false
|
||||
typeCheck('{x: Number, y: Maybe Boolean}', {x: 2}); // true
|
||||
typeCheck('{x: Number, y: Boolean}', {x: 2, y: false, z: 3}); // false
|
||||
typeCheck('{x: Number, y: Boolean, ...}', {x: 2, y: false, z: 3}); // true
|
||||
|
||||
// A particular type AND object properties:
|
||||
typeCheck('RegExp{source: String, ...}', /re/i); // true
|
||||
typeCheck('RegExp{source: String, ...}', {source: 're'}); // false
|
||||
|
||||
// Custom types:
|
||||
var opt = {customTypes:
|
||||
{Even: { typeOf: 'Number', validate: function(x) { return x % 2 === 0; }}}};
|
||||
typeCheck('Even', 2, opt); // true
|
||||
|
||||
// Nested:
|
||||
var type = '{a: (String, [Number], {y: Array, ...}), b: Error{message: String, ...}}'
|
||||
typeCheck(type, {a: ['hi', [1, 2, 3], {y: [1, 'ms']}], b: new Error('oh no')}); // true
|
||||
```
|
||||
|
||||
Check out the [type syntax format](#syntax) and [guide](#guide).
|
||||
|
||||
## Usage
|
||||
|
||||
`require('type-check');` returns an object that exposes four properties. `VERSION` is the current version of the library as a string. `typeCheck`, `parseType`, and `parsedTypeCheck` are functions.
|
||||
|
||||
```js
|
||||
// typeCheck(type, input, options);
|
||||
typeCheck('Number', 2); // true
|
||||
|
||||
// parseType(type);
|
||||
var parsedType = parseType('Number'); // object
|
||||
|
||||
// parsedTypeCheck(parsedType, input, options);
|
||||
parsedTypeCheck(parsedType, 2); // true
|
||||
```
|
||||
|
||||
### typeCheck(type, input, options)
|
||||
|
||||
`typeCheck` checks a JavaScript value `input` against `type` written in the [type format](#type-format) (and taking account the optional `options`) and returns whether the `input` matches the `type`.
|
||||
|
||||
##### arguments
|
||||
* type - `String` - the type written in the [type format](#type-format) which to check against
|
||||
* input - `*` - any JavaScript value, which is to be checked against the type
|
||||
* options - `Maybe Object` - an optional parameter specifying additional options, currently the only available option is specifying [custom types](#custom-types)
|
||||
|
||||
##### returns
|
||||
`Boolean` - whether the input matches the type
|
||||
|
||||
##### example
|
||||
```js
|
||||
typeCheck('Number', 2); // true
|
||||
```
|
||||
|
||||
### parseType(type)
|
||||
|
||||
`parseType` parses string `type` written in the [type format](#type-format) into an object representing the parsed type.
|
||||
|
||||
##### arguments
|
||||
* type - `String` - the type written in the [type format](#type-format) which to parse
|
||||
|
||||
##### returns
|
||||
`Object` - an object in the parsed type format representing the parsed type
|
||||
|
||||
##### example
|
||||
```js
|
||||
parseType('Number'); // [{type: 'Number'}]
|
||||
```
|
||||
### parsedTypeCheck(parsedType, input, options)
|
||||
|
||||
`parsedTypeCheck` checks a JavaScript value `input` against parsed `type` in the parsed type format (and taking account the optional `options`) and returns whether the `input` matches the `type`. Use this in conjunction with `parseType` if you are going to use a type more than once.
|
||||
|
||||
##### arguments
|
||||
* type - `Object` - the type in the parsed type format which to check against
|
||||
* input - `*` - any JavaScript value, which is to be checked against the type
|
||||
* options - `Maybe Object` - an optional parameter specifying additional options, currently the only available option is specifying [custom types](#custom-types)
|
||||
|
||||
##### returns
|
||||
`Boolean` - whether the input matches the type
|
||||
|
||||
##### example
|
||||
```js
|
||||
parsedTypeCheck([{type: 'Number'}], 2); // true
|
||||
var parsedType = parseType('String');
|
||||
parsedTypeCheck(parsedType, 'str'); // true
|
||||
```
|
||||
|
||||
<a name="type-format" />
|
||||
## Type Format
|
||||
|
||||
### Syntax
|
||||
|
||||
White space is ignored. The root node is a __Types__.
|
||||
|
||||
* __Identifier__ = `[\$\w]+` - a group of any lower or upper case letters, numbers, underscores, or dollar signs - eg. `String`
|
||||
* __Type__ = an `Identifier`, an `Identifier` followed by a `Structure`, just a `Structure`, or a wildcard `*` - eg. `String`, `Object{x: Number}`, `{x: Number}`, `Array{0: String, 1: Boolean, length: Number}`, `*`
|
||||
* __Types__ = optionally a comment (an `Identifier` followed by a `::`), optionally the identifier `Maybe`, one or more `Type`, separated by `|` - eg. `Number`, `String | Date`, `Maybe Number`, `Maybe Boolean | String`
|
||||
* __Structure__ = `Fields`, or a `Tuple`, or an `Array` - eg. `{x: Number}`, `(String, Number)`, `[Date]`
|
||||
* __Fields__ = a `{`, followed one or more `Field` separated by a comma `,` (trailing comma `,` is permitted), optionally an `...` (always preceded by a comma `,`), followed by a `}` - eg. `{x: Number, y: String}`, `{k: Function, ...}`
|
||||
* __Field__ = an `Identifier`, followed by a colon `:`, followed by `Types` - eg. `x: Date | String`, `y: Boolean`
|
||||
* __Tuple__ = a `(`, followed by one or more `Types` separated by a comma `,` (trailing comma `,` is permitted), followed by a `)` - eg `(Date)`, `(Number, Date)`
|
||||
* __Array__ = a `[` followed by exactly one `Types` followed by a `]` - eg. `[Boolean]`, `[Boolean | Null]`
|
||||
|
||||
### Guide
|
||||
|
||||
`type-check` uses `Object.toString` to find out the basic type of a value. Specifically,
|
||||
|
||||
```js
|
||||
{}.toString.call(VALUE).slice(8, -1)
|
||||
{}.toString.call(true).slice(8, -1) // 'Boolean'
|
||||
```
|
||||
A basic type, eg. `Number`, uses this check. This is much more versatile than using `typeof` - for example, with `document`, `typeof` produces `'object'` which isn't that useful, and our technique produces `'HTMLDocument'`.
|
||||
|
||||
You may check for multiple types by separating types with a `|`. The checker proceeds from left to right, and passes if the value is any of the types - eg. `String | Boolean` first checks if the value is a string, and then if it is a boolean. If it is none of those, then it returns false.
|
||||
|
||||
Adding a `Maybe` in front of a list of multiple types is the same as also checking for `Null` and `Undefined` - eg. `Maybe String` is equivalent to `Undefined | Null | String`.
|
||||
|
||||
You may add a comment to remind you of what the type is for by following an identifier with a `::` before a type (or multiple types). The comment is simply thrown out.
|
||||
|
||||
The wildcard `*` matches all types.
|
||||
|
||||
There are three types of structures for checking the contents of a value: 'fields', 'tuple', and 'array'.
|
||||
|
||||
If used by itself, a 'fields' structure will pass with any type of object as long as it is an instance of `Object` and the properties pass - this allows for duck typing - eg. `{x: Boolean}`.
|
||||
|
||||
To check if the properties pass, and the value is of a certain type, you can specify the type - eg. `Error{message: String}`.
|
||||
|
||||
If you want to make a field optional, you can simply use `Maybe` - eg. `{x: Boolean, y: Maybe String}` will still pass if `y` is undefined (or null).
|
||||
|
||||
If you don't care if the value has properties beyond what you have specified, you can use the 'etc' operator `...` - eg. `{x: Boolean, ...}` will match an object with an `x` property that is a boolean, and with zero or more other properties.
|
||||
|
||||
For an array, you must specify one or more types (separated by `|`) - it will pass for something of any length as long as each element passes the types provided - eg. `[Number]`, `[Number | String]`.
|
||||
|
||||
A tuple checks for a fixed number of elements, each of a potentially different type. Each element is separated by a comma - eg. `(String, Number)`.
|
||||
|
||||
An array and tuple structure check that the value is of type `Array` by default, but if another type is specified, they will check for that instead - eg. `Int32Array[Number]`. You can use the wildcard `*` to search for any type at all.
|
||||
|
||||
Check out the [type precedence](https://github.com/zaboco/type-precedence) library for type-check.
|
||||
|
||||
## Options
|
||||
|
||||
Options is an object. It is an optional parameter to the `typeCheck` and `parsedTypeCheck` functions. The only current option is `customTypes`.
|
||||
|
||||
<a name="custom-types" />
|
||||
### Custom Types
|
||||
|
||||
__Example:__
|
||||
|
||||
```js
|
||||
var options = {
|
||||
customTypes: {
|
||||
Even: {
|
||||
typeOf: 'Number',
|
||||
validate: function(x) {
|
||||
return x % 2 === 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
typeCheck('Even', 2, options); // true
|
||||
typeCheck('Even', 3, options); // false
|
||||
```
|
||||
|
||||
`customTypes` allows you to set up custom types for validation. The value of this is an object. The keys of the object are the types you will be matching. Each value of the object will be an object having a `typeOf` property - a string, and `validate` property - a function.
|
||||
|
||||
The `typeOf` property is the type the value should be (optional - if not set only `validate` will be used), and `validate` is a function which should return true if the value is of that type. `validate` receives one parameter, which is the value that we are checking.
|
||||
|
||||
## Technical About
|
||||
|
||||
`type-check` is written in [LiveScript](http://livescript.net/) - a language that compiles to JavaScript. It also uses the [prelude.ls](http://preludels.com/) library.
|
||||
@@ -0,0 +1,99 @@
|
||||
'use strict';
|
||||
// Descend into a directory structure and, for each file matching *.node, output
|
||||
// based on the imports found in the file whether it's an N-API module or not.
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Read the output of the command, break it into lines, and use the reducer to
|
||||
// decide whether the file is an N-API module or not.
|
||||
function checkFile (file, command, argv, reducer) {
|
||||
const child = require('child_process').spawn(command, argv, {
|
||||
stdio: ['inherit', 'pipe', 'inherit']
|
||||
});
|
||||
let leftover = '';
|
||||
let isNapi;
|
||||
child.stdout.on('data', (chunk) => {
|
||||
if (isNapi === undefined) {
|
||||
chunk = (leftover + chunk.toString()).split(/[\r\n]+/);
|
||||
leftover = chunk.pop();
|
||||
isNapi = chunk.reduce(reducer, isNapi);
|
||||
if (isNapi !== undefined) {
|
||||
child.kill();
|
||||
}
|
||||
}
|
||||
});
|
||||
child.on('close', (code, signal) => {
|
||||
if ((code === null && signal !== null) || (code !== 0)) {
|
||||
console.log(
|
||||
command + ' exited with code: ' + code + ' and signal: ' + signal);
|
||||
} else {
|
||||
// Green if it's a N-API module, red otherwise.
|
||||
console.log(
|
||||
'\x1b[' + (isNapi ? '42' : '41') + 'm' +
|
||||
(isNapi ? ' N-API' : 'Not N-API') +
|
||||
'\x1b[0m: ' + file);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Use nm -a to list symbols.
|
||||
function checkFileUNIX (file) {
|
||||
checkFile(file, 'nm', ['-a', file], (soFar, line) => {
|
||||
if (soFar === undefined) {
|
||||
line = line.match(/([0-9a-f]*)? ([a-zA-Z]) (.*$)/);
|
||||
if (line[2] === 'U') {
|
||||
if (/^napi/.test(line[3])) {
|
||||
soFar = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return soFar;
|
||||
});
|
||||
}
|
||||
|
||||
// Use dumpbin /imports to list symbols.
|
||||
function checkFileWin32 (file) {
|
||||
checkFile(file, 'dumpbin', ['/imports', file], (soFar, line) => {
|
||||
if (soFar === undefined) {
|
||||
line = line.match(/([0-9a-f]*)? +([a-zA-Z0-9]) (.*$)/);
|
||||
if (line && /^napi/.test(line[line.length - 1])) {
|
||||
soFar = true;
|
||||
}
|
||||
}
|
||||
return soFar;
|
||||
});
|
||||
}
|
||||
|
||||
// Descend into a directory structure and pass each file ending in '.node' to
|
||||
// one of the above checks, depending on the OS.
|
||||
function recurse (top) {
|
||||
fs.readdir(top, (error, items) => {
|
||||
if (error) {
|
||||
throw new Error('error reading directory ' + top + ': ' + error);
|
||||
}
|
||||
items.forEach((item) => {
|
||||
item = path.join(top, item);
|
||||
fs.stat(item, ((item) => (error, stats) => {
|
||||
if (error) {
|
||||
throw new Error('error about ' + item + ': ' + error);
|
||||
}
|
||||
if (stats.isDirectory()) {
|
||||
recurse(item);
|
||||
} else if (/[.]node$/.test(item) &&
|
||||
// Explicitly ignore files called 'nothing.node' because they are
|
||||
// artefacts of node-addon-api having identified a version of
|
||||
// Node.js that ships with a correct implementation of N-API.
|
||||
path.basename(item) !== 'nothing.node') {
|
||||
process.platform === 'win32'
|
||||
? checkFileWin32(item)
|
||||
: checkFileUNIX(item);
|
||||
}
|
||||
})(item));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Start with the directory given on the command line or the current directory
|
||||
// if nothing was given.
|
||||
recurse(process.argv.length > 3 ? process.argv[2] : '.');
|
||||
@@ -0,0 +1 @@
|
||||
module.exports={C:{"135":0.05062,"136":0.12021,_:"2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 137 138 139 140 3.5 3.6"},D:{"47":0.02531,"56":0.02531,"94":0.07592,"122":0.02531,"123":0.05062,"124":0.49351,"126":0.05062,"127":0.24675,"129":0.05062,"131":0.41758,"132":1.18315,"133":10.25607,"134":33.34329,_:"4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 48 49 50 51 52 53 54 55 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 83 84 85 86 87 88 89 90 91 92 93 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 125 128 130 135 136 137 138"},F:{"116":0.02531,"117":0.14552,_:"9 11 12 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 60 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 9.5-9.6 10.0-10.1 10.5 10.6 11.1 11.5 11.6 12.1"},B:{"132":0.10123,"133":1.13253,"134":2.90409,_:"12 13 14 15 16 17 18 79 80 81 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131"},E:{_:"0 4 5 6 7 8 9 10 11 12 13 14 15 3.1 3.2 5.1 6.1 7.1 9.1 10.1 11.1 12.1 15.1 15.2-15.3 15.4 16.0 16.4 16.5 17.0 17.2 17.3 18.1 18.2","13.1":0.12021,"14.1":0.07592,"15.5":0.12021,"15.6":0.02531,"16.1":7.94039,"16.2":0.14552,"16.3":0.02531,"16.6":0.02531,"17.1":0.12021,"17.4":0.02531,"17.5":0.02531,"17.6":1.60073,"18.0":0.02531,"18.3":1.18315,"18.4":0.07592},G:{"8":0,"3.2":0,"4.0-4.1":0,"4.2-4.3":0.00243,"5.0-5.1":0,"6.0-6.1":0.00729,"7.0-7.1":0.00486,"8.1-8.4":0,"9.0-9.2":0.00365,"9.3":0.01702,"10.0-10.2":0.00122,"10.3":0.02796,"11.0-11.2":0.12887,"11.3-11.4":0.00851,"12.0-12.1":0.00486,"12.2-12.5":0.12036,"13.0-13.1":0.00243,"13.2":0.00365,"13.3":0.00486,"13.4-13.7":0.01702,"14.0-14.4":0.04255,"14.5-14.8":0.05106,"15.0-15.1":0.02796,"15.2-15.3":0.02796,"15.4":0.03404,"15.5":0.0389,"15.6-15.8":0.47901,"16.0":0.06808,"16.1":0.13981,"16.2":0.07295,"16.3":0.12644,"16.4":0.02796,"16.5":0.05228,"16.6-16.7":0.56776,"17.0":0.03404,"17.1":0.06079,"17.2":0.0462,"17.3":0.06444,"17.4":0.12887,"17.5":0.28692,"17.6-17.7":0.8328,"18.0":0.23343,"18.1":0.7635,"18.2":0.34163,"18.3":7.14018,"18.4":0.10577},P:{"23":0.02378,"27":0.72516,_:"4 20 21 22 24 25 26 5.0-5.4 6.2-6.4 8.2 9.2 10.1 11.1-11.2 12.0 13.0 14.0 15.0 16.0 17.0 18.0 19.0","7.2-7.4":0.35664},I:{"0":0,"3":0,"4":0,"2.1":0,"2.2":0,"2.3":0,"4.1":0,"4.2-4.3":0,"4.4":0,"4.4.3-4.4.4":0},K:{"0":0,_:"10 11 12 11.1 11.5 12.1"},A:{_:"6 7 8 9 10 11 5.5"},S:{_:"2.5 3.0-3.1"},J:{_:"7 10"},N:{_:"10 11"},R:{_:"0"},M:{"0":0.02938},Q:{_:"14.9"},O:{_:"0"},H:{"0":0},L:{"0":23.58018}};
|
||||
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
module.exports = require('./cjs/scheduler-unstable_mock.production.js');
|
||||
} else {
|
||||
module.exports = require('./cjs/scheduler-unstable_mock.development.js');
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
module.exports={A:{A:{"2":"K D E F A B mC"},B:{"1":"0 9 Q H R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z AB BB CB DB EB FB GB HB IB JB KB LB MB NB OB I","2":"C","260":"L M G N O P"},C:{"1":"0 9 nB oB pB qB rB sB tB uB vB MC wB NC xB yB zB 0B 1B 2B 3B 4B 5B 6B 7B 8B 9B AC BC CC DC Q H R OC S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z AB BB CB DB EB FB GB HB IB JB KB LB MB NB OB I PC EC QC RC oC pC","2":"1 2 3 4 5 6 7 8 nC LC J PB K D E F A B C L M G N O P QB RB qC rC","516":"SB TB UB VB WB XB YB ZB aB bB cB dB eB fB gB hB iB jB kB lB mB"},D:{"1":"0 9 qB rB sB tB uB vB MC wB NC xB yB zB 0B 1B 2B 3B 4B 5B 6B 7B 8B 9B AC BC CC DC Q H R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z AB BB CB DB EB FB GB HB IB JB KB LB MB NB OB I PC EC QC RC","2":"J","16":"PB K D E F A B C L M","260":"pB","772":"1 2 3 4 5 6 7 8 G N O P QB RB SB TB UB VB WB XB YB ZB aB bB cB dB eB fB gB hB iB jB kB lB mB nB oB"},E:{"1":"B C L M G TC FC GC xC yC zC UC VC HC 0C IC WC XC YC ZC aC 1C JC bC cC dC eC fC 2C KC gC hC iC jC 3C","2":"J sC SC","16":"PB","772":"K D E F A tC uC vC wC"},F:{"1":"0 dB eB fB gB hB iB jB kB lB mB nB oB pB qB rB sB tB uB vB wB xB yB zB 0B 1B 2B 3B 4B 5B 6B 7B 8B 9B AC BC CC DC Q H R OC S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z","16":"F 4C","260":"B C cB 5C 6C 7C FC kC 8C GC","772":"1 2 3 4 5 6 7 8 G N O P QB RB SB TB UB VB WB XB YB ZB aB bB"},G:{"1":"HD ID JD KD LD MD ND OD PD QD RD SD UC VC HC TD IC WC XC YC ZC aC UD JC bC cC dC eC fC VD KC gC hC iC jC","2":"SC 9C lC","772":"E AD BD CD DD ED FD GD"},H:{"132":"WD"},I:{"1":"I","2":"LC XD YD ZD","260":"J aD lC bD cD"},J:{"2":"D","260":"A"},K:{"1":"H","260":"A B C FC kC GC"},L:{"1":"I"},M:{"1":"EC"},N:{"2":"A B"},O:{"1":"HC"},P:{"1":"1 2 3 4 5 6 7 8 dD eD fD gD hD TC iD jD kD lD mD IC JC KC nD","260":"J"},Q:{"1":"oD"},R:{"1":"pD"},S:{"1":"rD","516":"qD"}},B:5,C:":in-range and :out-of-range CSS pseudo-classes",D:true};
|
||||
@@ -0,0 +1,304 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _assert = require("assert");
|
||||
var _t = require("@babel/types");
|
||||
var _importBuilder = require("./import-builder.js");
|
||||
var _isModule = require("./is-module.js");
|
||||
const {
|
||||
identifier,
|
||||
importSpecifier,
|
||||
numericLiteral,
|
||||
sequenceExpression,
|
||||
isImportDeclaration
|
||||
} = _t;
|
||||
class ImportInjector {
|
||||
constructor(path, importedSource, opts) {
|
||||
this._defaultOpts = {
|
||||
importedSource: null,
|
||||
importedType: "commonjs",
|
||||
importedInterop: "babel",
|
||||
importingInterop: "babel",
|
||||
ensureLiveReference: false,
|
||||
ensureNoContext: false,
|
||||
importPosition: "before"
|
||||
};
|
||||
const programPath = path.find(p => p.isProgram());
|
||||
this._programPath = programPath;
|
||||
this._programScope = programPath.scope;
|
||||
this._hub = programPath.hub;
|
||||
this._defaultOpts = this._applyDefaults(importedSource, opts, true);
|
||||
}
|
||||
addDefault(importedSourceIn, opts) {
|
||||
return this.addNamed("default", importedSourceIn, opts);
|
||||
}
|
||||
addNamed(importName, importedSourceIn, opts) {
|
||||
_assert(typeof importName === "string");
|
||||
return this._generateImport(this._applyDefaults(importedSourceIn, opts), importName);
|
||||
}
|
||||
addNamespace(importedSourceIn, opts) {
|
||||
return this._generateImport(this._applyDefaults(importedSourceIn, opts), null);
|
||||
}
|
||||
addSideEffect(importedSourceIn, opts) {
|
||||
return this._generateImport(this._applyDefaults(importedSourceIn, opts), void 0);
|
||||
}
|
||||
_applyDefaults(importedSource, opts, isInit = false) {
|
||||
let newOpts;
|
||||
if (typeof importedSource === "string") {
|
||||
newOpts = Object.assign({}, this._defaultOpts, {
|
||||
importedSource
|
||||
}, opts);
|
||||
} else {
|
||||
_assert(!opts, "Unexpected secondary arguments.");
|
||||
newOpts = Object.assign({}, this._defaultOpts, importedSource);
|
||||
}
|
||||
if (!isInit && opts) {
|
||||
if (opts.nameHint !== undefined) newOpts.nameHint = opts.nameHint;
|
||||
if (opts.blockHoist !== undefined) newOpts.blockHoist = opts.blockHoist;
|
||||
}
|
||||
return newOpts;
|
||||
}
|
||||
_generateImport(opts, importName) {
|
||||
const isDefault = importName === "default";
|
||||
const isNamed = !!importName && !isDefault;
|
||||
const isNamespace = importName === null;
|
||||
const {
|
||||
importedSource,
|
||||
importedType,
|
||||
importedInterop,
|
||||
importingInterop,
|
||||
ensureLiveReference,
|
||||
ensureNoContext,
|
||||
nameHint,
|
||||
importPosition,
|
||||
blockHoist
|
||||
} = opts;
|
||||
let name = nameHint || importName;
|
||||
const isMod = (0, _isModule.default)(this._programPath);
|
||||
const isModuleForNode = isMod && importingInterop === "node";
|
||||
const isModuleForBabel = isMod && importingInterop === "babel";
|
||||
if (importPosition === "after" && !isMod) {
|
||||
throw new Error(`"importPosition": "after" is only supported in modules`);
|
||||
}
|
||||
const builder = new _importBuilder.default(importedSource, this._programScope, this._hub);
|
||||
if (importedType === "es6") {
|
||||
if (!isModuleForNode && !isModuleForBabel) {
|
||||
throw new Error("Cannot import an ES6 module from CommonJS");
|
||||
}
|
||||
builder.import();
|
||||
if (isNamespace) {
|
||||
builder.namespace(nameHint || importedSource);
|
||||
} else if (isDefault || isNamed) {
|
||||
builder.named(name, importName);
|
||||
}
|
||||
} else if (importedType !== "commonjs") {
|
||||
throw new Error(`Unexpected interopType "${importedType}"`);
|
||||
} else if (importedInterop === "babel") {
|
||||
if (isModuleForNode) {
|
||||
name = name !== "default" ? name : importedSource;
|
||||
const es6Default = `${importedSource}$es6Default`;
|
||||
builder.import();
|
||||
if (isNamespace) {
|
||||
builder.default(es6Default).var(name || importedSource).wildcardInterop();
|
||||
} else if (isDefault) {
|
||||
if (ensureLiveReference) {
|
||||
builder.default(es6Default).var(name || importedSource).defaultInterop().read("default");
|
||||
} else {
|
||||
builder.default(es6Default).var(name).defaultInterop().prop(importName);
|
||||
}
|
||||
} else if (isNamed) {
|
||||
builder.default(es6Default).read(importName);
|
||||
}
|
||||
} else if (isModuleForBabel) {
|
||||
builder.import();
|
||||
if (isNamespace) {
|
||||
builder.namespace(name || importedSource);
|
||||
} else if (isDefault || isNamed) {
|
||||
builder.named(name, importName);
|
||||
}
|
||||
} else {
|
||||
builder.require();
|
||||
if (isNamespace) {
|
||||
builder.var(name || importedSource).wildcardInterop();
|
||||
} else if ((isDefault || isNamed) && ensureLiveReference) {
|
||||
if (isDefault) {
|
||||
name = name !== "default" ? name : importedSource;
|
||||
builder.var(name).read(importName);
|
||||
builder.defaultInterop();
|
||||
} else {
|
||||
builder.var(importedSource).read(importName);
|
||||
}
|
||||
} else if (isDefault) {
|
||||
builder.var(name).defaultInterop().prop(importName);
|
||||
} else if (isNamed) {
|
||||
builder.var(name).prop(importName);
|
||||
}
|
||||
}
|
||||
} else if (importedInterop === "compiled") {
|
||||
if (isModuleForNode) {
|
||||
builder.import();
|
||||
if (isNamespace) {
|
||||
builder.default(name || importedSource);
|
||||
} else if (isDefault || isNamed) {
|
||||
builder.default(importedSource).read(name);
|
||||
}
|
||||
} else if (isModuleForBabel) {
|
||||
builder.import();
|
||||
if (isNamespace) {
|
||||
builder.namespace(name || importedSource);
|
||||
} else if (isDefault || isNamed) {
|
||||
builder.named(name, importName);
|
||||
}
|
||||
} else {
|
||||
builder.require();
|
||||
if (isNamespace) {
|
||||
builder.var(name || importedSource);
|
||||
} else if (isDefault || isNamed) {
|
||||
if (ensureLiveReference) {
|
||||
builder.var(importedSource).read(name);
|
||||
} else {
|
||||
builder.prop(importName).var(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (importedInterop === "uncompiled") {
|
||||
if (isDefault && ensureLiveReference) {
|
||||
throw new Error("No live reference for commonjs default");
|
||||
}
|
||||
if (isModuleForNode) {
|
||||
builder.import();
|
||||
if (isNamespace) {
|
||||
builder.default(name || importedSource);
|
||||
} else if (isDefault) {
|
||||
builder.default(name);
|
||||
} else if (isNamed) {
|
||||
builder.default(importedSource).read(name);
|
||||
}
|
||||
} else if (isModuleForBabel) {
|
||||
builder.import();
|
||||
if (isNamespace) {
|
||||
builder.default(name || importedSource);
|
||||
} else if (isDefault) {
|
||||
builder.default(name);
|
||||
} else if (isNamed) {
|
||||
builder.named(name, importName);
|
||||
}
|
||||
} else {
|
||||
builder.require();
|
||||
if (isNamespace) {
|
||||
builder.var(name || importedSource);
|
||||
} else if (isDefault) {
|
||||
builder.var(name);
|
||||
} else if (isNamed) {
|
||||
if (ensureLiveReference) {
|
||||
builder.var(importedSource).read(name);
|
||||
} else {
|
||||
builder.var(name).prop(importName);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Error(`Unknown importedInterop "${importedInterop}".`);
|
||||
}
|
||||
const {
|
||||
statements,
|
||||
resultName
|
||||
} = builder.done();
|
||||
this._insertStatements(statements, importPosition, blockHoist);
|
||||
if ((isDefault || isNamed) && ensureNoContext && resultName.type !== "Identifier") {
|
||||
return sequenceExpression([numericLiteral(0), resultName]);
|
||||
}
|
||||
return resultName;
|
||||
}
|
||||
_insertStatements(statements, importPosition = "before", blockHoist = 3) {
|
||||
if (importPosition === "after") {
|
||||
if (this._insertStatementsAfter(statements)) return;
|
||||
} else {
|
||||
if (this._insertStatementsBefore(statements, blockHoist)) return;
|
||||
}
|
||||
this._programPath.unshiftContainer("body", statements);
|
||||
}
|
||||
_insertStatementsBefore(statements, blockHoist) {
|
||||
if (statements.length === 1 && isImportDeclaration(statements[0]) && isValueImport(statements[0])) {
|
||||
const firstImportDecl = this._programPath.get("body").find(p => {
|
||||
return p.isImportDeclaration() && isValueImport(p.node);
|
||||
});
|
||||
if ((firstImportDecl == null ? void 0 : firstImportDecl.node.source.value) === statements[0].source.value && maybeAppendImportSpecifiers(firstImportDecl.node, statements[0])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
statements.forEach(node => {
|
||||
node._blockHoist = blockHoist;
|
||||
});
|
||||
const targetPath = this._programPath.get("body").find(p => {
|
||||
const val = p.node._blockHoist;
|
||||
return Number.isFinite(val) && val < 4;
|
||||
});
|
||||
if (targetPath) {
|
||||
targetPath.insertBefore(statements);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
_insertStatementsAfter(statements) {
|
||||
const statementsSet = new Set(statements);
|
||||
const importDeclarations = new Map();
|
||||
for (const statement of statements) {
|
||||
if (isImportDeclaration(statement) && isValueImport(statement)) {
|
||||
const source = statement.source.value;
|
||||
if (!importDeclarations.has(source)) importDeclarations.set(source, []);
|
||||
importDeclarations.get(source).push(statement);
|
||||
}
|
||||
}
|
||||
let lastImportPath = null;
|
||||
for (const bodyStmt of this._programPath.get("body")) {
|
||||
if (bodyStmt.isImportDeclaration() && isValueImport(bodyStmt.node)) {
|
||||
lastImportPath = bodyStmt;
|
||||
const source = bodyStmt.node.source.value;
|
||||
const newImports = importDeclarations.get(source);
|
||||
if (!newImports) continue;
|
||||
for (const decl of newImports) {
|
||||
if (!statementsSet.has(decl)) continue;
|
||||
if (maybeAppendImportSpecifiers(bodyStmt.node, decl)) {
|
||||
statementsSet.delete(decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (statementsSet.size === 0) return true;
|
||||
if (lastImportPath) lastImportPath.insertAfter(Array.from(statementsSet));
|
||||
return !!lastImportPath;
|
||||
}
|
||||
}
|
||||
exports.default = ImportInjector;
|
||||
function isValueImport(node) {
|
||||
return node.importKind !== "type" && node.importKind !== "typeof";
|
||||
}
|
||||
function hasNamespaceImport(node) {
|
||||
return node.specifiers.length === 1 && node.specifiers[0].type === "ImportNamespaceSpecifier" || node.specifiers.length === 2 && node.specifiers[1].type === "ImportNamespaceSpecifier";
|
||||
}
|
||||
function hasDefaultImport(node) {
|
||||
return node.specifiers.length > 0 && node.specifiers[0].type === "ImportDefaultSpecifier";
|
||||
}
|
||||
function maybeAppendImportSpecifiers(target, source) {
|
||||
if (!target.specifiers.length) {
|
||||
target.specifiers = source.specifiers;
|
||||
return true;
|
||||
}
|
||||
if (!source.specifiers.length) return true;
|
||||
if (hasNamespaceImport(target) || hasNamespaceImport(source)) return false;
|
||||
if (hasDefaultImport(source)) {
|
||||
if (hasDefaultImport(target)) {
|
||||
source.specifiers[0] = importSpecifier(source.specifiers[0].local, identifier("default"));
|
||||
} else {
|
||||
target.specifiers.unshift(source.specifiers.shift());
|
||||
}
|
||||
}
|
||||
target.specifiers.push(...source.specifiers);
|
||||
return true;
|
||||
}
|
||||
|
||||
//# sourceMappingURL=import-injector.js.map
|
||||
@@ -0,0 +1,149 @@
|
||||
# ISC License
|
||||
#
|
||||
# Copyright (c) 2018-2025, Andrea Giammarchi, @WebReflection
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
# PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import json as _json
|
||||
|
||||
class _Known:
|
||||
def __init__(self):
|
||||
self.key = []
|
||||
self.value = []
|
||||
|
||||
class _String:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
|
||||
def _array_keys(value):
|
||||
keys = []
|
||||
i = 0
|
||||
for _ in value:
|
||||
keys.append(i)
|
||||
i += 1
|
||||
return keys
|
||||
|
||||
def _object_keys(value):
|
||||
keys = []
|
||||
for key in value:
|
||||
keys.append(key)
|
||||
return keys
|
||||
|
||||
def _is_array(value):
|
||||
return isinstance(value, (list, tuple))
|
||||
|
||||
def _is_object(value):
|
||||
return isinstance(value, dict)
|
||||
|
||||
def _is_string(value):
|
||||
return isinstance(value, str)
|
||||
|
||||
def _index(known, input, value):
|
||||
input.append(value)
|
||||
index = str(len(input) - 1)
|
||||
known.key.append(value)
|
||||
known.value.append(index)
|
||||
return index
|
||||
|
||||
def _loop(keys, input, known, output):
|
||||
for key in keys:
|
||||
value = output[key]
|
||||
if isinstance(value, _String):
|
||||
_ref(key, input[int(value.value)], input, known, output)
|
||||
|
||||
return output
|
||||
|
||||
def _ref(key, value, input, known, output):
|
||||
if _is_array(value) and value not in known:
|
||||
known.append(value)
|
||||
value = _loop(_array_keys(value), input, known, value)
|
||||
elif _is_object(value) and value not in known:
|
||||
known.append(value)
|
||||
value = _loop(_object_keys(value), input, known, value)
|
||||
|
||||
output[key] = value
|
||||
|
||||
def _relate(known, input, value):
|
||||
if _is_string(value) or _is_array(value) or _is_object(value):
|
||||
try:
|
||||
return known.value[known.key.index(value)]
|
||||
except:
|
||||
return _index(known, input, value)
|
||||
|
||||
return value
|
||||
|
||||
def _transform(known, input, value):
|
||||
if _is_array(value):
|
||||
output = []
|
||||
for val in value:
|
||||
output.append(_relate(known, input, val))
|
||||
return output
|
||||
|
||||
if _is_object(value):
|
||||
obj = {}
|
||||
for key in value:
|
||||
obj[key] = _relate(known, input, value[key])
|
||||
return obj
|
||||
|
||||
return value
|
||||
|
||||
def _wrap(value):
|
||||
if _is_string(value):
|
||||
return _String(value)
|
||||
|
||||
if _is_array(value):
|
||||
i = 0
|
||||
for val in value:
|
||||
value[i] = _wrap(val)
|
||||
i += 1
|
||||
|
||||
elif _is_object(value):
|
||||
for key in value:
|
||||
value[key] = _wrap(value[key])
|
||||
|
||||
return value
|
||||
|
||||
def parse(value, *args, **kwargs):
|
||||
json = _json.loads(value, *args, **kwargs)
|
||||
wrapped = []
|
||||
for value in json:
|
||||
wrapped.append(_wrap(value))
|
||||
|
||||
input = []
|
||||
for value in wrapped:
|
||||
if isinstance(value, _String):
|
||||
input.append(value.value)
|
||||
else:
|
||||
input.append(value)
|
||||
|
||||
value = input[0]
|
||||
|
||||
if _is_array(value):
|
||||
return _loop(_array_keys(value), input, [value], value)
|
||||
|
||||
if _is_object(value):
|
||||
return _loop(_object_keys(value), input, [value], value)
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def stringify(value, *args, **kwargs):
|
||||
known = _Known()
|
||||
input = []
|
||||
output = []
|
||||
i = int(_index(known, input, value))
|
||||
while i < len(input):
|
||||
output.append(_transform(known, input, input[i]))
|
||||
i += 1
|
||||
return _json.dumps(output, *args, **kwargs)
|
||||
@@ -0,0 +1,19 @@
|
||||
# @babel/template
|
||||
|
||||
> Generate an AST from a string template.
|
||||
|
||||
See our website [@babel/template](https://babeljs.io/docs/babel-template) for more information or the [issues](https://github.com/babel/babel/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22pkg%3A%20template%22+is%3Aopen) associated with this package.
|
||||
|
||||
## Install
|
||||
|
||||
Using npm:
|
||||
|
||||
```sh
|
||||
npm install --save-dev @babel/template
|
||||
```
|
||||
|
||||
or using yarn:
|
||||
|
||||
```sh
|
||||
yarn add @babel/template --dev
|
||||
```
|
||||
@@ -0,0 +1,150 @@
|
||||
'use strict';
|
||||
module.exports = function generate_format(it, $keyword, $ruleType) {
|
||||
var out = ' ';
|
||||
var $lvl = it.level;
|
||||
var $dataLvl = it.dataLevel;
|
||||
var $schema = it.schema[$keyword];
|
||||
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
||||
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
||||
var $breakOnError = !it.opts.allErrors;
|
||||
var $data = 'data' + ($dataLvl || '');
|
||||
if (it.opts.format === false) {
|
||||
if ($breakOnError) {
|
||||
out += ' if (true) { ';
|
||||
}
|
||||
return out;
|
||||
}
|
||||
var $isData = it.opts.$data && $schema && $schema.$data,
|
||||
$schemaValue;
|
||||
if ($isData) {
|
||||
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
|
||||
$schemaValue = 'schema' + $lvl;
|
||||
} else {
|
||||
$schemaValue = $schema;
|
||||
}
|
||||
var $unknownFormats = it.opts.unknownFormats,
|
||||
$allowUnknown = Array.isArray($unknownFormats);
|
||||
if ($isData) {
|
||||
var $format = 'format' + $lvl,
|
||||
$isObject = 'isObject' + $lvl,
|
||||
$formatType = 'formatType' + $lvl;
|
||||
out += ' var ' + ($format) + ' = formats[' + ($schemaValue) + ']; var ' + ($isObject) + ' = typeof ' + ($format) + ' == \'object\' && !(' + ($format) + ' instanceof RegExp) && ' + ($format) + '.validate; var ' + ($formatType) + ' = ' + ($isObject) + ' && ' + ($format) + '.type || \'string\'; if (' + ($isObject) + ') { ';
|
||||
if (it.async) {
|
||||
out += ' var async' + ($lvl) + ' = ' + ($format) + '.async; ';
|
||||
}
|
||||
out += ' ' + ($format) + ' = ' + ($format) + '.validate; } if ( ';
|
||||
if ($isData) {
|
||||
out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'string\') || ';
|
||||
}
|
||||
out += ' (';
|
||||
if ($unknownFormats != 'ignore') {
|
||||
out += ' (' + ($schemaValue) + ' && !' + ($format) + ' ';
|
||||
if ($allowUnknown) {
|
||||
out += ' && self._opts.unknownFormats.indexOf(' + ($schemaValue) + ') == -1 ';
|
||||
}
|
||||
out += ') || ';
|
||||
}
|
||||
out += ' (' + ($format) + ' && ' + ($formatType) + ' == \'' + ($ruleType) + '\' && !(typeof ' + ($format) + ' == \'function\' ? ';
|
||||
if (it.async) {
|
||||
out += ' (async' + ($lvl) + ' ? await ' + ($format) + '(' + ($data) + ') : ' + ($format) + '(' + ($data) + ')) ';
|
||||
} else {
|
||||
out += ' ' + ($format) + '(' + ($data) + ') ';
|
||||
}
|
||||
out += ' : ' + ($format) + '.test(' + ($data) + '))))) {';
|
||||
} else {
|
||||
var $format = it.formats[$schema];
|
||||
if (!$format) {
|
||||
if ($unknownFormats == 'ignore') {
|
||||
it.logger.warn('unknown format "' + $schema + '" ignored in schema at path "' + it.errSchemaPath + '"');
|
||||
if ($breakOnError) {
|
||||
out += ' if (true) { ';
|
||||
}
|
||||
return out;
|
||||
} else if ($allowUnknown && $unknownFormats.indexOf($schema) >= 0) {
|
||||
if ($breakOnError) {
|
||||
out += ' if (true) { ';
|
||||
}
|
||||
return out;
|
||||
} else {
|
||||
throw new Error('unknown format "' + $schema + '" is used in schema at path "' + it.errSchemaPath + '"');
|
||||
}
|
||||
}
|
||||
var $isObject = typeof $format == 'object' && !($format instanceof RegExp) && $format.validate;
|
||||
var $formatType = $isObject && $format.type || 'string';
|
||||
if ($isObject) {
|
||||
var $async = $format.async === true;
|
||||
$format = $format.validate;
|
||||
}
|
||||
if ($formatType != $ruleType) {
|
||||
if ($breakOnError) {
|
||||
out += ' if (true) { ';
|
||||
}
|
||||
return out;
|
||||
}
|
||||
if ($async) {
|
||||
if (!it.async) throw new Error('async format in sync schema');
|
||||
var $formatRef = 'formats' + it.util.getProperty($schema) + '.validate';
|
||||
out += ' if (!(await ' + ($formatRef) + '(' + ($data) + '))) { ';
|
||||
} else {
|
||||
out += ' if (! ';
|
||||
var $formatRef = 'formats' + it.util.getProperty($schema);
|
||||
if ($isObject) $formatRef += '.validate';
|
||||
if (typeof $format == 'function') {
|
||||
out += ' ' + ($formatRef) + '(' + ($data) + ') ';
|
||||
} else {
|
||||
out += ' ' + ($formatRef) + '.test(' + ($data) + ') ';
|
||||
}
|
||||
out += ') { ';
|
||||
}
|
||||
}
|
||||
var $$outStack = $$outStack || [];
|
||||
$$outStack.push(out);
|
||||
out = ''; /* istanbul ignore else */
|
||||
if (it.createErrors !== false) {
|
||||
out += ' { keyword: \'' + ('format') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { format: ';
|
||||
if ($isData) {
|
||||
out += '' + ($schemaValue);
|
||||
} else {
|
||||
out += '' + (it.util.toQuotedString($schema));
|
||||
}
|
||||
out += ' } ';
|
||||
if (it.opts.messages !== false) {
|
||||
out += ' , message: \'should match format "';
|
||||
if ($isData) {
|
||||
out += '\' + ' + ($schemaValue) + ' + \'';
|
||||
} else {
|
||||
out += '' + (it.util.escapeQuotes($schema));
|
||||
}
|
||||
out += '"\' ';
|
||||
}
|
||||
if (it.opts.verbose) {
|
||||
out += ' , schema: ';
|
||||
if ($isData) {
|
||||
out += 'validate.schema' + ($schemaPath);
|
||||
} else {
|
||||
out += '' + (it.util.toQuotedString($schema));
|
||||
}
|
||||
out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
||||
}
|
||||
out += ' } ';
|
||||
} else {
|
||||
out += ' {} ';
|
||||
}
|
||||
var __err = out;
|
||||
out = $$outStack.pop();
|
||||
if (!it.compositeRule && $breakOnError) {
|
||||
/* istanbul ignore if */
|
||||
if (it.async) {
|
||||
out += ' throw new ValidationError([' + (__err) + ']); ';
|
||||
} else {
|
||||
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
||||
}
|
||||
} else {
|
||||
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
||||
}
|
||||
out += ' } ';
|
||||
if ($breakOnError) {
|
||||
out += ' else { ';
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -0,0 +1,766 @@
|
||||
/**
|
||||
* @fileoverview Utility to load config files
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const path = require("node:path");
|
||||
const fs = require("node:fs/promises");
|
||||
const findUp = require("find-up");
|
||||
const { pathToFileURL } = require("node:url");
|
||||
const debug = require("debug")("eslint:config-loader");
|
||||
const { FlatConfigArray } = require("./flat-config-array");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Types
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @typedef {import("../shared/types").FlatConfigObject} FlatConfigObject
|
||||
* @typedef {import("../shared/types").FlatConfigArray} FlatConfigArray
|
||||
* @typedef {Object} ConfigLoaderOptions
|
||||
* @property {string|false|undefined} configFile The path to the config file to use.
|
||||
* @property {string} cwd The current working directory.
|
||||
* @property {boolean} ignoreEnabled Indicates if ignore patterns should be honored.
|
||||
* @property {FlatConfigArray} [baseConfig] The base config to use.
|
||||
* @property {Array<FlatConfigObject>} [defaultConfigs] The default configs to use.
|
||||
* @property {Array<string>} [ignorePatterns] The ignore patterns to use.
|
||||
* @property {FlatConfigObject|Array<FlatConfigObject>} overrideConfig The override config to use.
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const FLAT_CONFIG_FILENAMES = [
|
||||
"eslint.config.js",
|
||||
"eslint.config.mjs",
|
||||
"eslint.config.cjs",
|
||||
"eslint.config.ts",
|
||||
"eslint.config.mts",
|
||||
"eslint.config.cts",
|
||||
];
|
||||
|
||||
const importedConfigFileModificationTime = new Map();
|
||||
|
||||
/**
|
||||
* Asserts that the given file path is valid.
|
||||
* @param {string} filePath The file path to check.
|
||||
* @returns {void}
|
||||
* @throws {Error} If `filePath` is not a non-empty string.
|
||||
*/
|
||||
function assertValidFilePath(filePath) {
|
||||
if (!filePath || typeof filePath !== "string") {
|
||||
throw new Error("'filePath' must be a non-empty string");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a configuration exists. A configuration exists if any
|
||||
* of the following are true:
|
||||
* - `configFilePath` is defined.
|
||||
* - `useConfigFile` is `false`.
|
||||
* @param {string|undefined} configFilePath The path to the config file.
|
||||
* @param {ConfigLoaderOptions} loaderOptions The options to use when loading configuration files.
|
||||
* @returns {void}
|
||||
* @throws {Error} If no configuration exists.
|
||||
*/
|
||||
function assertConfigurationExists(configFilePath, loaderOptions) {
|
||||
const { configFile: useConfigFile } = loaderOptions;
|
||||
|
||||
if (!configFilePath && useConfigFile !== false) {
|
||||
const error = new Error("Could not find config file.");
|
||||
|
||||
error.messageTemplate = "config-file-missing";
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the file is a TypeScript file.
|
||||
* @param {string} filePath The file path to check.
|
||||
* @returns {boolean} `true` if the file is a TypeScript file, `false` if it's not.
|
||||
*/
|
||||
function isFileTS(filePath) {
|
||||
const fileExtension = path.extname(filePath);
|
||||
|
||||
return /^\.[mc]?ts$/u.test(fileExtension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if ESLint is running in Bun.
|
||||
* @returns {boolean} `true` if the ESLint is running Bun, `false` if it's not.
|
||||
*/
|
||||
function isRunningInBun() {
|
||||
return !!globalThis.Bun;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if ESLint is running in Deno.
|
||||
* @returns {boolean} `true` if the ESLint is running in Deno, `false` if it's not.
|
||||
*/
|
||||
function isRunningInDeno() {
|
||||
return !!globalThis.Deno;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the config array from the given filename.
|
||||
* @param {string} filePath The filename to load from.
|
||||
* @returns {Promise<any>} The config loaded from the config file.
|
||||
*/
|
||||
async function loadConfigFile(filePath) {
|
||||
debug(`Loading config from ${filePath}`);
|
||||
|
||||
const fileURL = pathToFileURL(filePath);
|
||||
|
||||
debug(`Config file URL is ${fileURL}`);
|
||||
|
||||
const mtime = (await fs.stat(filePath)).mtime.getTime();
|
||||
|
||||
/*
|
||||
* Append a query with the config file's modification time (`mtime`) in order
|
||||
* to import the current version of the config file. Without the query, `import()` would
|
||||
* cache the config file module by the pathname only, and then always return
|
||||
* the same version (the one that was actual when the module was imported for the first time).
|
||||
*
|
||||
* This ensures that the config file module is loaded and executed again
|
||||
* if it has been changed since the last time it was imported.
|
||||
* If it hasn't been changed, `import()` will just return the cached version.
|
||||
*
|
||||
* Note that we should not overuse queries (e.g., by appending the current time
|
||||
* to always reload the config file module) as that could cause memory leaks
|
||||
* because entries are never removed from the import cache.
|
||||
*/
|
||||
fileURL.searchParams.append("mtime", mtime);
|
||||
|
||||
/*
|
||||
* With queries, we can bypass the import cache. However, when import-ing a CJS module,
|
||||
* Node.js uses the require infrastructure under the hood. That includes the require cache,
|
||||
* which caches the config file module by its file path (queries have no effect).
|
||||
* Therefore, we also need to clear the require cache before importing the config file module.
|
||||
* In order to get the same behavior with ESM and CJS config files, in particular - to reload
|
||||
* the config file only if it has been changed, we track file modification times and clear
|
||||
* the require cache only if the file has been changed.
|
||||
*/
|
||||
if (importedConfigFileModificationTime.get(filePath) !== mtime) {
|
||||
delete require.cache[filePath];
|
||||
}
|
||||
|
||||
const isTS = isFileTS(filePath);
|
||||
const isBun = isRunningInBun();
|
||||
const isDeno = isRunningInDeno();
|
||||
|
||||
/*
|
||||
* If we are dealing with a TypeScript file, then we need to use `jiti` to load it
|
||||
* in Node.js. Deno and Bun both allow native importing of TypeScript files.
|
||||
*
|
||||
* When Node.js supports native TypeScript imports, we can remove this check.
|
||||
*/
|
||||
if (isTS && !isDeno && !isBun) {
|
||||
// eslint-disable-next-line no-use-before-define -- `ConfigLoader.loadJiti` can be overwritten for testing
|
||||
const { createJiti } = await ConfigLoader.loadJiti().catch(() => {
|
||||
throw new Error(
|
||||
"The 'jiti' library is required for loading TypeScript configuration files. Make sure to install it.",
|
||||
);
|
||||
});
|
||||
|
||||
// `createJiti` was added in jiti v2.
|
||||
if (typeof createJiti !== "function") {
|
||||
throw new Error(
|
||||
"You are using an outdated version of the 'jiti' library. Please update to the latest version of 'jiti' to ensure compatibility and access to the latest features.",
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disabling `moduleCache` allows us to reload a
|
||||
* config file when the last modified timestamp changes.
|
||||
*/
|
||||
|
||||
const jiti = createJiti(__filename, {
|
||||
moduleCache: false,
|
||||
interopDefault: false,
|
||||
});
|
||||
const config = await jiti.import(fileURL.href);
|
||||
|
||||
importedConfigFileModificationTime.set(filePath, mtime);
|
||||
|
||||
return config?.default ?? config;
|
||||
}
|
||||
|
||||
// fallback to normal runtime behavior
|
||||
|
||||
const config = (await import(fileURL)).default;
|
||||
|
||||
importedConfigFileModificationTime.set(filePath, mtime);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Encapsulates the loading and caching of configuration files when looking up
|
||||
* from the file being linted.
|
||||
*/
|
||||
class ConfigLoader {
|
||||
/**
|
||||
* Map of config file paths to the config arrays for those directories.
|
||||
* @type {Map<string, FlatConfigArray|Promise<FlatConfigArray>>}
|
||||
*/
|
||||
#configArrays = new Map();
|
||||
|
||||
/**
|
||||
* Map of absolute directory names to the config file paths for those directories.
|
||||
* @type {Map<string, {configFilePath:string,basePath:string}|Promise<{configFilePath:string,basePath:string}>>}
|
||||
*/
|
||||
#configFilePaths = new Map();
|
||||
|
||||
/**
|
||||
* The options to use when loading configuration files.
|
||||
* @type {ConfigLoaderOptions}
|
||||
*/
|
||||
#options;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param {ConfigLoaderOptions} options The options to use when loading configuration files.
|
||||
*/
|
||||
constructor(options) {
|
||||
this.#options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which config file to use. This is determined by seeing if an
|
||||
* override config file was specified, and if so, using it; otherwise, as long
|
||||
* as override config file is not explicitly set to `false`, it will search
|
||||
* upwards from `fromDirectory` for a file named `eslint.config.js`.
|
||||
* @param {string} fromDirectory The directory from which to start searching.
|
||||
* @returns {Promise<{configFilePath:string|undefined,basePath:string}>} Location information for
|
||||
* the config file.
|
||||
*/
|
||||
async #locateConfigFileToUse(fromDirectory) {
|
||||
// check cache first
|
||||
if (this.#configFilePaths.has(fromDirectory)) {
|
||||
return this.#configFilePaths.get(fromDirectory);
|
||||
}
|
||||
|
||||
const resultPromise = ConfigLoader.locateConfigFileToUse({
|
||||
useConfigFile: this.#options.configFile,
|
||||
cwd: this.#options.cwd,
|
||||
fromDirectory,
|
||||
});
|
||||
|
||||
// ensure `ConfigLoader.locateConfigFileToUse` is called only once for `fromDirectory`
|
||||
this.#configFilePaths.set(fromDirectory, resultPromise);
|
||||
|
||||
// Unwrap the promise. This is primarily for the sync `getCachedConfigArrayForPath` method.
|
||||
const result = await resultPromise;
|
||||
|
||||
this.#configFilePaths.set(fromDirectory, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the config array for this run based on inputs.
|
||||
* @param {string} configFilePath The absolute path to the config file to use if not overridden.
|
||||
* @param {string} basePath The base path to use for relative paths in the config file.
|
||||
* @returns {Promise<FlatConfigArray>} The config array for `eslint`.
|
||||
*/
|
||||
async #calculateConfigArray(configFilePath, basePath) {
|
||||
// check for cached version first
|
||||
if (this.#configArrays.has(configFilePath)) {
|
||||
return this.#configArrays.get(configFilePath);
|
||||
}
|
||||
|
||||
const configsPromise = ConfigLoader.calculateConfigArray(
|
||||
configFilePath,
|
||||
basePath,
|
||||
this.#options,
|
||||
);
|
||||
|
||||
// ensure `ConfigLoader.calculateConfigArray` is called only once for `configFilePath`
|
||||
this.#configArrays.set(configFilePath, configsPromise);
|
||||
|
||||
// Unwrap the promise. This is primarily for the sync `getCachedConfigArrayForPath` method.
|
||||
const configs = await configsPromise;
|
||||
|
||||
this.#configArrays.set(configFilePath, configs);
|
||||
|
||||
return configs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the config file path for the given directory or file. This will either use
|
||||
* the override config file that was specified in the constructor options or
|
||||
* search for a config file from the directory.
|
||||
* @param {string} fileOrDirPath The file or directory path to get the config file path for.
|
||||
* @returns {Promise<string|undefined>} The config file path or `undefined` if not found.
|
||||
* @throws {Error} If `fileOrDirPath` is not a non-empty string.
|
||||
* @throws {Error} If `fileOrDirPath` is not an absolute path.
|
||||
*/
|
||||
async findConfigFileForPath(fileOrDirPath) {
|
||||
assertValidFilePath(fileOrDirPath);
|
||||
|
||||
const absoluteDirPath = path.resolve(
|
||||
this.#options.cwd,
|
||||
path.dirname(fileOrDirPath),
|
||||
);
|
||||
const { configFilePath } =
|
||||
await this.#locateConfigFileToUse(absoluteDirPath);
|
||||
|
||||
return configFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a configuration object for the given file based on the CLI options.
|
||||
* This is the same logic used by the ESLint CLI executable to determine
|
||||
* configuration for each file it processes.
|
||||
* @param {string} filePath The path of the file or directory to retrieve config for.
|
||||
* @returns {Promise<ConfigData|undefined>} A configuration object for the file
|
||||
* or `undefined` if there is no configuration data for the file.
|
||||
* @throws {Error} If no configuration for `filePath` exists.
|
||||
*/
|
||||
async loadConfigArrayForFile(filePath) {
|
||||
assertValidFilePath(filePath);
|
||||
|
||||
debug(`Calculating config for file ${filePath}`);
|
||||
|
||||
const configFilePath = await this.findConfigFileForPath(filePath);
|
||||
|
||||
assertConfigurationExists(configFilePath, this.#options);
|
||||
|
||||
return this.loadConfigArrayForDirectory(filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a configuration object for the given directory based on the CLI options.
|
||||
* This is the same logic used by the ESLint CLI executable to determine
|
||||
* configuration for each file it processes.
|
||||
* @param {string} dirPath The path of the directory to retrieve config for.
|
||||
* @returns {Promise<ConfigData|undefined>} A configuration object for the directory
|
||||
* or `undefined` if there is no configuration data for the directory.
|
||||
*/
|
||||
async loadConfigArrayForDirectory(dirPath) {
|
||||
assertValidFilePath(dirPath);
|
||||
|
||||
debug(`Calculating config for directory ${dirPath}`);
|
||||
|
||||
const absoluteDirPath = path.resolve(
|
||||
this.#options.cwd,
|
||||
path.dirname(dirPath),
|
||||
);
|
||||
const { configFilePath, basePath } =
|
||||
await this.#locateConfigFileToUse(absoluteDirPath);
|
||||
|
||||
debug(`Using config file ${configFilePath} and base path ${basePath}`);
|
||||
return this.#calculateConfigArray(configFilePath, basePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a configuration array for the given file based on the CLI options.
|
||||
* This is a synchronous operation and does not read any files from disk. It's
|
||||
* intended to be used in locations where we know the config file has already
|
||||
* been loaded and we just need to get the configuration for a file.
|
||||
* @param {string} filePath The path of the file to retrieve a config object for.
|
||||
* @returns {ConfigData|undefined} A configuration object for the file
|
||||
* or `undefined` if there is no configuration data for the file.
|
||||
* @throws {Error} If `filePath` is not a non-empty string.
|
||||
* @throws {Error} If `filePath` is not an absolute path.
|
||||
* @throws {Error} If the config file was not already loaded.
|
||||
*/
|
||||
getCachedConfigArrayForFile(filePath) {
|
||||
assertValidFilePath(filePath);
|
||||
|
||||
debug(`Looking up cached config for ${filePath}`);
|
||||
|
||||
return this.getCachedConfigArrayForPath(path.dirname(filePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a configuration array for the given directory based on the CLI options.
|
||||
* This is a synchronous operation and does not read any files from disk. It's
|
||||
* intended to be used in locations where we know the config file has already
|
||||
* been loaded and we just need to get the configuration for a file.
|
||||
* @param {string} fileOrDirPath The path of the directory to retrieve a config object for.
|
||||
* @returns {ConfigData|undefined} A configuration object for the directory
|
||||
* or `undefined` if there is no configuration data for the directory.
|
||||
* @throws {Error} If `dirPath` is not a non-empty string.
|
||||
* @throws {Error} If `dirPath` is not an absolute path.
|
||||
* @throws {Error} If the config file was not already loaded.
|
||||
*/
|
||||
getCachedConfigArrayForPath(fileOrDirPath) {
|
||||
assertValidFilePath(fileOrDirPath);
|
||||
|
||||
debug(`Looking up cached config for ${fileOrDirPath}`);
|
||||
|
||||
const absoluteDirPath = path.resolve(this.#options.cwd, fileOrDirPath);
|
||||
|
||||
if (!this.#configFilePaths.has(absoluteDirPath)) {
|
||||
throw new Error(`Could not find config file for ${fileOrDirPath}`);
|
||||
}
|
||||
|
||||
const configFilePathInfo = this.#configFilePaths.get(absoluteDirPath);
|
||||
|
||||
if (typeof configFilePathInfo.then === "function") {
|
||||
throw new Error(
|
||||
`Config file path for ${fileOrDirPath} has not yet been calculated or an error occurred during the calculation`,
|
||||
);
|
||||
}
|
||||
|
||||
const { configFilePath } = configFilePathInfo;
|
||||
|
||||
const configArray = this.#configArrays.get(configFilePath);
|
||||
|
||||
if (!configArray || typeof configArray.then === "function") {
|
||||
throw new Error(
|
||||
`Config array for ${fileOrDirPath} has not yet been calculated or an error occurred during the calculation`,
|
||||
);
|
||||
}
|
||||
|
||||
return configArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to import the jiti dependency. This method is exposed internally for testing purposes.
|
||||
* @returns {Promise<Record<string, unknown>>} A promise that fulfills with a module object
|
||||
* or rejects with an error if jiti is not found.
|
||||
*/
|
||||
static loadJiti() {
|
||||
return import("jiti");
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which config file to use. This is determined by seeing if an
|
||||
* override config file was specified, and if so, using it; otherwise, as long
|
||||
* as override config file is not explicitly set to `false`, it will search
|
||||
* upwards from `fromDirectory` for a file named `eslint.config.js`.
|
||||
* This method is exposed internally for testing purposes.
|
||||
* @param {Object} [options] the options object
|
||||
* @param {string|false|undefined} options.useConfigFile The path to the config file to use.
|
||||
* @param {string} options.cwd Path to a directory that should be considered as the current working directory.
|
||||
* @param {string} [options.fromDirectory] The directory from which to start searching. Defaults to `cwd`.
|
||||
* @returns {Promise<{configFilePath:string|undefined,basePath:string}>} Location information for
|
||||
* the config file.
|
||||
*/
|
||||
static async locateConfigFileToUse({
|
||||
useConfigFile,
|
||||
cwd,
|
||||
fromDirectory = cwd,
|
||||
}) {
|
||||
// determine where to load config file from
|
||||
let configFilePath;
|
||||
let basePath = cwd;
|
||||
|
||||
if (typeof useConfigFile === "string") {
|
||||
debug(`Override config file path is ${useConfigFile}`);
|
||||
configFilePath = path.resolve(cwd, useConfigFile);
|
||||
basePath = cwd;
|
||||
} else if (useConfigFile !== false) {
|
||||
debug("Searching for eslint.config.js");
|
||||
configFilePath = await findUp(FLAT_CONFIG_FILENAMES, {
|
||||
cwd: fromDirectory,
|
||||
});
|
||||
|
||||
if (configFilePath) {
|
||||
basePath = path.dirname(configFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
configFilePath,
|
||||
basePath,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the config array for this run based on inputs.
|
||||
* This method is exposed internally for testing purposes.
|
||||
* @param {string} configFilePath The absolute path to the config file to use if not overridden.
|
||||
* @param {string} basePath The base path to use for relative paths in the config file.
|
||||
* @param {ConfigLoaderOptions} options The options to use when loading configuration files.
|
||||
* @returns {Promise<FlatConfigArray>} The config array for `eslint`.
|
||||
*/
|
||||
static async calculateConfigArray(configFilePath, basePath, options) {
|
||||
const {
|
||||
cwd,
|
||||
baseConfig,
|
||||
ignoreEnabled,
|
||||
ignorePatterns,
|
||||
overrideConfig,
|
||||
defaultConfigs = [],
|
||||
} = options;
|
||||
|
||||
debug(
|
||||
`Calculating config array from config file ${configFilePath} and base path ${basePath}`,
|
||||
);
|
||||
|
||||
const configs = new FlatConfigArray(baseConfig || [], {
|
||||
basePath,
|
||||
shouldIgnore: ignoreEnabled,
|
||||
});
|
||||
|
||||
// load config file
|
||||
if (configFilePath) {
|
||||
debug(`Loading config file ${configFilePath}`);
|
||||
const fileConfig = await loadConfigFile(configFilePath);
|
||||
|
||||
/*
|
||||
* It's possible that a config file could be empty or else
|
||||
* have an empty object or array. In this case, we want to
|
||||
* warn the user that they have an empty config.
|
||||
*
|
||||
* An empty CommonJS file exports an empty object while
|
||||
* an empty ESM file exports undefined.
|
||||
*/
|
||||
|
||||
let emptyConfig = typeof fileConfig === "undefined";
|
||||
|
||||
debug(
|
||||
`Config file ${configFilePath} is ${emptyConfig ? "empty" : "not empty"}`,
|
||||
);
|
||||
|
||||
if (!emptyConfig) {
|
||||
if (Array.isArray(fileConfig)) {
|
||||
if (fileConfig.length === 0) {
|
||||
debug(
|
||||
`Config file ${configFilePath} is an empty array`,
|
||||
);
|
||||
emptyConfig = true;
|
||||
} else {
|
||||
configs.push(...fileConfig);
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
typeof fileConfig === "object" &&
|
||||
fileConfig !== null &&
|
||||
Object.keys(fileConfig).length === 0
|
||||
) {
|
||||
debug(
|
||||
`Config file ${configFilePath} is an empty object`,
|
||||
);
|
||||
emptyConfig = true;
|
||||
} else {
|
||||
configs.push(fileConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (emptyConfig) {
|
||||
globalThis.process?.emitWarning?.(
|
||||
`Running ESLint with an empty config (from ${configFilePath}). Please double-check that this is what you want. If you want to run ESLint with an empty config, export [{}] to remove this warning.`,
|
||||
"ESLintEmptyConfigWarning",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// add in any configured defaults
|
||||
configs.push(...defaultConfigs);
|
||||
|
||||
// append command line ignore patterns
|
||||
if (ignorePatterns && ignorePatterns.length > 0) {
|
||||
let relativeIgnorePatterns;
|
||||
|
||||
/*
|
||||
* If the config file basePath is different than the cwd, then
|
||||
* the ignore patterns won't work correctly. Here, we adjust the
|
||||
* ignore pattern to include the correct relative path. Patterns
|
||||
* passed as `ignorePatterns` are relative to the cwd, whereas
|
||||
* the config file basePath can be an ancestor of the cwd.
|
||||
*/
|
||||
if (basePath === cwd) {
|
||||
relativeIgnorePatterns = ignorePatterns;
|
||||
} else {
|
||||
// relative path must only have Unix-style separators
|
||||
const relativeIgnorePath = path
|
||||
.relative(basePath, cwd)
|
||||
.replace(/\\/gu, "/");
|
||||
|
||||
relativeIgnorePatterns = ignorePatterns.map(pattern => {
|
||||
const negated = pattern.startsWith("!");
|
||||
const basePattern = negated ? pattern.slice(1) : pattern;
|
||||
|
||||
return (
|
||||
(negated ? "!" : "") +
|
||||
path.posix.join(relativeIgnorePath, basePattern)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore patterns are added to the end of the config array
|
||||
* so they can override default ignores.
|
||||
*/
|
||||
configs.push({
|
||||
ignores: relativeIgnorePatterns,
|
||||
});
|
||||
}
|
||||
|
||||
if (overrideConfig) {
|
||||
if (Array.isArray(overrideConfig)) {
|
||||
configs.push(...overrideConfig);
|
||||
} else {
|
||||
configs.push(overrideConfig);
|
||||
}
|
||||
}
|
||||
|
||||
await configs.normalize();
|
||||
|
||||
return configs;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates the loading and caching of configuration files when looking up
|
||||
* from the current working directory.
|
||||
*/
|
||||
class LegacyConfigLoader extends ConfigLoader {
|
||||
/**
|
||||
* The options to use when loading configuration files.
|
||||
* @type {ConfigLoaderOptions}
|
||||
*/
|
||||
#options;
|
||||
|
||||
/**
|
||||
* The cached config file path for this instance.
|
||||
* @type {Promise<{configFilePath:string,basePath:string}|undefined>}
|
||||
*/
|
||||
#configFilePath;
|
||||
|
||||
/**
|
||||
* The cached config array for this instance.
|
||||
* @type {FlatConfigArray|Promise<FlatConfigArray>}
|
||||
*/
|
||||
#configArray;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param {ConfigLoaderOptions} options The options to use when loading configuration files.
|
||||
*/
|
||||
constructor(options) {
|
||||
super(options);
|
||||
this.#options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which config file to use. This is determined by seeing if an
|
||||
* override config file was specified, and if so, using it; otherwise, as long
|
||||
* as override config file is not explicitly set to `false`, it will search
|
||||
* upwards from the cwd for a file named `eslint.config.js`.
|
||||
* @returns {Promise<{configFilePath:string|undefined,basePath:string}>} Location information for
|
||||
* the config file.
|
||||
*/
|
||||
#locateConfigFileToUse() {
|
||||
if (!this.#configFilePath) {
|
||||
this.#configFilePath = ConfigLoader.locateConfigFileToUse({
|
||||
useConfigFile: this.#options.configFile,
|
||||
cwd: this.#options.cwd,
|
||||
});
|
||||
}
|
||||
|
||||
return this.#configFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the config array for this run based on inputs.
|
||||
* @param {string} configFilePath The absolute path to the config file to use if not overridden.
|
||||
* @param {string} basePath The base path to use for relative paths in the config file.
|
||||
* @returns {Promise<FlatConfigArray>} The config array for `eslint`.
|
||||
*/
|
||||
async #calculateConfigArray(configFilePath, basePath) {
|
||||
// check for cached version first
|
||||
if (this.#configArray) {
|
||||
return this.#configArray;
|
||||
}
|
||||
|
||||
// ensure `ConfigLoader.calculateConfigArray` is called only once
|
||||
this.#configArray = ConfigLoader.calculateConfigArray(
|
||||
configFilePath,
|
||||
basePath,
|
||||
this.#options,
|
||||
);
|
||||
|
||||
// Unwrap the promise. This is primarily for the sync `getCachedConfigArrayForPath` method.
|
||||
this.#configArray = await this.#configArray;
|
||||
|
||||
return this.#configArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the config file path for the given directory. This will either use
|
||||
* the override config file that was specified in the constructor options or
|
||||
* search for a config file from the directory of the file being linted.
|
||||
* @param {string} dirPath The directory path to get the config file path for.
|
||||
* @returns {Promise<string|undefined>} The config file path or `undefined` if not found.
|
||||
* @throws {Error} If `fileOrDirPath` is not a non-empty string.
|
||||
* @throws {Error} If `fileOrDirPath` is not an absolute path.
|
||||
*/
|
||||
async findConfigFileForPath(dirPath) {
|
||||
assertValidFilePath(dirPath);
|
||||
|
||||
const { configFilePath } = await this.#locateConfigFileToUse();
|
||||
|
||||
return configFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a configuration object for the given file based on the CLI options.
|
||||
* This is the same logic used by the ESLint CLI executable to determine
|
||||
* configuration for each file it processes.
|
||||
* @param {string} dirPath The path of the directory to retrieve config for.
|
||||
* @returns {Promise<ConfigData|undefined>} A configuration object for the file
|
||||
* or `undefined` if there is no configuration data for the file.
|
||||
*/
|
||||
async loadConfigArrayForDirectory(dirPath) {
|
||||
assertValidFilePath(dirPath);
|
||||
|
||||
debug(`[Legacy]: Calculating config for ${dirPath}`);
|
||||
|
||||
const { configFilePath, basePath } =
|
||||
await this.#locateConfigFileToUse();
|
||||
|
||||
debug(
|
||||
`[Legacy]: Using config file ${configFilePath} and base path ${basePath}`,
|
||||
);
|
||||
return this.#calculateConfigArray(configFilePath, basePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a configuration array for the given directory based on the CLI options.
|
||||
* This is a synchronous operation and does not read any files from disk. It's
|
||||
* intended to be used in locations where we know the config file has already
|
||||
* been loaded and we just need to get the configuration for a file.
|
||||
* @param {string} dirPath The path of the directory to retrieve a config object for.
|
||||
* @returns {ConfigData|undefined} A configuration object for the file
|
||||
* or `undefined` if there is no configuration data for the file.
|
||||
* @throws {Error} If `dirPath` is not a non-empty string.
|
||||
* @throws {Error} If `dirPath` is not an absolute path.
|
||||
* @throws {Error} If the config file was not already loaded.
|
||||
*/
|
||||
getCachedConfigArrayForPath(dirPath) {
|
||||
assertValidFilePath(dirPath);
|
||||
|
||||
debug(`[Legacy]: Looking up cached config for ${dirPath}`);
|
||||
|
||||
if (!this.#configArray) {
|
||||
throw new Error(`Could not find config file for ${dirPath}`);
|
||||
}
|
||||
|
||||
if (typeof this.#configArray.then === "function") {
|
||||
throw new Error(
|
||||
`Config array for ${dirPath} has not yet been calculated or an error occurred during the calculation`,
|
||||
);
|
||||
}
|
||||
|
||||
return this.#configArray;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { ConfigLoader, LegacyConfigLoader };
|
||||
@@ -0,0 +1,264 @@
|
||||
# @jridgewell/sourcemap-codec
|
||||
|
||||
Encode/decode the `mappings` property of a [sourcemap](https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit).
|
||||
|
||||
|
||||
## Why?
|
||||
|
||||
Sourcemaps are difficult to generate and manipulate, because the `mappings` property – the part that actually links the generated code back to the original source – is encoded using an obscure method called [Variable-length quantity](https://en.wikipedia.org/wiki/Variable-length_quantity). On top of that, each segment in the mapping contains offsets rather than absolute indices, which means that you can't look at a segment in isolation – you have to understand the whole sourcemap.
|
||||
|
||||
This package makes the process slightly easier.
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @jridgewell/sourcemap-codec
|
||||
```
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
import { encode, decode } from '@jridgewell/sourcemap-codec';
|
||||
|
||||
var decoded = decode( ';EAEEA,EAAE,EAAC,CAAE;ECQY,UACC' );
|
||||
|
||||
assert.deepEqual( decoded, [
|
||||
// the first line (of the generated code) has no mappings,
|
||||
// as shown by the starting semi-colon (which separates lines)
|
||||
[],
|
||||
|
||||
// the second line contains four (comma-separated) segments
|
||||
[
|
||||
// segments are encoded as you'd expect:
|
||||
// [ generatedCodeColumn, sourceIndex, sourceCodeLine, sourceCodeColumn, nameIndex ]
|
||||
|
||||
// i.e. the first segment begins at column 2, and maps back to the second column
|
||||
// of the second line (both zero-based) of the 0th source, and uses the 0th
|
||||
// name in the `map.names` array
|
||||
[ 2, 0, 2, 2, 0 ],
|
||||
|
||||
// the remaining segments are 4-length rather than 5-length,
|
||||
// because they don't map a name
|
||||
[ 4, 0, 2, 4 ],
|
||||
[ 6, 0, 2, 5 ],
|
||||
[ 7, 0, 2, 7 ]
|
||||
],
|
||||
|
||||
// the final line contains two segments
|
||||
[
|
||||
[ 2, 1, 10, 19 ],
|
||||
[ 12, 1, 11, 20 ]
|
||||
]
|
||||
]);
|
||||
|
||||
var encoded = encode( decoded );
|
||||
assert.equal( encoded, ';EAEEA,EAAE,EAAC,CAAE;ECQY,UACC' );
|
||||
```
|
||||
|
||||
## Benchmarks
|
||||
|
||||
```
|
||||
node v20.10.0
|
||||
|
||||
amp.js.map - 45120 segments
|
||||
|
||||
Decode Memory Usage:
|
||||
local code 5815135 bytes
|
||||
@jridgewell/sourcemap-codec 1.4.15 5868160 bytes
|
||||
sourcemap-codec 5492584 bytes
|
||||
source-map-0.6.1 13569984 bytes
|
||||
source-map-0.8.0 6390584 bytes
|
||||
chrome dev tools 8011136 bytes
|
||||
Smallest memory usage is sourcemap-codec
|
||||
|
||||
Decode speed:
|
||||
decode: local code x 492 ops/sec ±1.22% (90 runs sampled)
|
||||
decode: @jridgewell/sourcemap-codec 1.4.15 x 499 ops/sec ±1.16% (89 runs sampled)
|
||||
decode: sourcemap-codec x 376 ops/sec ±1.66% (89 runs sampled)
|
||||
decode: source-map-0.6.1 x 34.99 ops/sec ±0.94% (48 runs sampled)
|
||||
decode: source-map-0.8.0 x 351 ops/sec ±0.07% (95 runs sampled)
|
||||
chrome dev tools x 165 ops/sec ±0.91% (86 runs sampled)
|
||||
Fastest is decode: @jridgewell/sourcemap-codec 1.4.15
|
||||
|
||||
Encode Memory Usage:
|
||||
local code 444248 bytes
|
||||
@jridgewell/sourcemap-codec 1.4.15 623024 bytes
|
||||
sourcemap-codec 8696280 bytes
|
||||
source-map-0.6.1 8745176 bytes
|
||||
source-map-0.8.0 8736624 bytes
|
||||
Smallest memory usage is local code
|
||||
|
||||
Encode speed:
|
||||
encode: local code x 796 ops/sec ±0.11% (97 runs sampled)
|
||||
encode: @jridgewell/sourcemap-codec 1.4.15 x 795 ops/sec ±0.25% (98 runs sampled)
|
||||
encode: sourcemap-codec x 231 ops/sec ±0.83% (86 runs sampled)
|
||||
encode: source-map-0.6.1 x 166 ops/sec ±0.57% (86 runs sampled)
|
||||
encode: source-map-0.8.0 x 203 ops/sec ±0.45% (88 runs sampled)
|
||||
Fastest is encode: local code,encode: @jridgewell/sourcemap-codec 1.4.15
|
||||
|
||||
|
||||
***
|
||||
|
||||
|
||||
babel.min.js.map - 347793 segments
|
||||
|
||||
Decode Memory Usage:
|
||||
local code 35424960 bytes
|
||||
@jridgewell/sourcemap-codec 1.4.15 35424696 bytes
|
||||
sourcemap-codec 36033464 bytes
|
||||
source-map-0.6.1 62253704 bytes
|
||||
source-map-0.8.0 43843920 bytes
|
||||
chrome dev tools 45111400 bytes
|
||||
Smallest memory usage is @jridgewell/sourcemap-codec 1.4.15
|
||||
|
||||
Decode speed:
|
||||
decode: local code x 38.18 ops/sec ±5.44% (52 runs sampled)
|
||||
decode: @jridgewell/sourcemap-codec 1.4.15 x 38.36 ops/sec ±5.02% (52 runs sampled)
|
||||
decode: sourcemap-codec x 34.05 ops/sec ±4.45% (47 runs sampled)
|
||||
decode: source-map-0.6.1 x 4.31 ops/sec ±2.76% (15 runs sampled)
|
||||
decode: source-map-0.8.0 x 55.60 ops/sec ±0.13% (73 runs sampled)
|
||||
chrome dev tools x 16.94 ops/sec ±3.78% (46 runs sampled)
|
||||
Fastest is decode: source-map-0.8.0
|
||||
|
||||
Encode Memory Usage:
|
||||
local code 2606016 bytes
|
||||
@jridgewell/sourcemap-codec 1.4.15 2626440 bytes
|
||||
sourcemap-codec 21152576 bytes
|
||||
source-map-0.6.1 25023928 bytes
|
||||
source-map-0.8.0 25256448 bytes
|
||||
Smallest memory usage is local code
|
||||
|
||||
Encode speed:
|
||||
encode: local code x 127 ops/sec ±0.18% (83 runs sampled)
|
||||
encode: @jridgewell/sourcemap-codec 1.4.15 x 128 ops/sec ±0.26% (83 runs sampled)
|
||||
encode: sourcemap-codec x 29.31 ops/sec ±2.55% (53 runs sampled)
|
||||
encode: source-map-0.6.1 x 18.85 ops/sec ±3.19% (36 runs sampled)
|
||||
encode: source-map-0.8.0 x 19.34 ops/sec ±1.97% (36 runs sampled)
|
||||
Fastest is encode: @jridgewell/sourcemap-codec 1.4.15
|
||||
|
||||
|
||||
***
|
||||
|
||||
|
||||
preact.js.map - 1992 segments
|
||||
|
||||
Decode Memory Usage:
|
||||
local code 261696 bytes
|
||||
@jridgewell/sourcemap-codec 1.4.15 244296 bytes
|
||||
sourcemap-codec 302816 bytes
|
||||
source-map-0.6.1 939176 bytes
|
||||
source-map-0.8.0 336 bytes
|
||||
chrome dev tools 587368 bytes
|
||||
Smallest memory usage is source-map-0.8.0
|
||||
|
||||
Decode speed:
|
||||
decode: local code x 17,782 ops/sec ±0.32% (97 runs sampled)
|
||||
decode: @jridgewell/sourcemap-codec 1.4.15 x 17,863 ops/sec ±0.40% (100 runs sampled)
|
||||
decode: sourcemap-codec x 12,453 ops/sec ±0.27% (101 runs sampled)
|
||||
decode: source-map-0.6.1 x 1,288 ops/sec ±1.05% (96 runs sampled)
|
||||
decode: source-map-0.8.0 x 9,289 ops/sec ±0.27% (101 runs sampled)
|
||||
chrome dev tools x 4,769 ops/sec ±0.18% (100 runs sampled)
|
||||
Fastest is decode: @jridgewell/sourcemap-codec 1.4.15
|
||||
|
||||
Encode Memory Usage:
|
||||
local code 262944 bytes
|
||||
@jridgewell/sourcemap-codec 1.4.15 25544 bytes
|
||||
sourcemap-codec 323048 bytes
|
||||
source-map-0.6.1 507808 bytes
|
||||
source-map-0.8.0 507480 bytes
|
||||
Smallest memory usage is @jridgewell/sourcemap-codec 1.4.15
|
||||
|
||||
Encode speed:
|
||||
encode: local code x 24,207 ops/sec ±0.79% (95 runs sampled)
|
||||
encode: @jridgewell/sourcemap-codec 1.4.15 x 24,288 ops/sec ±0.48% (96 runs sampled)
|
||||
encode: sourcemap-codec x 6,761 ops/sec ±0.21% (100 runs sampled)
|
||||
encode: source-map-0.6.1 x 5,374 ops/sec ±0.17% (99 runs sampled)
|
||||
encode: source-map-0.8.0 x 5,633 ops/sec ±0.32% (99 runs sampled)
|
||||
Fastest is encode: @jridgewell/sourcemap-codec 1.4.15,encode: local code
|
||||
|
||||
|
||||
***
|
||||
|
||||
|
||||
react.js.map - 5726 segments
|
||||
|
||||
Decode Memory Usage:
|
||||
local code 678816 bytes
|
||||
@jridgewell/sourcemap-codec 1.4.15 678816 bytes
|
||||
sourcemap-codec 816400 bytes
|
||||
source-map-0.6.1 2288864 bytes
|
||||
source-map-0.8.0 721360 bytes
|
||||
chrome dev tools 1012512 bytes
|
||||
Smallest memory usage is local code
|
||||
|
||||
Decode speed:
|
||||
decode: local code x 6,178 ops/sec ±0.19% (98 runs sampled)
|
||||
decode: @jridgewell/sourcemap-codec 1.4.15 x 6,261 ops/sec ±0.22% (100 runs sampled)
|
||||
decode: sourcemap-codec x 4,472 ops/sec ±0.90% (99 runs sampled)
|
||||
decode: source-map-0.6.1 x 449 ops/sec ±0.31% (95 runs sampled)
|
||||
decode: source-map-0.8.0 x 3,219 ops/sec ±0.13% (100 runs sampled)
|
||||
chrome dev tools x 1,743 ops/sec ±0.20% (99 runs sampled)
|
||||
Fastest is decode: @jridgewell/sourcemap-codec 1.4.15
|
||||
|
||||
Encode Memory Usage:
|
||||
local code 140960 bytes
|
||||
@jridgewell/sourcemap-codec 1.4.15 159808 bytes
|
||||
sourcemap-codec 969304 bytes
|
||||
source-map-0.6.1 930520 bytes
|
||||
source-map-0.8.0 930248 bytes
|
||||
Smallest memory usage is local code
|
||||
|
||||
Encode speed:
|
||||
encode: local code x 8,013 ops/sec ±0.19% (100 runs sampled)
|
||||
encode: @jridgewell/sourcemap-codec 1.4.15 x 7,989 ops/sec ±0.20% (101 runs sampled)
|
||||
encode: sourcemap-codec x 2,472 ops/sec ±0.21% (99 runs sampled)
|
||||
encode: source-map-0.6.1 x 2,200 ops/sec ±0.17% (99 runs sampled)
|
||||
encode: source-map-0.8.0 x 2,220 ops/sec ±0.37% (99 runs sampled)
|
||||
Fastest is encode: local code
|
||||
|
||||
|
||||
***
|
||||
|
||||
|
||||
vscode.map - 2141001 segments
|
||||
|
||||
Decode Memory Usage:
|
||||
local code 198955264 bytes
|
||||
@jridgewell/sourcemap-codec 1.4.15 199175352 bytes
|
||||
sourcemap-codec 199102688 bytes
|
||||
source-map-0.6.1 386323432 bytes
|
||||
source-map-0.8.0 244116432 bytes
|
||||
chrome dev tools 293734280 bytes
|
||||
Smallest memory usage is local code
|
||||
|
||||
Decode speed:
|
||||
decode: local code x 3.90 ops/sec ±22.21% (15 runs sampled)
|
||||
decode: @jridgewell/sourcemap-codec 1.4.15 x 3.95 ops/sec ±23.53% (15 runs sampled)
|
||||
decode: sourcemap-codec x 3.82 ops/sec ±17.94% (14 runs sampled)
|
||||
decode: source-map-0.6.1 x 0.61 ops/sec ±7.81% (6 runs sampled)
|
||||
decode: source-map-0.8.0 x 9.54 ops/sec ±0.28% (28 runs sampled)
|
||||
chrome dev tools x 2.18 ops/sec ±10.58% (10 runs sampled)
|
||||
Fastest is decode: source-map-0.8.0
|
||||
|
||||
Encode Memory Usage:
|
||||
local code 13509880 bytes
|
||||
@jridgewell/sourcemap-codec 1.4.15 13537648 bytes
|
||||
sourcemap-codec 32540104 bytes
|
||||
source-map-0.6.1 127531040 bytes
|
||||
source-map-0.8.0 127535312 bytes
|
||||
Smallest memory usage is local code
|
||||
|
||||
Encode speed:
|
||||
encode: local code x 20.10 ops/sec ±0.19% (38 runs sampled)
|
||||
encode: @jridgewell/sourcemap-codec 1.4.15 x 20.26 ops/sec ±0.32% (38 runs sampled)
|
||||
encode: sourcemap-codec x 5.44 ops/sec ±1.64% (18 runs sampled)
|
||||
encode: source-map-0.6.1 x 2.30 ops/sec ±4.79% (10 runs sampled)
|
||||
encode: source-map-0.8.0 x 2.46 ops/sec ±6.53% (10 runs sampled)
|
||||
Fastest is encode: @jridgewell/sourcemap-codec 1.4.15
|
||||
```
|
||||
|
||||
# License
|
||||
|
||||
MIT
|
||||
Reference in New Issue
Block a user