diff --git a/lib/constants.js b/lib/constants.js
index dc0ebaafe..07f9ab589 100644
--- a/lib/constants.js
+++ b/lib/constants.js
@@ -10,7 +10,7 @@ exports.action = {
token: (0, core_1.getInput)('token'),
template: !(0, util_1.isNullOrUndefined)((0, core_1.getInput)('template'))
? (0, core_1.getInput)('template')
- : ``,
+ : ``,
minimum: !(0, util_1.isNullOrUndefined)((0, core_1.getInput)('minimum'))
? parseInt((0, core_1.getInput)('minimum'))
: 0,
diff --git a/node_modules/eslint/node_modules/eslint-visitor-keys/LICENSE b/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/LICENSE
similarity index 100%
rename from node_modules/eslint/node_modules/eslint-visitor-keys/LICENSE
rename to node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/LICENSE
diff --git a/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/README.md b/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/README.md
new file mode 100644
index 000000000..cab810320
--- /dev/null
+++ b/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/README.md
@@ -0,0 +1,105 @@
+# eslint-visitor-keys
+
+[![npm version](https://img.shields.io/npm/v/eslint-visitor-keys.svg)](https://www.npmjs.com/package/eslint-visitor-keys)
+[![Downloads/month](https://img.shields.io/npm/dm/eslint-visitor-keys.svg)](http://www.npmtrends.com/eslint-visitor-keys)
+[![Build Status](https://github.com/eslint/eslint-visitor-keys/workflows/CI/badge.svg)](https://github.com/eslint/eslint-visitor-keys/actions)
+
+Constants and utilities about visitor keys to traverse AST.
+
+## 💿 Installation
+
+Use [npm] to install.
+
+```bash
+$ npm install eslint-visitor-keys
+```
+
+### Requirements
+
+- [Node.js] `^12.22.0`, `^14.17.0`, or `>=16.0.0`
+
+
+## 📖 Usage
+
+To use in an ESM file:
+
+```js
+import * as evk from "eslint-visitor-keys"
+```
+
+To use in a CommonJS file:
+
+```js
+const evk = require("eslint-visitor-keys")
+```
+
+### evk.KEYS
+
+> type: `{ [type: string]: string[] | undefined }`
+
+Visitor keys. This keys are frozen.
+
+This is an object. Keys are the type of [ESTree] nodes. Their values are an array of property names which have child nodes.
+
+For example:
+
+```
+console.log(evk.KEYS.AssignmentExpression) // → ["left", "right"]
+```
+
+### evk.getKeys(node)
+
+> type: `(node: object) => string[]`
+
+Get the visitor keys of a given AST node.
+
+This is similar to `Object.keys(node)` of ES Standard, but some keys are excluded: `parent`, `leadingComments`, `trailingComments`, and names which start with `_`.
+
+This will be used to traverse unknown nodes.
+
+For example:
+
+```js
+const node = {
+ type: "AssignmentExpression",
+ left: { type: "Identifier", name: "foo" },
+ right: { type: "Literal", value: 0 }
+}
+console.log(evk.getKeys(node)) // → ["type", "left", "right"]
+```
+
+### evk.unionWith(additionalKeys)
+
+> type: `(additionalKeys: object) => { [type: string]: string[] | undefined }`
+
+Make the union set with `evk.KEYS` and the given keys.
+
+- The order of keys is, `additionalKeys` is at first, then `evk.KEYS` is concatenated after that.
+- It removes duplicated keys as keeping the first one.
+
+For example:
+
+```js
+console.log(evk.unionWith({
+ MethodDefinition: ["decorators"]
+})) // → { ..., MethodDefinition: ["decorators", "key", "value"], ... }
+```
+
+## 📰 Change log
+
+See [GitHub releases](https://github.com/eslint/eslint-visitor-keys/releases).
+
+## 🍻 Contributing
+
+Welcome. See [ESLint contribution guidelines](https://eslint.org/docs/developer-guide/contributing/).
+
+### Development commands
+
+- `npm test` runs tests and measures code coverage.
+- `npm run lint` checks source codes with ESLint.
+- `npm run test:open-coverage` opens the code coverage report of the previous test with your default browser.
+
+
+[npm]: https://www.npmjs.com/
+[Node.js]: https://nodejs.org/
+[ESTree]: https://github.com/estree/estree
diff --git a/node_modules/espree/node_modules/eslint-visitor-keys/dist/eslint-visitor-keys.cjs b/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/eslint-visitor-keys.cjs
similarity index 87%
rename from node_modules/espree/node_modules/eslint-visitor-keys/dist/eslint-visitor-keys.cjs
rename to node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/eslint-visitor-keys.cjs
index 7f58e49bc..00f91bcc4 100644
--- a/node_modules/espree/node_modules/eslint-visitor-keys/dist/eslint-visitor-keys.cjs
+++ b/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/eslint-visitor-keys.cjs
@@ -1,12 +1,10 @@
'use strict';
-/* eslint-disable jsdoc/valid-types -- doesn't allow `readonly`.
- TODO: remove eslint-disable when https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/issues/164 is fixed
-*/
+Object.defineProperty(exports, '__esModule', { value: true });
+
/**
* @typedef {{ readonly [type: string]: ReadonlyArray }} VisitorKeys
*/
-/* eslint-enable jsdoc/valid-types -- doesn't allow `readonly string[]`. TODO: check why */
/**
* @type {VisitorKeys}
@@ -89,8 +87,7 @@ const KEYS = {
],
ExportAllDeclaration: [
"exported",
- "source",
- "attributes"
+ "source"
],
ExportDefaultDeclaration: [
"declaration"
@@ -98,8 +95,7 @@ const KEYS = {
ExportNamedDeclaration: [
"declaration",
"specifiers",
- "source",
- "attributes"
+ "source"
],
ExportSpecifier: [
"exported",
@@ -140,21 +136,15 @@ const KEYS = {
"consequent",
"alternate"
],
- ImportAttribute: [
- "key",
- "value"
- ],
ImportDeclaration: [
"specifiers",
- "source",
- "attributes"
+ "source"
],
ImportDefaultSpecifier: [
"local"
],
ImportExpression: [
- "source",
- "options"
+ "source"
],
ImportNamespaceSpecifier: [
"local"
@@ -351,31 +341,29 @@ function filterKey(key) {
return !KEY_BLACKLIST.has(key) && key[0] !== "_";
}
-
-/* eslint-disable jsdoc/valid-types -- doesn't allow `readonly`.
- TODO: remove eslint-disable when https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/issues/164 is fixed
-*/
/**
* Get visitor keys of a given node.
- * @param {Object} node The AST node to get keys.
+ * @param {object} node The AST node to get keys.
* @returns {readonly string[]} Visitor keys of the node.
*/
function getKeys(node) {
return Object.keys(node).filter(filterKey);
}
-/* eslint-enable jsdoc/valid-types -- doesn't allow `readonly` */
+// Disable valid-jsdoc rule because it reports syntax error on the type of @returns.
+// eslint-disable-next-line valid-jsdoc
/**
* Make the union set with `KEYS` and given keys.
* @param {VisitorKeys} additionalKeys The additional keys.
* @returns {VisitorKeys} The union set.
*/
function unionWith(additionalKeys) {
- const retv = /** @type {{ [type: string]: ReadonlyArray }} */
- (Object.assign({}, KEYS));
+ const retv = /** @type {{
+ [type: string]: ReadonlyArray
+ }} */ (Object.assign({}, KEYS));
for (const type of Object.keys(additionalKeys)) {
- if (Object.hasOwn(retv, type)) {
+ if (Object.prototype.hasOwnProperty.call(retv, type)) {
const keys = new Set(additionalKeys[type]);
for (const key of retv[type]) {
diff --git a/node_modules/eslint/node_modules/eslint-visitor-keys/dist/eslint-visitor-keys.d.cts b/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/eslint-visitor-keys.d.cts
similarity index 71%
rename from node_modules/eslint/node_modules/eslint-visitor-keys/dist/eslint-visitor-keys.d.cts
rename to node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/eslint-visitor-keys.d.cts
index a8684341f..c7c28ed37 100644
--- a/node_modules/eslint/node_modules/eslint-visitor-keys/dist/eslint-visitor-keys.d.cts
+++ b/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/eslint-visitor-keys.d.cts
@@ -1,5 +1,5 @@
type VisitorKeys$1 = {
- readonly [type: string]: ReadonlyArray;
+ readonly [type: string]: readonly string[];
};
/**
* @typedef {{ readonly [type: string]: ReadonlyArray }} VisitorKeys
@@ -11,10 +11,10 @@ declare const KEYS: VisitorKeys$1;
/**
* Get visitor keys of a given node.
- * @param {Object} node The AST node to get keys.
+ * @param {object} node The AST node to get keys.
* @returns {readonly string[]} Visitor keys of the node.
*/
-declare function getKeys(node: Object): readonly string[];
+declare function getKeys(node: object): readonly string[];
/**
* Make the union set with `KEYS` and given keys.
* @param {VisitorKeys} additionalKeys The additional keys.
@@ -24,4 +24,4 @@ declare function unionWith(additionalKeys: VisitorKeys): VisitorKeys;
type VisitorKeys = VisitorKeys$1;
-export { KEYS, type VisitorKeys, getKeys, unionWith };
+export { KEYS, VisitorKeys, getKeys, unionWith };
diff --git a/node_modules/eslint/node_modules/eslint-visitor-keys/dist/index.d.ts b/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/index.d.ts
similarity index 71%
rename from node_modules/eslint/node_modules/eslint-visitor-keys/dist/index.d.ts
rename to node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/index.d.ts
index e65b7da33..46bd87e27 100644
--- a/node_modules/eslint/node_modules/eslint-visitor-keys/dist/index.d.ts
+++ b/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/index.d.ts
@@ -1,9 +1,9 @@
/**
* Get visitor keys of a given node.
- * @param {Object} node The AST node to get keys.
+ * @param {object} node The AST node to get keys.
* @returns {readonly string[]} Visitor keys of the node.
*/
-export function getKeys(node: Object): readonly string[];
+export function getKeys(node: object): readonly string[];
/**
* Make the union set with `KEYS` and given keys.
* @param {VisitorKeys} additionalKeys The additional keys.
@@ -11,6 +11,6 @@ export function getKeys(node: Object): readonly string[];
*/
export function unionWith(additionalKeys: VisitorKeys): VisitorKeys;
export { KEYS };
-export type VisitorKeys = import("./visitor-keys.js").VisitorKeys;
+export type VisitorKeys = import('./visitor-keys.js').VisitorKeys;
import KEYS from "./visitor-keys.js";
//# sourceMappingURL=index.d.ts.map
\ No newline at end of file
diff --git a/node_modules/eslint/node_modules/eslint-visitor-keys/dist/visitor-keys.d.ts b/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/visitor-keys.d.ts
similarity index 82%
rename from node_modules/eslint/node_modules/eslint-visitor-keys/dist/visitor-keys.d.ts
rename to node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/visitor-keys.d.ts
index 2d7ada2f1..57a952c50 100644
--- a/node_modules/eslint/node_modules/eslint-visitor-keys/dist/visitor-keys.d.ts
+++ b/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/dist/visitor-keys.d.ts
@@ -1,6 +1,6 @@
export default KEYS;
export type VisitorKeys = {
- readonly [type: string]: ReadonlyArray;
+ readonly [type: string]: readonly string[];
};
/**
* @typedef {{ readonly [type: string]: ReadonlyArray }} VisitorKeys
diff --git a/node_modules/eslint/node_modules/eslint-visitor-keys/lib/index.js b/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/lib/index.js
similarity index 75%
rename from node_modules/eslint/node_modules/eslint-visitor-keys/lib/index.js
rename to node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/lib/index.js
index 1fc89b43d..3622816d6 100644
--- a/node_modules/eslint/node_modules/eslint-visitor-keys/lib/index.js
+++ b/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/lib/index.js
@@ -24,31 +24,29 @@ function filterKey(key) {
return !KEY_BLACKLIST.has(key) && key[0] !== "_";
}
-
-/* eslint-disable jsdoc/valid-types -- doesn't allow `readonly`.
- TODO: remove eslint-disable when https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/issues/164 is fixed
-*/
/**
* Get visitor keys of a given node.
- * @param {Object} node The AST node to get keys.
+ * @param {object} node The AST node to get keys.
* @returns {readonly string[]} Visitor keys of the node.
*/
export function getKeys(node) {
return Object.keys(node).filter(filterKey);
}
-/* eslint-enable jsdoc/valid-types -- doesn't allow `readonly` */
+// Disable valid-jsdoc rule because it reports syntax error on the type of @returns.
+// eslint-disable-next-line valid-jsdoc
/**
* Make the union set with `KEYS` and given keys.
* @param {VisitorKeys} additionalKeys The additional keys.
* @returns {VisitorKeys} The union set.
*/
export function unionWith(additionalKeys) {
- const retv = /** @type {{ [type: string]: ReadonlyArray }} */
- (Object.assign({}, KEYS));
+ const retv = /** @type {{
+ [type: string]: ReadonlyArray
+ }} */ (Object.assign({}, KEYS));
for (const type of Object.keys(additionalKeys)) {
- if (Object.hasOwn(retv, type)) {
+ if (Object.prototype.hasOwnProperty.call(retv, type)) {
const keys = new Set(additionalKeys[type]);
for (const key of retv[type]) {
diff --git a/node_modules/espree/node_modules/eslint-visitor-keys/lib/visitor-keys.js b/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/lib/visitor-keys.js
similarity index 91%
rename from node_modules/espree/node_modules/eslint-visitor-keys/lib/visitor-keys.js
rename to node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/lib/visitor-keys.js
index 41feb4b2f..ccf2b1f9a 100644
--- a/node_modules/espree/node_modules/eslint-visitor-keys/lib/visitor-keys.js
+++ b/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/lib/visitor-keys.js
@@ -1,10 +1,6 @@
-/* eslint-disable jsdoc/valid-types -- doesn't allow `readonly`.
- TODO: remove eslint-disable when https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/issues/164 is fixed
-*/
/**
* @typedef {{ readonly [type: string]: ReadonlyArray }} VisitorKeys
*/
-/* eslint-enable jsdoc/valid-types -- doesn't allow `readonly string[]`. TODO: check why */
/**
* @type {VisitorKeys}
@@ -87,8 +83,7 @@ const KEYS = {
],
ExportAllDeclaration: [
"exported",
- "source",
- "attributes"
+ "source"
],
ExportDefaultDeclaration: [
"declaration"
@@ -96,8 +91,7 @@ const KEYS = {
ExportNamedDeclaration: [
"declaration",
"specifiers",
- "source",
- "attributes"
+ "source"
],
ExportSpecifier: [
"exported",
@@ -138,21 +132,15 @@ const KEYS = {
"consequent",
"alternate"
],
- ImportAttribute: [
- "key",
- "value"
- ],
ImportDeclaration: [
"specifiers",
- "source",
- "attributes"
+ "source"
],
ImportDefaultSpecifier: [
"local"
],
ImportExpression: [
- "source",
- "options"
+ "source"
],
ImportNamespaceSpecifier: [
"local"
diff --git a/node_modules/espree/node_modules/eslint-visitor-keys/package.json b/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/package.json
similarity index 72%
rename from node_modules/espree/node_modules/eslint-visitor-keys/package.json
rename to node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/package.json
index 4dc2123db..b9d51ce0e 100644
--- a/node_modules/espree/node_modules/eslint-visitor-keys/package.json
+++ b/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys/package.json
@@ -1,6 +1,6 @@
{
"name": "eslint-visitor-keys",
- "version": "4.2.0",
+ "version": "3.4.3",
"description": "Constants and utilities about visitor keys to traverse AST.",
"type": "module",
"main": "dist/eslint-visitor-keys.cjs",
@@ -23,29 +23,36 @@
"lib"
],
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"devDependencies": {
"@types/estree": "^0.0.51",
"@types/estree-jsx": "^0.0.1",
- "@typescript-eslint/parser": "^8.7.0",
+ "@typescript-eslint/parser": "^5.14.0",
"c8": "^7.11.0",
"chai": "^4.3.6",
+ "eslint": "^7.29.0",
+ "eslint-config-eslint": "^7.0.0",
+ "eslint-plugin-jsdoc": "^35.4.0",
+ "eslint-plugin-node": "^11.1.0",
"eslint-release": "^3.2.0",
"esquery": "^1.4.0",
"json-diff": "^0.7.3",
"mocha": "^9.2.1",
"opener": "^1.5.2",
- "rollup": "^4.22.4",
- "rollup-plugin-dts": "^6.1.1",
- "tsd": "^0.31.2",
- "typescript": "^5.6.2"
+ "rollup": "^2.70.0",
+ "rollup-plugin-dts": "^4.2.3",
+ "tsd": "^0.19.1",
+ "typescript": "^4.6.2"
},
"scripts": {
"build": "npm run build:cjs && npm run build:types",
"build:cjs": "rollup -c",
"build:debug": "npm run build:cjs -- -m && npm run build:types",
- "build:types": "tsc -v && tsc",
+ "build:keys": "node tools/build-keys-from-ts",
+ "build:types": "tsc",
+ "lint": "eslint .",
+ "prepare": "npm run build",
"release:generate:latest": "eslint-generate-release",
"release:generate:alpha": "eslint-generate-prerelease alpha",
"release:generate:beta": "eslint-generate-prerelease beta",
@@ -55,13 +62,13 @@
"test:open-coverage": "c8 report --reporter lcov && opener coverage/lcov-report/index.html",
"test:types": "tsd"
},
- "repository": "eslint/js",
+ "repository": "eslint/eslint-visitor-keys",
"funding": "https://opencollective.com/eslint",
"keywords": [],
"author": "Toru Nagashima (https://github.com/mysticatea)",
"license": "Apache-2.0",
"bugs": {
- "url": "https://github.com/eslint/js/issues"
+ "url": "https://github.com/eslint/eslint-visitor-keys/issues"
},
- "homepage": "https://github.com/eslint/js/blob/main/packages/eslint-visitor-keys/README.md"
+ "homepage": "https://github.com/eslint/eslint-visitor-keys#readme"
}
diff --git a/node_modules/@eslint/config-array/README.md b/node_modules/@eslint/config-array/README.md
index 339612e95..9d343aaec 100644
--- a/node_modules/@eslint/config-array/README.md
+++ b/node_modules/@eslint/config-array/README.md
@@ -170,7 +170,7 @@ export default [
In this example, the array contains both config objects and a config array. When a config array is normalized (see details below), it is flattened so only config objects remain. However, the order of evaluation remains the same.
-If the `files` array contains a function, then that function is called with the absolute path of the file and is expected to return `true` if there is a match and `false` if not. (The `ignores` array can also contain functions.)
+If the `files` array contains a function, then that function is called with the path of the file as it was passed in. The function is expected to return `true` if there is a match and `false` if not. (The `ignores` array can also contain functions.)
If the `files` array contains an item that is an array of strings and functions, then all patterns must match in order for the config to match. In the preceding examples, both `*.test.*` and `*.js` must match in order for the config object to be used.
@@ -273,7 +273,7 @@ await configs.normalizeSync({
To get the config for a file, use the `getConfig()` method on a normalized config array and pass in the filename to get a config for:
```js
-// pass in absolute filename
+// pass in filename
const fileConfig = configs.getConfig(
path.resolve(process.cwd(), "package.json"),
);
@@ -283,14 +283,14 @@ The config array always returns an object, even if there are no configs matching
A few things to keep in mind:
-- You must pass in the absolute filename to get a config for.
+- If a filename is not an absolute path, it will be resolved relative to the base path directory.
- The returned config object never has `files`, `ignores`, or `name` properties; the only properties on the object will be the other configuration options specified.
- The config array caches configs, so subsequent calls to `getConfig()` with the same filename will return in a fast lookup rather than another calculation.
- A config will only be generated if the filename matches an entry in a `files` key. A config will not be generated without matching a `files` key (configs without a `files` key are only applied when another config with a `files` key is applied; configs without `files` are never applied on their own). Any config with a `files` key entry that is `*` or ends with `/**` or `/*` will only be applied if another entry in the same `files` key matches or another config matches.
## Determining Ignored Paths
-You can determine if a file is ignored by using the `isFileIgnored()` method and passing in the absolute path of any file, as in this example:
+You can determine if a file is ignored by using the `isFileIgnored()` method and passing in the path of any file, as in this example:
```js
const ignored = configs.isFileIgnored("/foo/bar/baz.txt");
@@ -304,7 +304,7 @@ A file is considered ignored if any of the following is true:
- **If it matches an entry in `files` and also in `ignores`.** For example, if `**/*.js` is in `files` and `**/a.js` is in `ignores`, then `foo/a.js` and `foo/baz/a.js` are considered ignored.
- **The file is outside the `basePath`.** If the `basePath` is `/usr/me`, then `/foo/a.js` is considered ignored.
-For directories, use the `isDirectoryIgnored()` method and pass in the absolute path of any directory, as in this example:
+For directories, use the `isDirectoryIgnored()` method and pass in the path of any directory, as in this example:
```js
const ignored = configs.isDirectoryIgnored("/foo/bar/");
@@ -339,21 +339,20 @@ The design of this project was influenced by feedback on the ESLint RFC, and inc
Apache 2.0
+
+
+
## Sponsors
-The following companies, organizations, and individuals support ESLint's ongoing maintenance and development. [Become a Sponsor](https://eslint.org/donate) to get your logo on our README and website.
+The following companies, organizations, and individuals support ESLint's ongoing maintenance and development. [Become a Sponsor](https://eslint.org/donate)
+to get your logo on our READMEs and [website](https://eslint.org/sponsors).
-
-
Platinum Sponsors
Gold Sponsors
-
Silver Sponsors
+
Silver Sponsors
Bronze Sponsors
-
+
+
Technology Sponsors
+Technology sponsors allow us to use their products and services for free as part of a contribution to the open source ecosystem and our work.
+
-
-
-
Technology Sponsors
-
-
-
diff --git a/node_modules/@eslint/config-array/dist/cjs/index.cjs b/node_modules/@eslint/config-array/dist/cjs/index.cjs
index c411b9c5c..cc033c315 100644
--- a/node_modules/@eslint/config-array/dist/cjs/index.cjs
+++ b/node_modules/@eslint/config-array/dist/cjs/index.cjs
@@ -1,10 +1,31 @@
'use strict';
-var path = require('node:path');
+var posixPath = require('./std__path/posix.cjs');
+var windowsPath = require('./std__path/windows.cjs');
var minimatch = require('minimatch');
var createDebug = require('debug');
var objectSchema = require('@eslint/object-schema');
+function _interopNamespaceDefault(e) {
+ var n = Object.create(null);
+ if (e) {
+ Object.keys(e).forEach(function (k) {
+ if (k !== 'default') {
+ var d = Object.getOwnPropertyDescriptor(e, k);
+ Object.defineProperty(n, k, d.get ? d : {
+ enumerable: true,
+ get: function () { return e[k]; }
+ });
+ }
+ });
+ }
+ n.default = e;
+ return Object.freeze(n);
+}
+
+var posixPath__namespace = /*#__PURE__*/_interopNamespaceDefault(posixPath);
+var windowsPath__namespace = /*#__PURE__*/_interopNamespaceDefault(windowsPath);
+
/**
* @fileoverview ConfigSchema
* @author Nicholas C. Zakas
@@ -170,6 +191,7 @@ const filesAndIgnoresSchema = Object.freeze({
/** @typedef {import("./types.ts").ConfigObject} ConfigObject */
/** @typedef {import("minimatch").IMinimatchStatic} IMinimatchStatic */
/** @typedef {import("minimatch").IMinimatch} IMinimatch */
+/** @typedef {import("@jsr/std__path")} PathImpl */
/*
* This is a bit of a hack to make TypeScript happy with the Rollup-created
@@ -235,6 +257,9 @@ const CONFIG_WITH_STATUS_UNCONFIGURED = Object.freeze({
status: "unconfigured",
});
+// Match two leading dots followed by a slash or the end of input.
+const EXTERNAL_PATH_REGEX = /^\.\.(?:\/|$)/u;
+
/**
* Wrapper error for config validation errors that adds a name to the front of the
* error message.
@@ -493,16 +518,12 @@ function normalizeSync(items, context, extraConfigTypes) {
* Determines if a given file path should be ignored based on the given
* matcher.
* @param {Array boolean)>} ignores The ignore patterns to check.
- * @param {string} filePath The absolute path of the file to check.
- * @param {string} relativeFilePath The relative path of the file to check.
+ * @param {string} filePath The unprocessed file path to check.
+ * @param {string} relativeFilePath The path of the file to check relative to the base path,
+ * using forward slash (`"/"`) as a separator.
* @returns {boolean} True if the path should be ignored and false if not.
*/
function shouldIgnorePath(ignores, filePath, relativeFilePath) {
- // all files outside of the basePath are ignored
- if (relativeFilePath.startsWith("..")) {
- return true;
- }
-
return ignores.reduce((ignored, matcher) => {
if (!ignored) {
if (typeof matcher === "function") {
@@ -532,20 +553,14 @@ function shouldIgnorePath(ignores, filePath, relativeFilePath) {
/**
* Determines if a given file path is matched by a config based on
* `ignores` only.
- * @param {string} filePath The absolute file path to check.
- * @param {string} basePath The base path for the config.
+ * @param {string} filePath The unprocessed file path to check.
+ * @param {string} relativeFilePath The path of the file to check relative to the base path,
+ * using forward slash (`"/"`) as a separator.
* @param {Object} config The config object to check.
* @returns {boolean} True if the file path is matched by the config,
* false if not.
*/
-function pathMatchesIgnores(filePath, basePath, config) {
- /*
- * For both files and ignores, functions are passed the absolute
- * file path while strings are compared against the relative
- * file path.
- */
- const relativeFilePath = path.relative(basePath, filePath);
-
+function pathMatchesIgnores(filePath, relativeFilePath, config) {
return (
Object.keys(config).filter(key => !META_FIELDS.has(key)).length > 1 &&
!shouldIgnorePath(config.ignores, filePath, relativeFilePath)
@@ -557,20 +572,14 @@ function pathMatchesIgnores(filePath, basePath, config) {
* has no `files` field, then it matches; otherwise, if a `files` field
* is present then we match the globs in `files` and exclude any globs in
* `ignores`.
- * @param {string} filePath The absolute file path to check.
- * @param {string} basePath The base path for the config.
+ * @param {string} filePath The unprocessed file path to check.
+ * @param {string} relativeFilePath The path of the file to check relative to the base path,
+ * using forward slash (`"/"`) as a separator.
* @param {Object} config The config object to check.
* @returns {boolean} True if the file path is matched by the config,
* false if not.
*/
-function pathMatches(filePath, basePath, config) {
- /*
- * For both files and ignores, functions are passed the absolute
- * file path while strings are compared against the relative
- * file path.
- */
- const relativeFilePath = path.relative(basePath, filePath);
-
+function pathMatches(filePath, relativeFilePath, config) {
// match both strings and functions
function match(pattern) {
if (isString(pattern)) {
@@ -645,6 +654,44 @@ function assertExtraConfigTypes(extraConfigTypes) {
}
}
+/**
+ * Returns path-handling implementations for Unix or Windows, depending on a given absolute path.
+ * @param {string} fileOrDirPath The absolute path to check.
+ * @returns {PathImpl} Path-handling implementations for the specified path.
+ * @throws An error is thrown if the specified argument is not an absolute path.
+ */
+function getPathImpl(fileOrDirPath) {
+ // Posix absolute paths always start with a slash.
+ if (fileOrDirPath.startsWith("/")) {
+ return posixPath__namespace;
+ }
+
+ // Windows absolute paths start with a letter followed by a colon and at least one backslash,
+ // or with two backslashes in the case of UNC paths.
+ // Forward slashed are automatically normalized to backslashes.
+ if (/^(?:[A-Za-z]:[/\\]|[/\\]{2})/u.test(fileOrDirPath)) {
+ return windowsPath__namespace;
+ }
+
+ throw new Error(
+ `Expected an absolute path but received "${fileOrDirPath}"`,
+ );
+}
+
+/**
+ * Converts a given path to a relative path with all separator characters replaced by forward slashes (`"/"`).
+ * @param {string} fileOrDirPath The unprocessed path to convert.
+ * @param {string} namespacedBasePath The namespaced base path of the directory to which the calculated path shall be relative.
+ * @param {PathImpl} path Path-handling implementations.
+ * @returns {string} A relative path with all separator characters replaced by forward slashes.
+ */
+function toRelativePath(fileOrDirPath, namespacedBasePath, path) {
+ const fullPath = path.resolve(namespacedBasePath, fileOrDirPath);
+ const namespacedFullPath = path.toNamespacedPath(fullPath);
+ const relativePath = path.relative(namespacedBasePath, namespacedFullPath);
+ return relativePath.replaceAll(path.SEPARATOR, "/");
+}
+
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
@@ -665,12 +712,25 @@ const dataCache = new WeakMap();
* those config objects.
*/
class ConfigArray extends Array {
+ /**
+ * The namespaced path of the config file directory.
+ * @type {string}
+ */
+ #namespacedBasePath;
+
+ /**
+ * Path-handling implementations.
+ * @type {PathImpl}
+ */
+ #path;
+
/**
* Creates a new instance of ConfigArray.
* @param {Iterable|Function|Object} configs An iterable yielding config
* objects, or a config function, or a config object.
* @param {Object} options The options for the ConfigArray.
- * @param {string} [options.basePath=""] The path of the config file
+ * @param {string} [options.basePath="/"] The absolute path of the config file directory.
+ * Defaults to `"/"`.
* @param {boolean} [options.normalized=false] Flag indicating if the
* configs have already been normalized.
* @param {Object} [options.schema] The additional schema
@@ -680,7 +740,7 @@ class ConfigArray extends Array {
constructor(
configs,
{
- basePath = "",
+ basePath = "/",
normalized = false,
schema: customSchema,
extraConfigTypes = [],
@@ -706,6 +766,10 @@ class ConfigArray extends Array {
Object.assign({}, customSchema, baseSchema),
);
+ if (!isString(basePath) || !basePath) {
+ throw new TypeError("basePath must be a non-empty string");
+ }
+
/**
* The path of the config file that this array was loaded from.
* This is used to calculate filename matches.
@@ -745,6 +809,14 @@ class ConfigArray extends Array {
} else {
this.push(configs);
}
+
+ // select path-handling implementations depending on the base path
+ this.#path = getPathImpl(basePath);
+
+ // On Windows, `path.relative()` returns an absolute path when given two paths on different drives.
+ // The namespaced base path is useful to make sure that calculated relative paths are always relative.
+ // On Unix, it is identical to the base path.
+ this.#namespacedBasePath = this.#path.toNamespacedPath(basePath);
}
/**
@@ -932,7 +1004,7 @@ class ConfigArray extends Array {
/**
* Returns the config object for a given file path and a status that can be used to determine why a file has no config.
- * @param {string} filePath The complete path of a file to get a config for.
+ * @param {string} filePath The path of a file to get a config for.
* @returns {{ config?: Object, status: "ignored"|"external"|"unconfigured"|"matched" }}
* An object with an optional property `config` and property `status`.
* `config` is the config object for the specified file as returned by {@linkcode ConfigArray.getConfig},
@@ -950,9 +1022,13 @@ class ConfigArray extends Array {
// check to see if the file is outside the base path
- const relativeFilePath = path.relative(this.basePath, filePath);
+ const relativeFilePath = toRelativePath(
+ filePath,
+ this.#namespacedBasePath,
+ this.#path,
+ );
- if (relativeFilePath.startsWith("..")) {
+ if (EXTERNAL_PATH_REGEX.test(relativeFilePath)) {
debug(`No config for file ${filePath} outside of base path`);
// cache and return result
@@ -963,7 +1039,7 @@ class ConfigArray extends Array {
// next check to see if the file should be ignored
// check if this should be ignored due to its directory
- if (this.isDirectoryIgnored(path.dirname(filePath))) {
+ if (this.isDirectoryIgnored(this.#path.dirname(filePath))) {
debug(`Ignoring ${filePath} based on directory pattern`);
// cache and return result
@@ -988,12 +1064,12 @@ class ConfigArray extends Array {
this.forEach((config, index) => {
if (!config.files) {
if (!config.ignores) {
- debug(`Anonymous universal config found for ${filePath}`);
+ debug(`Universal config found for ${filePath}`);
matchingConfigIndices.push(index);
return;
}
- if (pathMatchesIgnores(filePath, this.basePath, config)) {
+ if (pathMatchesIgnores(filePath, relativeFilePath, config)) {
debug(
`Matching config found for ${filePath} (based on ignores: ${config.ignores})`,
);
@@ -1029,7 +1105,7 @@ class ConfigArray extends Array {
// check that the config matches without the non-universal files first
if (
nonUniversalFiles.length &&
- pathMatches(filePath, this.basePath, {
+ pathMatches(filePath, relativeFilePath, {
files: nonUniversalFiles,
ignores: config.ignores,
})
@@ -1043,7 +1119,7 @@ class ConfigArray extends Array {
// if there wasn't a match then check if it matches with universal files
if (
universalFiles.length &&
- pathMatches(filePath, this.basePath, {
+ pathMatches(filePath, relativeFilePath, {
files: universalFiles,
ignores: config.ignores,
})
@@ -1058,7 +1134,7 @@ class ConfigArray extends Array {
}
// the normal case
- if (pathMatches(filePath, this.basePath, config)) {
+ if (pathMatches(filePath, relativeFilePath, config)) {
debug(`Matching config found for ${filePath}`);
matchingConfigIndices.push(index);
matchFound = true;
@@ -1113,7 +1189,7 @@ class ConfigArray extends Array {
/**
* Returns the config object for a given file path.
- * @param {string} filePath The complete path of a file to get a config for.
+ * @param {string} filePath The path of a file to get a config for.
* @returns {Object|undefined} The config object for this file or `undefined`.
*/
getConfig(filePath) {
@@ -1122,7 +1198,7 @@ class ConfigArray extends Array {
/**
* Determines whether a file has a config or why it doesn't.
- * @param {string} filePath The complete path of the file to check.
+ * @param {string} filePath The path of the file to check.
* @returns {"ignored"|"external"|"unconfigured"|"matched"} One of the following values:
* * `"ignored"`: the file is ignored
* * `"external"`: the file is outside the base path
@@ -1135,7 +1211,7 @@ class ConfigArray extends Array {
/**
* Determines if the given filepath is ignored based on the configs.
- * @param {string} filePath The complete path of a file to check.
+ * @param {string} filePath The path of a file to check.
* @returns {boolean} True if the path is ignored, false if not.
* @deprecated Use `isFileIgnored` instead.
*/
@@ -1145,7 +1221,7 @@ class ConfigArray extends Array {
/**
* Determines if the given filepath is ignored based on the configs.
- * @param {string} filePath The complete path of a file to check.
+ * @param {string} filePath The path of a file to check.
* @returns {boolean} True if the path is ignored, false if not.
*/
isFileIgnored(filePath) {
@@ -1158,7 +1234,7 @@ class ConfigArray extends Array {
* same config. A pattern such as `/foo` be considered to ignore the directory
* while a pattern such as `/foo/**` is not considered to ignore the
* directory because it is matching files.
- * @param {string} directoryPath The complete path of a directory to check.
+ * @param {string} directoryPath The path of a directory to check.
* @returns {boolean} True if the directory is ignored, false if not. Will
* return true for any directory that is not inside of `basePath`.
* @throws {Error} When the `ConfigArray` is not normalized.
@@ -1166,16 +1242,18 @@ class ConfigArray extends Array {
isDirectoryIgnored(directoryPath) {
assertNormalized(this);
- const relativeDirectoryPath = path
- .relative(this.basePath, directoryPath)
- .replace(/\\/gu, "/");
+ const relativeDirectoryPath = toRelativePath(
+ directoryPath,
+ this.#namespacedBasePath,
+ this.#path,
+ );
// basePath directory can never be ignored
if (relativeDirectoryPath === "") {
return false;
}
- if (relativeDirectoryPath.startsWith("..")) {
+ if (EXTERNAL_PATH_REGEX.test(relativeDirectoryPath)) {
return true;
}
@@ -1204,7 +1282,7 @@ class ConfigArray extends Array {
result = shouldIgnorePath(
this.ignores,
- path.join(this.basePath, relativeDirectoryToCheck),
+ this.#path.join(this.basePath, relativeDirectoryToCheck),
relativeDirectoryToCheck,
);
diff --git a/node_modules/@eslint/config-array/dist/cjs/index.d.cts b/node_modules/@eslint/config-array/dist/cjs/index.d.cts
index ee7f48b4a..6fb977e03 100644
--- a/node_modules/@eslint/config-array/dist/cjs/index.d.cts
+++ b/node_modules/@eslint/config-array/dist/cjs/index.d.cts
@@ -4,6 +4,7 @@ export type ObjectDefinition = import("@eslint/object-schema").ObjectDefinition;
export type ConfigObject = import("./types.ts").ConfigObject;
export type IMinimatchStatic = import("minimatch").IMinimatchStatic;
export type IMinimatch = import("minimatch").IMinimatch;
+export type PathImpl = typeof import("@jsr/std__path");
export type ObjectSchemaInstance = import("@eslint/object-schema").ObjectSchema;
/**
* Represents an array of config objects and provides method for working with
@@ -15,7 +16,8 @@ export class ConfigArray extends Array {
* @param {Iterable|Function|Object} configs An iterable yielding config
* objects, or a config function, or a config object.
* @param {Object} options The options for the ConfigArray.
- * @param {string} [options.basePath=""] The path of the config file
+ * @param {string} [options.basePath="/"] The absolute path of the config file directory.
+ * Defaults to `"/"`.
* @param {boolean} [options.normalized=false] Flag indicating if the
* configs have already been normalized.
* @param {Object} [options.schema] The additional schema
@@ -77,7 +79,7 @@ export class ConfigArray extends Array {
normalizeSync(context?: any): ConfigArray;
/**
* Returns the config object for a given file path and a status that can be used to determine why a file has no config.
- * @param {string} filePath The complete path of a file to get a config for.
+ * @param {string} filePath The path of a file to get a config for.
* @returns {{ config?: Object, status: "ignored"|"external"|"unconfigured"|"matched" }}
* An object with an optional property `config` and property `status`.
* `config` is the config object for the specified file as returned by {@linkcode ConfigArray.getConfig},
@@ -89,13 +91,13 @@ export class ConfigArray extends Array {
};
/**
* Returns the config object for a given file path.
- * @param {string} filePath The complete path of a file to get a config for.
+ * @param {string} filePath The path of a file to get a config for.
* @returns {Object|undefined} The config object for this file or `undefined`.
*/
getConfig(filePath: string): any | undefined;
/**
* Determines whether a file has a config or why it doesn't.
- * @param {string} filePath The complete path of the file to check.
+ * @param {string} filePath The path of the file to check.
* @returns {"ignored"|"external"|"unconfigured"|"matched"} One of the following values:
* * `"ignored"`: the file is ignored
* * `"external"`: the file is outside the base path
@@ -105,14 +107,14 @@ export class ConfigArray extends Array {
getConfigStatus(filePath: string): "ignored" | "external" | "unconfigured" | "matched";
/**
* Determines if the given filepath is ignored based on the configs.
- * @param {string} filePath The complete path of a file to check.
+ * @param {string} filePath The path of a file to check.
* @returns {boolean} True if the path is ignored, false if not.
* @deprecated Use `isFileIgnored` instead.
*/
isIgnored(filePath: string): boolean;
/**
* Determines if the given filepath is ignored based on the configs.
- * @param {string} filePath The complete path of a file to check.
+ * @param {string} filePath The path of a file to check.
* @returns {boolean} True if the path is ignored, false if not.
*/
isFileIgnored(filePath: string): boolean;
@@ -122,12 +124,13 @@ export class ConfigArray extends Array {
* same config. A pattern such as `/foo` be considered to ignore the directory
* while a pattern such as `/foo/**` is not considered to ignore the
* directory because it is matching files.
- * @param {string} directoryPath The complete path of a directory to check.
+ * @param {string} directoryPath The path of a directory to check.
* @returns {boolean} True if the directory is ignored, false if not. Will
* return true for any directory that is not inside of `basePath`.
* @throws {Error} When the `ConfigArray` is not normalized.
*/
isDirectoryIgnored(directoryPath: string): boolean;
+ #private;
}
export namespace ConfigArraySymbol {
let isNormalized: symbol;
diff --git a/node_modules/@eslint/config-array/dist/cjs/std__path/posix.cjs b/node_modules/@eslint/config-array/dist/cjs/std__path/posix.cjs
new file mode 100644
index 000000000..036cff9a3
--- /dev/null
+++ b/node_modules/@eslint/config-array/dist/cjs/std__path/posix.cjs
@@ -0,0 +1,1323 @@
+'use strict';
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// Copyright the Browserify authors. MIT License.
+function assertPath(path) {
+ if (typeof path !== "string") {
+ throw new TypeError(`Path must be a string, received "${JSON.stringify(path)}"`);
+ }
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function stripSuffix(name, suffix) {
+ if (suffix.length >= name.length) {
+ return name;
+ }
+ const lenDiff = name.length - suffix.length;
+ for(let i = suffix.length - 1; i >= 0; --i){
+ if (name.charCodeAt(lenDiff + i) !== suffix.charCodeAt(i)) {
+ return name;
+ }
+ }
+ return name.slice(0, -suffix.length);
+}
+function lastPathSegment(path, isSep, start = 0) {
+ let matchedNonSeparator = false;
+ let end = path.length;
+ for(let i = path.length - 1; i >= start; --i){
+ if (isSep(path.charCodeAt(i))) {
+ if (matchedNonSeparator) {
+ start = i + 1;
+ break;
+ }
+ } else if (!matchedNonSeparator) {
+ matchedNonSeparator = true;
+ end = i + 1;
+ }
+ }
+ return path.slice(start, end);
+}
+function assertArgs$1(path, suffix) {
+ assertPath(path);
+ if (path.length === 0) return path;
+ if (typeof suffix !== "string") {
+ throw new TypeError(`Suffix must be a string, received "${JSON.stringify(suffix)}"`);
+ }
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// Copyright the Browserify authors. MIT License.
+// Ported from https://github.com/browserify/path-browserify/
+// This module is browser compatible.
+function stripTrailingSeparators(segment, isSep) {
+ if (segment.length <= 1) {
+ return segment;
+ }
+ let end = segment.length;
+ for(let i = segment.length - 1; i > 0; i--){
+ if (isSep(segment.charCodeAt(i))) {
+ end = i;
+ } else {
+ break;
+ }
+ }
+ return segment.slice(0, end);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// Copyright the Browserify authors. MIT License.
+// Ported from https://github.com/browserify/path-browserify/
+// This module is browser compatible.
+// Alphabet chars.
+// Non-alphabetic chars.
+const CHAR_DOT = 46; /* . */
+const CHAR_FORWARD_SLASH = 47; /* / */
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// Copyright the Browserify authors. MIT License.
+// Ported from https://github.com/browserify/path-browserify/
+// This module is browser compatible.
+function isPosixPathSeparator(code) {
+ return code === CHAR_FORWARD_SLASH;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Return the last portion of a `path`.
+ * Trailing directory separators are ignored, and optional suffix is removed.
+ *
+ * @example Usage
+ * ```ts
+ * import { basename } from "@std/path/posix/basename";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(basename("/home/user/Documents/"), "Documents");
+ * assertEquals(basename("/home/user/Documents/image.png"), "image.png");
+ * assertEquals(basename("/home/user/Documents/image.png", ".png"), "image");
+ * ```
+ *
+ * @example Working with URLs
+ *
+ * Note: This function doesn't automatically strip hash and query parts from
+ * URLs. If your URL contains a hash or query, remove them before passing the
+ * URL to the function. This can be done by passing the URL to `new URL(url)`,
+ * and setting the `hash` and `search` properties to empty strings.
+ *
+ * ```ts
+ * import { basename } from "@std/path/posix/basename";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(basename("https://deno.land/std/path/mod.ts"), "mod.ts");
+ * assertEquals(basename("https://deno.land/std/path/mod.ts", ".ts"), "mod");
+ * assertEquals(basename("https://deno.land/std/path/mod.ts?a=b"), "mod.ts?a=b");
+ * assertEquals(basename("https://deno.land/std/path/mod.ts#header"), "mod.ts#header");
+ * ```
+ *
+ * Note: If you are working with file URLs,
+ * use the new version of `basename` from `@std/path/posix/unstable-basename`.
+ *
+ * @param path The path to extract the name from.
+ * @param suffix The suffix to remove from extracted name.
+ * @returns The extracted name.
+ */ function basename(path, suffix = "") {
+ assertArgs$1(path, suffix);
+ const lastSegment = lastPathSegment(path, isPosixPathSeparator);
+ const strippedSegment = stripTrailingSeparators(lastSegment, isPosixPathSeparator);
+ return suffix ? stripSuffix(strippedSegment, suffix) : strippedSegment;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * The character used to separate entries in the PATH environment variable.
+ */ const DELIMITER = ":";
+/**
+ * The character used to separate components of a file path.
+ */ const SEPARATOR = "/";
+/**
+ * A regular expression that matches one or more path separators.
+ */ const SEPARATOR_PATTERN = /\/+/;
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function assertArg$3(path) {
+ assertPath(path);
+ if (path.length === 0) return ".";
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Return the directory path of a `path`.
+ *
+ * @example Usage
+ * ```ts
+ * import { dirname } from "@std/path/posix/dirname";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(dirname("/home/user/Documents/"), "/home/user");
+ * assertEquals(dirname("/home/user/Documents/image.png"), "/home/user/Documents");
+ * assertEquals(dirname("https://deno.land/std/path/mod.ts"), "https://deno.land/std/path");
+ * ```
+ *
+ * @example Working with URLs
+ *
+ * ```ts
+ * import { dirname } from "@std/path/posix/dirname";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(dirname("https://deno.land/std/path/mod.ts"), "https://deno.land/std/path");
+ * assertEquals(dirname("https://deno.land/std/path/mod.ts?a=b"), "https://deno.land/std/path");
+ * assertEquals(dirname("https://deno.land/std/path/mod.ts#header"), "https://deno.land/std/path");
+ * ```
+ *
+ * Note: If you are working with file URLs,
+ * use the new version of `dirname` from `@std/path/posix/unstable-dirname`.
+ *
+ * @param path The path to get the directory from.
+ * @returns The directory path.
+ */ function dirname(path) {
+ assertArg$3(path);
+ let end = -1;
+ let matchedNonSeparator = false;
+ for(let i = path.length - 1; i >= 1; --i){
+ if (isPosixPathSeparator(path.charCodeAt(i))) {
+ if (matchedNonSeparator) {
+ end = i;
+ break;
+ }
+ } else {
+ matchedNonSeparator = true;
+ }
+ }
+ // No matches. Fallback based on provided path:
+ //
+ // - leading slashes paths
+ // "/foo" => "/"
+ // "///foo" => "/"
+ // - no slash path
+ // "foo" => "."
+ if (end === -1) {
+ return isPosixPathSeparator(path.charCodeAt(0)) ? "/" : ".";
+ }
+ return stripTrailingSeparators(path.slice(0, end), isPosixPathSeparator);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Return the extension of the `path` with leading period.
+ *
+ * @example Usage
+ * ```ts
+ * import { extname } from "@std/path/posix/extname";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(extname("/home/user/Documents/file.ts"), ".ts");
+ * assertEquals(extname("/home/user/Documents/"), "");
+ * assertEquals(extname("/home/user/Documents/image.png"), ".png");
+ * ```
+ *
+ * @example Working with URLs
+ *
+ * Note: This function doesn't automatically strip hash and query parts from
+ * URLs. If your URL contains a hash or query, remove them before passing the
+ * URL to the function. This can be done by passing the URL to `new URL(url)`,
+ * and setting the `hash` and `search` properties to empty strings.
+ *
+ * ```ts
+ * import { extname } from "@std/path/posix/extname";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(extname("https://deno.land/std/path/mod.ts"), ".ts");
+ * assertEquals(extname("https://deno.land/std/path/mod.ts?a=b"), ".ts?a=b");
+ * assertEquals(extname("https://deno.land/std/path/mod.ts#header"), ".ts#header");
+ * ```
+ *
+ * Note: If you are working with file URLs,
+ * use the new version of `extname` from `@std/path/posix/unstable-extname`.
+ *
+ * @param path The path to get the extension from.
+ * @returns The extension (ex. for `file.ts` returns `.ts`).
+ */ function extname(path) {
+ assertPath(path);
+ let startDot = -1;
+ let startPart = 0;
+ let end = -1;
+ let matchedSlash = true;
+ // Track the state of characters (if any) we see before our first dot and
+ // after any path separator we find
+ let preDotState = 0;
+ for(let i = path.length - 1; i >= 0; --i){
+ const code = path.charCodeAt(i);
+ if (isPosixPathSeparator(code)) {
+ // If we reached a path separator that was not part of a set of path
+ // separators at the end of the string, stop now
+ if (!matchedSlash) {
+ startPart = i + 1;
+ break;
+ }
+ continue;
+ }
+ if (end === -1) {
+ // We saw the first non-path separator, mark this as the end of our
+ // extension
+ matchedSlash = false;
+ end = i + 1;
+ }
+ if (code === CHAR_DOT) {
+ // If this is our first dot, mark it as the start of our extension
+ if (startDot === -1) startDot = i;
+ else if (preDotState !== 1) preDotState = 1;
+ } else if (startDot !== -1) {
+ // We saw a non-dot and non-path separator before our dot, so we should
+ // have a good chance at having a non-empty extension
+ preDotState = -1;
+ }
+ }
+ if (startDot === -1 || end === -1 || // We saw a non-dot character immediately before the dot
+ preDotState === 0 || // The (right-most) trimmed path component is exactly '..'
+ preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
+ return "";
+ }
+ return path.slice(startDot, end);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function _format(sep, pathObject) {
+ const dir = pathObject.dir || pathObject.root;
+ const base = pathObject.base || (pathObject.name ?? "") + (pathObject.ext ?? "");
+ if (!dir) return base;
+ if (base === sep) return dir;
+ if (dir === pathObject.root) return dir + base;
+ return dir + sep + base;
+}
+function assertArg$2(pathObject) {
+ if (pathObject === null || typeof pathObject !== "object") {
+ throw new TypeError(`The "pathObject" argument must be of type Object, received type "${typeof pathObject}"`);
+ }
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Generate a path from `ParsedPath` object.
+ *
+ * @example Usage
+ * ```ts
+ * import { format } from "@std/path/posix/format";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const path = format({
+ * root: "/",
+ * dir: "/path/dir",
+ * base: "file.txt",
+ * ext: ".txt",
+ * name: "file"
+ * });
+ * assertEquals(path, "/path/dir/file.txt");
+ * ```
+ *
+ * @param pathObject The path object to format.
+ * @returns The formatted path.
+ */ function format(pathObject) {
+ assertArg$2(pathObject);
+ return _format("/", pathObject);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function assertArg$1(url) {
+ url = url instanceof URL ? url : new URL(url);
+ if (url.protocol !== "file:") {
+ throw new TypeError(`URL must be a file URL: received "${url.protocol}"`);
+ }
+ return url;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Converts a file URL to a path string.
+ *
+ * @example Usage
+ * ```ts
+ * import { fromFileUrl } from "@std/path/posix/from-file-url";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(fromFileUrl(new URL("file:///home/foo")), "/home/foo");
+ * ```
+ *
+ * @param url The file URL to convert.
+ * @returns The path string.
+ */ function fromFileUrl(url) {
+ url = assertArg$1(url);
+ return decodeURIComponent(url.pathname.replace(/%(?![0-9A-Fa-f]{2})/g, "%25"));
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Verifies whether provided path is absolute.
+ *
+ * @example Usage
+ * ```ts
+ * import { isAbsolute } from "@std/path/posix/is-absolute";
+ * import { assert, assertFalse } from "@std/assert";
+ *
+ * assert(isAbsolute("/home/user/Documents/"));
+ * assertFalse(isAbsolute("home/user/Documents/"));
+ * ```
+ *
+ * @param path The path to verify.
+ * @returns Whether the path is absolute.
+ */ function isAbsolute(path) {
+ assertPath(path);
+ return path.length > 0 && isPosixPathSeparator(path.charCodeAt(0));
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function assertArg(path) {
+ assertPath(path);
+ if (path.length === 0) return ".";
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// Copyright the Browserify authors. MIT License.
+// Ported from https://github.com/browserify/path-browserify/
+// This module is browser compatible.
+// Resolves . and .. elements in a path with directory names
+function normalizeString(path, allowAboveRoot, separator, isPathSeparator) {
+ let res = "";
+ let lastSegmentLength = 0;
+ let lastSlash = -1;
+ let dots = 0;
+ let code;
+ for(let i = 0; i <= path.length; ++i){
+ if (i < path.length) code = path.charCodeAt(i);
+ else if (isPathSeparator(code)) break;
+ else code = CHAR_FORWARD_SLASH;
+ if (isPathSeparator(code)) {
+ if (lastSlash === i - 1 || dots === 1) ; else if (lastSlash !== i - 1 && dots === 2) {
+ if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== CHAR_DOT || res.charCodeAt(res.length - 2) !== CHAR_DOT) {
+ if (res.length > 2) {
+ const lastSlashIndex = res.lastIndexOf(separator);
+ if (lastSlashIndex === -1) {
+ res = "";
+ lastSegmentLength = 0;
+ } else {
+ res = res.slice(0, lastSlashIndex);
+ lastSegmentLength = res.length - 1 - res.lastIndexOf(separator);
+ }
+ lastSlash = i;
+ dots = 0;
+ continue;
+ } else if (res.length === 2 || res.length === 1) {
+ res = "";
+ lastSegmentLength = 0;
+ lastSlash = i;
+ dots = 0;
+ continue;
+ }
+ }
+ if (allowAboveRoot) {
+ if (res.length > 0) res += `${separator}..`;
+ else res = "..";
+ lastSegmentLength = 2;
+ }
+ } else {
+ if (res.length > 0) res += separator + path.slice(lastSlash + 1, i);
+ else res = path.slice(lastSlash + 1, i);
+ lastSegmentLength = i - lastSlash - 1;
+ }
+ lastSlash = i;
+ dots = 0;
+ } else if (code === CHAR_DOT && dots !== -1) {
+ ++dots;
+ } else {
+ dots = -1;
+ }
+ }
+ return res;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Normalize the `path`, resolving `'..'` and `'.'` segments.
+ * Note that resolving these segments does not necessarily mean that all will be eliminated.
+ * A `'..'` at the top-level will be preserved, and an empty path is canonically `'.'`.
+ *
+ * @example Usage
+ * ```ts
+ * import { normalize } from "@std/path/posix/normalize";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const path = normalize("/foo/bar//baz/asdf/quux/..");
+ * assertEquals(path, "/foo/bar/baz/asdf");
+ * ```
+ *
+ * @example Working with URLs
+ *
+ * Note: This function will remove the double slashes from a URL's scheme.
+ * Hence, do not pass a full URL to this function. Instead, pass the pathname of
+ * the URL.
+ *
+ * ```ts
+ * import { normalize } from "@std/path/posix/normalize";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const url = new URL("https://deno.land");
+ * url.pathname = normalize("//std//assert//.//mod.ts");
+ * assertEquals(url.href, "https://deno.land/std/assert/mod.ts");
+ *
+ * url.pathname = normalize("std/assert/../async/retry.ts");
+ * assertEquals(url.href, "https://deno.land/std/async/retry.ts");
+ * ```
+ *
+ * Note: If you are working with file URLs,
+ * use the new version of `normalize` from `@std/path/posix/unstable-normalize`.
+ *
+ * @param path The path to normalize.
+ * @returns The normalized path.
+ */ function normalize(path) {
+ assertArg(path);
+ const isAbsolute = isPosixPathSeparator(path.charCodeAt(0));
+ const trailingSeparator = isPosixPathSeparator(path.charCodeAt(path.length - 1));
+ // Normalize the path
+ path = normalizeString(path, !isAbsolute, "/", isPosixPathSeparator);
+ if (path.length === 0 && !isAbsolute) path = ".";
+ if (path.length > 0 && trailingSeparator) path += "/";
+ if (isAbsolute) return `/${path}`;
+ return path;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Join all given a sequence of `paths`,then normalizes the resulting path.
+ *
+ * @example Usage
+ * ```ts
+ * import { join } from "@std/path/posix/join";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const path = join("/foo", "bar", "baz/asdf", "quux", "..");
+ * assertEquals(path, "/foo/bar/baz/asdf");
+ * ```
+ *
+ * @example Working with URLs
+ * ```ts
+ * import { join } from "@std/path/posix/join";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const url = new URL("https://deno.land");
+ * url.pathname = join("std", "path", "mod.ts");
+ * assertEquals(url.href, "https://deno.land/std/path/mod.ts");
+ *
+ * url.pathname = join("//std", "path/", "/mod.ts");
+ * assertEquals(url.href, "https://deno.land/std/path/mod.ts");
+ * ```
+ *
+ * Note: If you are working with file URLs,
+ * use the new version of `join` from `@std/path/posix/unstable-join`.
+ *
+ * @param paths The paths to join.
+ * @returns The joined path.
+ */ function join(...paths) {
+ if (paths.length === 0) return ".";
+ paths.forEach((path)=>assertPath(path));
+ const joined = paths.filter((path)=>path.length > 0).join("/");
+ return joined === "" ? "." : normalize(joined);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Return a `ParsedPath` object of the `path`.
+ *
+ * @example Usage
+ * ```ts
+ * import { parse } from "@std/path/posix/parse";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const path = parse("/home/user/file.txt");
+ * assertEquals(path, {
+ * root: "/",
+ * dir: "/home/user",
+ * base: "file.txt",
+ * ext: ".txt",
+ * name: "file"
+ * });
+ * ```
+ *
+ * @param path The path to parse.
+ * @returns The parsed path object.
+ */ function parse(path) {
+ assertPath(path);
+ const ret = {
+ root: "",
+ dir: "",
+ base: "",
+ ext: "",
+ name: ""
+ };
+ if (path.length === 0) return ret;
+ const isAbsolute = isPosixPathSeparator(path.charCodeAt(0));
+ let start;
+ if (isAbsolute) {
+ ret.root = "/";
+ start = 1;
+ } else {
+ start = 0;
+ }
+ let startDot = -1;
+ let startPart = 0;
+ let end = -1;
+ let matchedSlash = true;
+ let i = path.length - 1;
+ // Track the state of characters (if any) we see before our first dot and
+ // after any path separator we find
+ let preDotState = 0;
+ // Get non-dir info
+ for(; i >= start; --i){
+ const code = path.charCodeAt(i);
+ if (isPosixPathSeparator(code)) {
+ // If we reached a path separator that was not part of a set of path
+ // separators at the end of the string, stop now
+ if (!matchedSlash) {
+ startPart = i + 1;
+ break;
+ }
+ continue;
+ }
+ if (end === -1) {
+ // We saw the first non-path separator, mark this as the end of our
+ // extension
+ matchedSlash = false;
+ end = i + 1;
+ }
+ if (code === CHAR_DOT) {
+ // If this is our first dot, mark it as the start of our extension
+ if (startDot === -1) startDot = i;
+ else if (preDotState !== 1) preDotState = 1;
+ } else if (startDot !== -1) {
+ // We saw a non-dot and non-path separator before our dot, so we should
+ // have a good chance at having a non-empty extension
+ preDotState = -1;
+ }
+ }
+ if (startDot === -1 || end === -1 || // We saw a non-dot character immediately before the dot
+ preDotState === 0 || // The (right-most) trimmed path component is exactly '..'
+ preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
+ if (end !== -1) {
+ if (startPart === 0 && isAbsolute) {
+ ret.base = ret.name = path.slice(1, end);
+ } else {
+ ret.base = ret.name = path.slice(startPart, end);
+ }
+ }
+ // Fallback to '/' in case there is no basename
+ ret.base = ret.base || "/";
+ } else {
+ if (startPart === 0 && isAbsolute) {
+ ret.name = path.slice(1, startDot);
+ ret.base = path.slice(1, end);
+ } else {
+ ret.name = path.slice(startPart, startDot);
+ ret.base = path.slice(startPart, end);
+ }
+ ret.ext = path.slice(startDot, end);
+ }
+ if (startPart > 0) {
+ ret.dir = stripTrailingSeparators(path.slice(0, startPart - 1), isPosixPathSeparator);
+ } else if (isAbsolute) ret.dir = "/";
+ return ret;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Resolves path segments into a `path`.
+ *
+ * @example Usage
+ * ```ts
+ * import { resolve } from "@std/path/posix/resolve";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const path = resolve("/foo", "bar", "baz/asdf", "quux", "..");
+ * assertEquals(path, "/foo/bar/baz/asdf");
+ * ```
+ *
+ * @param pathSegments The path segments to resolve.
+ * @returns The resolved path.
+ */ function resolve(...pathSegments) {
+ let resolvedPath = "";
+ let resolvedAbsolute = false;
+ for(let i = pathSegments.length - 1; i >= -1 && !resolvedAbsolute; i--){
+ let path;
+ if (i >= 0) path = pathSegments[i];
+ else {
+ // deno-lint-ignore no-explicit-any
+ const { Deno } = globalThis;
+ if (typeof Deno?.cwd !== "function") {
+ throw new TypeError("Resolved a relative path without a current working directory (CWD)");
+ }
+ path = Deno.cwd();
+ }
+ assertPath(path);
+ // Skip empty entries
+ if (path.length === 0) {
+ continue;
+ }
+ resolvedPath = `${path}/${resolvedPath}`;
+ resolvedAbsolute = isPosixPathSeparator(path.charCodeAt(0));
+ }
+ // At this point the path should be resolved to a full absolute path, but
+ // handle relative paths to be safe (might happen when Deno.cwd() fails)
+ // Normalize the path
+ resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute, "/", isPosixPathSeparator);
+ if (resolvedAbsolute) {
+ if (resolvedPath.length > 0) return `/${resolvedPath}`;
+ else return "/";
+ } else if (resolvedPath.length > 0) return resolvedPath;
+ else return ".";
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function assertArgs(from, to) {
+ assertPath(from);
+ assertPath(to);
+ if (from === to) return "";
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Return the relative path from `from` to `to` based on current working directory.
+ *
+ * If `from` and `to` are the same, return an empty string.
+ *
+ * @example Usage
+ * ```ts
+ * import { relative } from "@std/path/posix/relative";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const path = relative("/data/orandea/test/aaa", "/data/orandea/impl/bbb");
+ * assertEquals(path, "../../impl/bbb");
+ * ```
+ *
+ * @param from The path to start from.
+ * @param to The path to reach.
+ * @returns The relative path.
+ */ function relative(from, to) {
+ assertArgs(from, to);
+ from = resolve(from);
+ to = resolve(to);
+ if (from === to) return "";
+ // Trim any leading backslashes
+ let fromStart = 1;
+ const fromEnd = from.length;
+ for(; fromStart < fromEnd; ++fromStart){
+ if (!isPosixPathSeparator(from.charCodeAt(fromStart))) break;
+ }
+ const fromLen = fromEnd - fromStart;
+ // Trim any leading backslashes
+ let toStart = 1;
+ const toEnd = to.length;
+ for(; toStart < toEnd; ++toStart){
+ if (!isPosixPathSeparator(to.charCodeAt(toStart))) break;
+ }
+ const toLen = toEnd - toStart;
+ // Compare paths to find the longest common path from root
+ const length = fromLen < toLen ? fromLen : toLen;
+ let lastCommonSep = -1;
+ let i = 0;
+ for(; i <= length; ++i){
+ if (i === length) {
+ if (toLen > length) {
+ if (isPosixPathSeparator(to.charCodeAt(toStart + i))) {
+ // We get here if `from` is the exact base path for `to`.
+ // For example: from='/foo/bar'; to='/foo/bar/baz'
+ return to.slice(toStart + i + 1);
+ } else if (i === 0) {
+ // We get here if `from` is the root
+ // For example: from='/'; to='/foo'
+ return to.slice(toStart + i);
+ }
+ } else if (fromLen > length) {
+ if (isPosixPathSeparator(from.charCodeAt(fromStart + i))) {
+ // We get here if `to` is the exact base path for `from`.
+ // For example: from='/foo/bar/baz'; to='/foo/bar'
+ lastCommonSep = i;
+ } else if (i === 0) {
+ // We get here if `to` is the root.
+ // For example: from='/foo'; to='/'
+ lastCommonSep = 0;
+ }
+ }
+ break;
+ }
+ const fromCode = from.charCodeAt(fromStart + i);
+ const toCode = to.charCodeAt(toStart + i);
+ if (fromCode !== toCode) break;
+ else if (isPosixPathSeparator(fromCode)) lastCommonSep = i;
+ }
+ let out = "";
+ // Generate the relative path based on the path difference between `to`
+ // and `from`
+ for(i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i){
+ if (i === fromEnd || isPosixPathSeparator(from.charCodeAt(i))) {
+ if (out.length === 0) out += "..";
+ else out += "/..";
+ }
+ }
+ // Lastly, append the rest of the destination (`to`) path that comes after
+ // the common path parts
+ if (out.length > 0) return out + to.slice(toStart + lastCommonSep);
+ else {
+ toStart += lastCommonSep;
+ if (isPosixPathSeparator(to.charCodeAt(toStart))) ++toStart;
+ return to.slice(toStart);
+ }
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+const WHITESPACE_ENCODINGS = {
+ "\u0009": "%09",
+ "\u000A": "%0A",
+ "\u000B": "%0B",
+ "\u000C": "%0C",
+ "\u000D": "%0D",
+ "\u0020": "%20"
+};
+function encodeWhitespace(string) {
+ return string.replaceAll(/[\s]/g, (c)=>{
+ return WHITESPACE_ENCODINGS[c] ?? c;
+ });
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Converts a path string to a file URL.
+ *
+ * @example Usage
+ * ```ts
+ * import { toFileUrl } from "@std/path/posix/to-file-url";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(toFileUrl("/home/foo"), new URL("file:///home/foo"));
+ * assertEquals(toFileUrl("/home/foo bar"), new URL("file:///home/foo%20bar"));
+ * ```
+ *
+ * @param path The path to convert.
+ * @returns The file URL.
+ */ function toFileUrl(path) {
+ if (!isAbsolute(path)) {
+ throw new TypeError(`Path must be absolute: received "${path}"`);
+ }
+ const url = new URL("file:///");
+ url.pathname = encodeWhitespace(path.replace(/%/g, "%25").replace(/\\/g, "%5C"));
+ return url;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Converts a path to a namespaced path. This function returns the path as is on posix.
+ *
+ * @example Usage
+ * ```ts
+ * import { toNamespacedPath } from "@std/path/posix/to-namespaced-path";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(toNamespacedPath("/home/foo"), "/home/foo");
+ * ```
+ *
+ * @param path The path.
+ * @returns The namespaced path.
+ */ function toNamespacedPath(path) {
+ // Non-op on posix systems
+ return path;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function common$1(paths, sep) {
+ const [first = "", ...remaining] = paths;
+ const parts = first.split(sep);
+ let endOfPrefix = parts.length;
+ let append = "";
+ for (const path of remaining){
+ const compare = path.split(sep);
+ if (compare.length <= endOfPrefix) {
+ endOfPrefix = compare.length;
+ append = "";
+ }
+ for(let i = 0; i < endOfPrefix; i++){
+ if (compare[i] !== parts[i]) {
+ endOfPrefix = i;
+ append = i === 0 ? "" : sep;
+ break;
+ }
+ }
+ }
+ return parts.slice(0, endOfPrefix).join(sep) + append;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/** Determines the common path from a set of paths for POSIX systems.
+ *
+ * @example Usage
+ * ```ts
+ * import { common } from "@std/path/posix/common";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const path = common([
+ * "./deno/std/path/mod.ts",
+ * "./deno/std/fs/mod.ts",
+ * ]);
+ * assertEquals(path, "./deno/std/");
+ * ```
+ *
+ * @param paths The paths to compare.
+ * @returns The common path.
+ */ function common(paths) {
+ return common$1(paths, SEPARATOR);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Options for {@linkcode globToRegExp}, {@linkcode joinGlobs},
+ * {@linkcode normalizeGlob} and {@linkcode expandGlob}.
+ */ const REG_EXP_ESCAPE_CHARS = [
+ "!",
+ "$",
+ "(",
+ ")",
+ "*",
+ "+",
+ ".",
+ "=",
+ "?",
+ "[",
+ "\\",
+ "^",
+ "{",
+ "|"
+];
+const RANGE_ESCAPE_CHARS = [
+ "-",
+ "\\",
+ "]"
+];
+function _globToRegExp(c, glob, { extended = true, globstar: globstarOption = true, // os = osType,
+caseInsensitive = false } = {}) {
+ if (glob === "") {
+ return /(?!)/;
+ }
+ // Remove trailing separators.
+ let newLength = glob.length;
+ for(; newLength > 1 && c.seps.includes(glob[newLength - 1]); newLength--);
+ glob = glob.slice(0, newLength);
+ let regExpString = "";
+ // Terminates correctly. Trust that `j` is incremented every iteration.
+ for(let j = 0; j < glob.length;){
+ let segment = "";
+ const groupStack = [];
+ let inRange = false;
+ let inEscape = false;
+ let endsWithSep = false;
+ let i = j;
+ // Terminates with `i` at the non-inclusive end of the current segment.
+ for(; i < glob.length && !c.seps.includes(glob[i]); i++){
+ if (inEscape) {
+ inEscape = false;
+ const escapeChars = inRange ? RANGE_ESCAPE_CHARS : REG_EXP_ESCAPE_CHARS;
+ segment += escapeChars.includes(glob[i]) ? `\\${glob[i]}` : glob[i];
+ continue;
+ }
+ if (glob[i] === c.escapePrefix) {
+ inEscape = true;
+ continue;
+ }
+ if (glob[i] === "[") {
+ if (!inRange) {
+ inRange = true;
+ segment += "[";
+ if (glob[i + 1] === "!") {
+ i++;
+ segment += "^";
+ } else if (glob[i + 1] === "^") {
+ i++;
+ segment += "\\^";
+ }
+ continue;
+ } else if (glob[i + 1] === ":") {
+ let k = i + 1;
+ let value = "";
+ while(glob[k + 1] !== undefined && glob[k + 1] !== ":"){
+ value += glob[k + 1];
+ k++;
+ }
+ if (glob[k + 1] === ":" && glob[k + 2] === "]") {
+ i = k + 2;
+ if (value === "alnum") segment += "\\dA-Za-z";
+ else if (value === "alpha") segment += "A-Za-z";
+ else if (value === "ascii") segment += "\x00-\x7F";
+ else if (value === "blank") segment += "\t ";
+ else if (value === "cntrl") segment += "\x00-\x1F\x7F";
+ else if (value === "digit") segment += "\\d";
+ else if (value === "graph") segment += "\x21-\x7E";
+ else if (value === "lower") segment += "a-z";
+ else if (value === "print") segment += "\x20-\x7E";
+ else if (value === "punct") {
+ segment += "!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_‘{|}~";
+ } else if (value === "space") segment += "\\s\v";
+ else if (value === "upper") segment += "A-Z";
+ else if (value === "word") segment += "\\w";
+ else if (value === "xdigit") segment += "\\dA-Fa-f";
+ continue;
+ }
+ }
+ }
+ if (glob[i] === "]" && inRange) {
+ inRange = false;
+ segment += "]";
+ continue;
+ }
+ if (inRange) {
+ segment += glob[i];
+ continue;
+ }
+ if (glob[i] === ")" && groupStack.length > 0 && groupStack[groupStack.length - 1] !== "BRACE") {
+ segment += ")";
+ const type = groupStack.pop();
+ if (type === "!") {
+ segment += c.wildcard;
+ } else if (type !== "@") {
+ segment += type;
+ }
+ continue;
+ }
+ if (glob[i] === "|" && groupStack.length > 0 && groupStack[groupStack.length - 1] !== "BRACE") {
+ segment += "|";
+ continue;
+ }
+ if (glob[i] === "+" && extended && glob[i + 1] === "(") {
+ i++;
+ groupStack.push("+");
+ segment += "(?:";
+ continue;
+ }
+ if (glob[i] === "@" && extended && glob[i + 1] === "(") {
+ i++;
+ groupStack.push("@");
+ segment += "(?:";
+ continue;
+ }
+ if (glob[i] === "?") {
+ if (extended && glob[i + 1] === "(") {
+ i++;
+ groupStack.push("?");
+ segment += "(?:";
+ } else {
+ segment += ".";
+ }
+ continue;
+ }
+ if (glob[i] === "!" && extended && glob[i + 1] === "(") {
+ i++;
+ groupStack.push("!");
+ segment += "(?!";
+ continue;
+ }
+ if (glob[i] === "{") {
+ groupStack.push("BRACE");
+ segment += "(?:";
+ continue;
+ }
+ if (glob[i] === "}" && groupStack[groupStack.length - 1] === "BRACE") {
+ groupStack.pop();
+ segment += ")";
+ continue;
+ }
+ if (glob[i] === "," && groupStack[groupStack.length - 1] === "BRACE") {
+ segment += "|";
+ continue;
+ }
+ if (glob[i] === "*") {
+ if (extended && glob[i + 1] === "(") {
+ i++;
+ groupStack.push("*");
+ segment += "(?:";
+ } else {
+ const prevChar = glob[i - 1];
+ let numStars = 1;
+ while(glob[i + 1] === "*"){
+ i++;
+ numStars++;
+ }
+ const nextChar = glob[i + 1];
+ if (globstarOption && numStars === 2 && [
+ ...c.seps,
+ undefined
+ ].includes(prevChar) && [
+ ...c.seps,
+ undefined
+ ].includes(nextChar)) {
+ segment += c.globstar;
+ endsWithSep = true;
+ } else {
+ segment += c.wildcard;
+ }
+ }
+ continue;
+ }
+ segment += REG_EXP_ESCAPE_CHARS.includes(glob[i]) ? `\\${glob[i]}` : glob[i];
+ }
+ // Check for unclosed groups or a dangling backslash.
+ if (groupStack.length > 0 || inRange || inEscape) {
+ // Parse failure. Take all characters from this segment literally.
+ segment = "";
+ for (const c of glob.slice(j, i)){
+ segment += REG_EXP_ESCAPE_CHARS.includes(c) ? `\\${c}` : c;
+ endsWithSep = false;
+ }
+ }
+ regExpString += segment;
+ if (!endsWithSep) {
+ regExpString += i < glob.length ? c.sep : c.sepMaybe;
+ endsWithSep = true;
+ }
+ // Terminates with `i` at the start of the next segment.
+ while(c.seps.includes(glob[i]))i++;
+ j = i;
+ }
+ regExpString = `^${regExpString}$`;
+ return new RegExp(regExpString, caseInsensitive ? "i" : "");
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+const constants = {
+ sep: "/+",
+ sepMaybe: "/*",
+ seps: [
+ "/"
+ ],
+ globstar: "(?:[^/]*(?:/|$)+)*",
+ wildcard: "[^/]*",
+ escapePrefix: "\\"
+};
+/** Convert a glob string to a regular expression.
+ *
+ * Tries to match bash glob expansion as closely as possible.
+ *
+ * Basic glob syntax:
+ * - `*` - Matches everything without leaving the path segment.
+ * - `?` - Matches any single character.
+ * - `{foo,bar}` - Matches `foo` or `bar`.
+ * - `[abcd]` - Matches `a`, `b`, `c` or `d`.
+ * - `[a-d]` - Matches `a`, `b`, `c` or `d`.
+ * - `[!abcd]` - Matches any single character besides `a`, `b`, `c` or `d`.
+ * - `[[::]]` - Matches any character belonging to ``.
+ * - `[[:alnum:]]` - Matches any digit or letter.
+ * - `[[:digit:]abc]` - Matches any digit, `a`, `b` or `c`.
+ * - See https://facelessuser.github.io/wcmatch/glob/#posix-character-classes
+ * for a complete list of supported character classes.
+ * - `\` - Escapes the next character for an `os` other than `"windows"`.
+ * - \` - Escapes the next character for `os` set to `"windows"`.
+ * - `/` - Path separator.
+ * - `\` - Additional path separator only for `os` set to `"windows"`.
+ *
+ * Extended syntax:
+ * - Requires `{ extended: true }`.
+ * - `?(foo|bar)` - Matches 0 or 1 instance of `{foo,bar}`.
+ * - `@(foo|bar)` - Matches 1 instance of `{foo,bar}`. They behave the same.
+ * - `*(foo|bar)` - Matches _n_ instances of `{foo,bar}`.
+ * - `+(foo|bar)` - Matches _n > 0_ instances of `{foo,bar}`.
+ * - `!(foo|bar)` - Matches anything other than `{foo,bar}`.
+ * - See https://www.linuxjournal.com/content/bash-extended-globbing.
+ *
+ * Globstar syntax:
+ * - Requires `{ globstar: true }`.
+ * - `**` - Matches any number of any path segments.
+ * - Must comprise its entire path segment in the provided glob.
+ * - See https://www.linuxjournal.com/content/globstar-new-bash-globbing-option.
+ *
+ * Note the following properties:
+ * - The generated `RegExp` is anchored at both start and end.
+ * - Repeating and trailing separators are tolerated. Trailing separators in the
+ * provided glob have no meaning and are discarded.
+ * - Absolute globs will only match absolute paths, etc.
+ * - Empty globs will match nothing.
+ * - Any special glob syntax must be contained to one path segment. For example,
+ * `?(foo|bar/baz)` is invalid. The separator will take precedence and the
+ * first segment ends with an unclosed group.
+ * - If a path segment ends with unclosed groups or a dangling escape prefix, a
+ * parse error has occurred. Every character for that segment is taken
+ * literally in this event.
+ *
+ * Limitations:
+ * - A negative group like `!(foo|bar)` will wrongly be converted to a negative
+ * look-ahead followed by a wildcard. This means that `!(foo).js` will wrongly
+ * fail to match `foobar.js`, even though `foobar` is not `foo`. Effectively,
+ * `!(foo|bar)` is treated like `!(@(foo|bar)*)`. This will work correctly if
+ * the group occurs not nested at the end of the segment.
+ *
+ * @example Usage
+ * ```ts
+ * import { globToRegExp } from "@std/path/posix/glob-to-regexp";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(globToRegExp("*.js"), /^[^/]*\.js\/*$/);
+ * ```
+ *
+ * @param glob Glob string to convert.
+ * @param options Conversion options.
+ * @returns The regular expression equivalent to the glob.
+ */ function globToRegExp(glob, options = {}) {
+ return _globToRegExp(constants, glob, options);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Test whether the given string is a glob.
+ *
+ * @example Usage
+ * ```ts
+ * import { isGlob } from "@std/path/is-glob";
+ * import { assert } from "@std/assert";
+ *
+ * assert(!isGlob("foo/bar/../baz"));
+ * assert(isGlob("foo/*ar/../baz"));
+ * ```
+ *
+ * @param str String to test.
+ * @returns `true` if the given string is a glob, otherwise `false`
+ */ function isGlob(str) {
+ const chars = {
+ "{": "}",
+ "(": ")",
+ "[": "]"
+ };
+ const regex = /\\(.)|(^!|\*|\?|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/;
+ if (str === "") {
+ return false;
+ }
+ let match;
+ while(match = regex.exec(str)){
+ if (match[2]) return true;
+ let idx = match.index + match[0].length;
+ // if an open bracket/brace/paren is escaped,
+ // set the index to the next closing character
+ const open = match[1];
+ const close = open ? chars[open] : null;
+ if (open && close) {
+ const n = str.indexOf(close, idx);
+ if (n !== -1) {
+ idx = n + 1;
+ }
+ }
+ str = str.slice(idx);
+ }
+ return false;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Like normalize(), but doesn't collapse "**\/.." when `globstar` is true.
+ *
+ * @example Usage
+ * ```ts
+ * import { normalizeGlob } from "@std/path/posix/normalize-glob";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const path = normalizeGlob("foo/bar/../*", { globstar: true });
+ * assertEquals(path, "foo/*");
+ * ```
+ *
+ * @param glob The glob to normalize.
+ * @param options The options to use.
+ * @returns The normalized path.
+ */ function normalizeGlob(glob, { globstar = false } = {}) {
+ if (glob.match(/\0/g)) {
+ throw new Error(`Glob contains invalid characters: "${glob}"`);
+ }
+ if (!globstar) {
+ return normalize(glob);
+ }
+ const s = SEPARATOR_PATTERN.source;
+ const badParentPattern = new RegExp(`(?<=(${s}|^)\\*\\*${s})\\.\\.(?=${s}|$)`, "g");
+ return normalize(glob.replace(badParentPattern, "\0")).replace(/\0/g, "..");
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Like join(), but doesn't collapse "**\/.." when `globstar` is true.
+ *
+ * @example Usage
+ * ```ts
+ * import { joinGlobs } from "@std/path/posix/join-globs";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const path = joinGlobs(["foo", "bar", "**"], { globstar: true });
+ * assertEquals(path, "foo/bar/**");
+ * ```
+ *
+ * @param globs The globs to join.
+ * @param options The options to use.
+ * @returns The joined path.
+ */ function joinGlobs(globs, { extended = true, globstar = false } = {}) {
+ if (!globstar || globs.length === 0) {
+ return join(...globs);
+ }
+ let joined;
+ for (const glob of globs){
+ const path = glob;
+ if (path.length > 0) {
+ if (!joined) joined = path;
+ else joined += `${SEPARATOR}${path}`;
+ }
+ }
+ if (!joined) return ".";
+ return normalizeGlob(joined, {
+ extended,
+ globstar
+ });
+}
+
+exports.DELIMITER = DELIMITER;
+exports.SEPARATOR = SEPARATOR;
+exports.SEPARATOR_PATTERN = SEPARATOR_PATTERN;
+exports.basename = basename;
+exports.common = common;
+exports.dirname = dirname;
+exports.extname = extname;
+exports.format = format;
+exports.fromFileUrl = fromFileUrl;
+exports.globToRegExp = globToRegExp;
+exports.isAbsolute = isAbsolute;
+exports.isGlob = isGlob;
+exports.join = join;
+exports.joinGlobs = joinGlobs;
+exports.normalize = normalize;
+exports.normalizeGlob = normalizeGlob;
+exports.parse = parse;
+exports.relative = relative;
+exports.resolve = resolve;
+exports.toFileUrl = toFileUrl;
+exports.toNamespacedPath = toNamespacedPath;
diff --git a/node_modules/@eslint/config-array/dist/cjs/std__path/windows.cjs b/node_modules/@eslint/config-array/dist/cjs/std__path/windows.cjs
new file mode 100644
index 000000000..956165954
--- /dev/null
+++ b/node_modules/@eslint/config-array/dist/cjs/std__path/windows.cjs
@@ -0,0 +1,1669 @@
+'use strict';
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// Copyright the Browserify authors. MIT License.
+function assertPath(path) {
+ if (typeof path !== "string") {
+ throw new TypeError(`Path must be a string, received "${JSON.stringify(path)}"`);
+ }
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function stripSuffix(name, suffix) {
+ if (suffix.length >= name.length) {
+ return name;
+ }
+ const lenDiff = name.length - suffix.length;
+ for(let i = suffix.length - 1; i >= 0; --i){
+ if (name.charCodeAt(lenDiff + i) !== suffix.charCodeAt(i)) {
+ return name;
+ }
+ }
+ return name.slice(0, -suffix.length);
+}
+function lastPathSegment(path, isSep, start = 0) {
+ let matchedNonSeparator = false;
+ let end = path.length;
+ for(let i = path.length - 1; i >= start; --i){
+ if (isSep(path.charCodeAt(i))) {
+ if (matchedNonSeparator) {
+ start = i + 1;
+ break;
+ }
+ } else if (!matchedNonSeparator) {
+ matchedNonSeparator = true;
+ end = i + 1;
+ }
+ }
+ return path.slice(start, end);
+}
+function assertArgs$1(path, suffix) {
+ assertPath(path);
+ if (path.length === 0) return path;
+ if (typeof suffix !== "string") {
+ throw new TypeError(`Suffix must be a string, received "${JSON.stringify(suffix)}"`);
+ }
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// Copyright the Browserify authors. MIT License.
+// Ported from https://github.com/browserify/path-browserify/
+// This module is browser compatible.
+// Alphabet chars.
+const CHAR_UPPERCASE_A = 65; /* A */
+const CHAR_LOWERCASE_A = 97; /* a */
+const CHAR_UPPERCASE_Z = 90; /* Z */
+const CHAR_LOWERCASE_Z = 122; /* z */
+// Non-alphabetic chars.
+const CHAR_DOT = 46; /* . */
+const CHAR_FORWARD_SLASH = 47; /* / */
+const CHAR_BACKWARD_SLASH = 92; /* \ */
+const CHAR_COLON = 58; /* : */
+const CHAR_QUESTION_MARK = 63; /* ? */
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// Copyright the Browserify authors. MIT License.
+// Ported from https://github.com/browserify/path-browserify/
+// This module is browser compatible.
+function stripTrailingSeparators(segment, isSep) {
+ if (segment.length <= 1) {
+ return segment;
+ }
+ let end = segment.length;
+ for(let i = segment.length - 1; i > 0; i--){
+ if (isSep(segment.charCodeAt(i))) {
+ end = i;
+ } else {
+ break;
+ }
+ }
+ return segment.slice(0, end);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// Copyright the Browserify authors. MIT License.
+// Ported from https://github.com/browserify/path-browserify/
+// This module is browser compatible.
+function isPosixPathSeparator(code) {
+ return code === CHAR_FORWARD_SLASH;
+}
+function isPathSeparator(code) {
+ return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;
+}
+function isWindowsDeviceRoot(code) {
+ return code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z || code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Return the last portion of a `path`.
+ * Trailing directory separators are ignored, and optional suffix is removed.
+ *
+ * @example Usage
+ * ```ts
+ * import { basename } from "@std/path/windows/basename";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(basename("C:\\user\\Documents\\"), "Documents");
+ * assertEquals(basename("C:\\user\\Documents\\image.png"), "image.png");
+ * assertEquals(basename("C:\\user\\Documents\\image.png", ".png"), "image");
+ * ```
+ *
+ * Note: If you are working with file URLs,
+ * use the new version of `basename` from `@std/path/windows/unstable-basename`.
+ *
+ * @param path The path to extract the name from.
+ * @param suffix The suffix to remove from extracted name.
+ * @returns The extracted name.
+ */ function basename(path, suffix = "") {
+ assertArgs$1(path, suffix);
+ // Check for a drive letter prefix so as not to mistake the following
+ // path separator as an extra separator at the end of the path that can be
+ // disregarded
+ let start = 0;
+ if (path.length >= 2) {
+ const drive = path.charCodeAt(0);
+ if (isWindowsDeviceRoot(drive)) {
+ if (path.charCodeAt(1) === CHAR_COLON) start = 2;
+ }
+ }
+ const lastSegment = lastPathSegment(path, isPathSeparator, start);
+ const strippedSegment = stripTrailingSeparators(lastSegment, isPathSeparator);
+ return suffix ? stripSuffix(strippedSegment, suffix) : strippedSegment;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * The character used to separate entries in the PATH environment variable.
+ */ const DELIMITER = ";";
+/**
+ * The character used to separate components of a file path.
+ */ const SEPARATOR = "\\";
+/**
+ * A regular expression that matches one or more path separators.
+ */ const SEPARATOR_PATTERN = /[\\/]+/;
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function assertArg$3(path) {
+ assertPath(path);
+ if (path.length === 0) return ".";
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Return the directory path of a `path`.
+ *
+ * @example Usage
+ * ```ts
+ * import { dirname } from "@std/path/windows/dirname";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const dir = dirname("C:\\foo\\bar\\baz.ext");
+ * assertEquals(dir, "C:\\foo\\bar");
+ * ```
+ *
+ * Note: If you are working with file URLs,
+ * use the new version of `dirname` from `@std/path/windows/unstable-dirname`.
+ *
+ * @param path The path to get the directory from.
+ * @returns The directory path.
+ */ function dirname(path) {
+ assertArg$3(path);
+ const len = path.length;
+ let rootEnd = -1;
+ let end = -1;
+ let matchedSlash = true;
+ let offset = 0;
+ const code = path.charCodeAt(0);
+ // Try to match a root
+ if (len > 1) {
+ if (isPathSeparator(code)) {
+ // Possible UNC root
+ rootEnd = offset = 1;
+ if (isPathSeparator(path.charCodeAt(1))) {
+ // Matched double path separator at beginning
+ let j = 2;
+ let last = j;
+ // Match 1 or more non-path separators
+ for(; j < len; ++j){
+ if (isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j < len && j !== last) {
+ // Matched!
+ last = j;
+ // Match 1 or more path separators
+ for(; j < len; ++j){
+ if (!isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j < len && j !== last) {
+ // Matched!
+ last = j;
+ // Match 1 or more non-path separators
+ for(; j < len; ++j){
+ if (isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j === len) {
+ // We matched a UNC root only
+ return path;
+ }
+ if (j !== last) {
+ // We matched a UNC root with leftovers
+ // Offset by 1 to include the separator after the UNC root to
+ // treat it as a "normal root" on top of a (UNC) root
+ rootEnd = offset = j + 1;
+ }
+ }
+ }
+ }
+ } else if (isWindowsDeviceRoot(code)) {
+ // Possible device root
+ if (path.charCodeAt(1) === CHAR_COLON) {
+ rootEnd = offset = 2;
+ if (len > 2) {
+ if (isPathSeparator(path.charCodeAt(2))) rootEnd = offset = 3;
+ }
+ }
+ }
+ } else if (isPathSeparator(code)) {
+ // `path` contains just a path separator, exit early to avoid
+ // unnecessary work
+ return path;
+ }
+ for(let i = len - 1; i >= offset; --i){
+ if (isPathSeparator(path.charCodeAt(i))) {
+ if (!matchedSlash) {
+ end = i;
+ break;
+ }
+ } else {
+ // We saw the first non-path separator
+ matchedSlash = false;
+ }
+ }
+ if (end === -1) {
+ if (rootEnd === -1) return ".";
+ else end = rootEnd;
+ }
+ return stripTrailingSeparators(path.slice(0, end), isPosixPathSeparator);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Return the extension of the `path` with leading period.
+ *
+ * @example Usage
+ * ```ts
+ * import { extname } from "@std/path/windows/extname";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const ext = extname("file.ts");
+ * assertEquals(ext, ".ts");
+ * ```
+ *
+ * Note: If you are working with file URLs,
+ * use the new version of `extname` from `@std/path/windows/unstable-extname`.
+ *
+ * @param path The path to get the extension from.
+ * @returns The extension of the `path`.
+ */ function extname(path) {
+ assertPath(path);
+ let start = 0;
+ let startDot = -1;
+ let startPart = 0;
+ let end = -1;
+ let matchedSlash = true;
+ // Track the state of characters (if any) we see before our first dot and
+ // after any path separator we find
+ let preDotState = 0;
+ // Check for a drive letter prefix so as not to mistake the following
+ // path separator as an extra separator at the end of the path that can be
+ // disregarded
+ if (path.length >= 2 && path.charCodeAt(1) === CHAR_COLON && isWindowsDeviceRoot(path.charCodeAt(0))) {
+ start = startPart = 2;
+ }
+ for(let i = path.length - 1; i >= start; --i){
+ const code = path.charCodeAt(i);
+ if (isPathSeparator(code)) {
+ // If we reached a path separator that was not part of a set of path
+ // separators at the end of the string, stop now
+ if (!matchedSlash) {
+ startPart = i + 1;
+ break;
+ }
+ continue;
+ }
+ if (end === -1) {
+ // We saw the first non-path separator, mark this as the end of our
+ // extension
+ matchedSlash = false;
+ end = i + 1;
+ }
+ if (code === CHAR_DOT) {
+ // If this is our first dot, mark it as the start of our extension
+ if (startDot === -1) startDot = i;
+ else if (preDotState !== 1) preDotState = 1;
+ } else if (startDot !== -1) {
+ // We saw a non-dot and non-path separator before our dot, so we should
+ // have a good chance at having a non-empty extension
+ preDotState = -1;
+ }
+ }
+ if (startDot === -1 || end === -1 || // We saw a non-dot character immediately before the dot
+ preDotState === 0 || // The (right-most) trimmed path component is exactly '..'
+ preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
+ return "";
+ }
+ return path.slice(startDot, end);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function _format(sep, pathObject) {
+ const dir = pathObject.dir || pathObject.root;
+ const base = pathObject.base || (pathObject.name ?? "") + (pathObject.ext ?? "");
+ if (!dir) return base;
+ if (base === sep) return dir;
+ if (dir === pathObject.root) return dir + base;
+ return dir + sep + base;
+}
+function assertArg$2(pathObject) {
+ if (pathObject === null || typeof pathObject !== "object") {
+ throw new TypeError(`The "pathObject" argument must be of type Object, received type "${typeof pathObject}"`);
+ }
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Generate a path from `ParsedPath` object.
+ *
+ * @example Usage
+ * ```ts
+ * import { format } from "@std/path/windows/format";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const path = format({
+ * root: "C:\\",
+ * dir: "C:\\path\\dir",
+ * base: "file.txt",
+ * ext: ".txt",
+ * name: "file"
+ * });
+ * assertEquals(path, "C:\\path\\dir\\file.txt");
+ * ```
+ *
+ * @param pathObject The path object to format.
+ * @returns The formatted path.
+ */ function format(pathObject) {
+ assertArg$2(pathObject);
+ return _format("\\", pathObject);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function assertArg$1(url) {
+ url = url instanceof URL ? url : new URL(url);
+ if (url.protocol !== "file:") {
+ throw new TypeError(`URL must be a file URL: received "${url.protocol}"`);
+ }
+ return url;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Converts a file URL to a path string.
+ *
+ * @example Usage
+ * ```ts
+ * import { fromFileUrl } from "@std/path/windows/from-file-url";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(fromFileUrl("file:///home/foo"), "\\home\\foo");
+ * assertEquals(fromFileUrl("file:///C:/Users/foo"), "C:\\Users\\foo");
+ * assertEquals(fromFileUrl("file://localhost/home/foo"), "\\home\\foo");
+ * ```
+ *
+ * @param url The file URL to convert.
+ * @returns The path string.
+ */ function fromFileUrl(url) {
+ url = assertArg$1(url);
+ let path = decodeURIComponent(url.pathname.replace(/\//g, "\\").replace(/%(?![0-9A-Fa-f]{2})/g, "%25")).replace(/^\\*([A-Za-z]:)(\\|$)/, "$1\\");
+ if (url.hostname !== "") {
+ // Note: The `URL` implementation guarantees that the drive letter and
+ // hostname are mutually exclusive. Otherwise it would not have been valid
+ // to append the hostname and path like this.
+ path = `\\\\${url.hostname}${path}`;
+ }
+ return path;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Verifies whether provided path is absolute.
+ *
+ * @example Usage
+ * ```ts
+ * import { isAbsolute } from "@std/path/windows/is-absolute";
+ * import { assert, assertFalse } from "@std/assert";
+ *
+ * assert(isAbsolute("C:\\foo\\bar"));
+ * assertFalse(isAbsolute("..\\baz"));
+ * ```
+ *
+ * @param path The path to verify.
+ * @returns `true` if the path is absolute, `false` otherwise.
+ */ function isAbsolute(path) {
+ assertPath(path);
+ const len = path.length;
+ if (len === 0) return false;
+ const code = path.charCodeAt(0);
+ if (isPathSeparator(code)) {
+ return true;
+ } else if (isWindowsDeviceRoot(code)) {
+ // Possible device root
+ if (len > 2 && path.charCodeAt(1) === CHAR_COLON) {
+ if (isPathSeparator(path.charCodeAt(2))) return true;
+ }
+ }
+ return false;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function assertArg(path) {
+ assertPath(path);
+ if (path.length === 0) return ".";
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// Copyright the Browserify authors. MIT License.
+// Ported from https://github.com/browserify/path-browserify/
+// This module is browser compatible.
+// Resolves . and .. elements in a path with directory names
+function normalizeString(path, allowAboveRoot, separator, isPathSeparator) {
+ let res = "";
+ let lastSegmentLength = 0;
+ let lastSlash = -1;
+ let dots = 0;
+ let code;
+ for(let i = 0; i <= path.length; ++i){
+ if (i < path.length) code = path.charCodeAt(i);
+ else if (isPathSeparator(code)) break;
+ else code = CHAR_FORWARD_SLASH;
+ if (isPathSeparator(code)) {
+ if (lastSlash === i - 1 || dots === 1) ; else if (lastSlash !== i - 1 && dots === 2) {
+ if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== CHAR_DOT || res.charCodeAt(res.length - 2) !== CHAR_DOT) {
+ if (res.length > 2) {
+ const lastSlashIndex = res.lastIndexOf(separator);
+ if (lastSlashIndex === -1) {
+ res = "";
+ lastSegmentLength = 0;
+ } else {
+ res = res.slice(0, lastSlashIndex);
+ lastSegmentLength = res.length - 1 - res.lastIndexOf(separator);
+ }
+ lastSlash = i;
+ dots = 0;
+ continue;
+ } else if (res.length === 2 || res.length === 1) {
+ res = "";
+ lastSegmentLength = 0;
+ lastSlash = i;
+ dots = 0;
+ continue;
+ }
+ }
+ if (allowAboveRoot) {
+ if (res.length > 0) res += `${separator}..`;
+ else res = "..";
+ lastSegmentLength = 2;
+ }
+ } else {
+ if (res.length > 0) res += separator + path.slice(lastSlash + 1, i);
+ else res = path.slice(lastSlash + 1, i);
+ lastSegmentLength = i - lastSlash - 1;
+ }
+ lastSlash = i;
+ dots = 0;
+ } else if (code === CHAR_DOT && dots !== -1) {
+ ++dots;
+ } else {
+ dots = -1;
+ }
+ }
+ return res;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Normalize the `path`, resolving `'..'` and `'.'` segments.
+ * Note that resolving these segments does not necessarily mean that all will be eliminated.
+ * A `'..'` at the top-level will be preserved, and an empty path is canonically `'.'`.
+ *
+ * @example Usage
+ * ```ts
+ * import { normalize } from "@std/path/windows/normalize";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const normalized = normalize("C:\\foo\\..\\bar");
+ * assertEquals(normalized, "C:\\bar");
+ * ```
+ *
+ * Note: If you are working with file URLs,
+ * use the new version of `normalize` from `@std/path/windows/unstable-normalize`.
+ *
+ * @param path The path to normalize
+ * @returns The normalized path
+ */ function normalize(path) {
+ assertArg(path);
+ const len = path.length;
+ let rootEnd = 0;
+ let device;
+ let isAbsolute = false;
+ const code = path.charCodeAt(0);
+ // Try to match a root
+ if (len > 1) {
+ if (isPathSeparator(code)) {
+ // Possible UNC root
+ // If we started with a separator, we know we at least have an absolute
+ // path of some kind (UNC or otherwise)
+ isAbsolute = true;
+ if (isPathSeparator(path.charCodeAt(1))) {
+ // Matched double path separator at beginning
+ let j = 2;
+ let last = j;
+ // Match 1 or more non-path separators
+ for(; j < len; ++j){
+ if (isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j < len && j !== last) {
+ const firstPart = path.slice(last, j);
+ // Matched!
+ last = j;
+ // Match 1 or more path separators
+ for(; j < len; ++j){
+ if (!isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j < len && j !== last) {
+ // Matched!
+ last = j;
+ // Match 1 or more non-path separators
+ for(; j < len; ++j){
+ if (isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j === len) {
+ // We matched a UNC root only
+ // Return the normalized version of the UNC root since there
+ // is nothing left to process
+ return `\\\\${firstPart}\\${path.slice(last)}\\`;
+ } else if (j !== last) {
+ // We matched a UNC root with leftovers
+ device = `\\\\${firstPart}\\${path.slice(last, j)}`;
+ rootEnd = j;
+ }
+ }
+ }
+ } else {
+ rootEnd = 1;
+ }
+ } else if (isWindowsDeviceRoot(code)) {
+ // Possible device root
+ if (path.charCodeAt(1) === CHAR_COLON) {
+ device = path.slice(0, 2);
+ rootEnd = 2;
+ if (len > 2) {
+ if (isPathSeparator(path.charCodeAt(2))) {
+ // Treat separator following drive name as an absolute path
+ // indicator
+ isAbsolute = true;
+ rootEnd = 3;
+ }
+ }
+ }
+ }
+ } else if (isPathSeparator(code)) {
+ // `path` contains just a path separator, exit early to avoid unnecessary
+ // work
+ return "\\";
+ }
+ let tail;
+ if (rootEnd < len) {
+ tail = normalizeString(path.slice(rootEnd), !isAbsolute, "\\", isPathSeparator);
+ } else {
+ tail = "";
+ }
+ if (tail.length === 0 && !isAbsolute) tail = ".";
+ if (tail.length > 0 && isPathSeparator(path.charCodeAt(len - 1))) {
+ tail += "\\";
+ }
+ if (device === undefined) {
+ if (isAbsolute) {
+ if (tail.length > 0) return `\\${tail}`;
+ else return "\\";
+ }
+ return tail;
+ } else if (isAbsolute) {
+ if (tail.length > 0) return `${device}\\${tail}`;
+ else return `${device}\\`;
+ }
+ return device + tail;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Join all given a sequence of `paths`,then normalizes the resulting path.
+ *
+ * @example Usage
+ * ```ts
+ * import { join } from "@std/path/windows/join";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const joined = join("C:\\foo", "bar", "baz\\..");
+ * assertEquals(joined, "C:\\foo\\bar");
+ * ```
+ *
+ * Note: If you are working with file URLs,
+ * use the new version of `join` from `@std/path/windows/unstable-join`.
+ *
+ * @param paths The paths to join.
+ * @returns The joined path.
+ */ function join(...paths) {
+ paths.forEach((path)=>assertPath(path));
+ paths = paths.filter((path)=>path.length > 0);
+ if (paths.length === 0) return ".";
+ // Make sure that the joined path doesn't start with two slashes, because
+ // normalize() will mistake it for an UNC path then.
+ //
+ // This step is skipped when it is very clear that the user actually
+ // intended to point at an UNC path. This is assumed when the first
+ // non-empty string arguments starts with exactly two slashes followed by
+ // at least one more non-slash character.
+ //
+ // Note that for normalize() to treat a path as an UNC path it needs to
+ // have at least 2 components, so we don't filter for that here.
+ // This means that the user can use join to construct UNC paths from
+ // a server name and a share name; for example:
+ // path.join('//server', 'share') -> '\\\\server\\share\\'
+ let needsReplace = true;
+ let slashCount = 0;
+ const firstPart = paths[0];
+ if (isPathSeparator(firstPart.charCodeAt(0))) {
+ ++slashCount;
+ const firstLen = firstPart.length;
+ if (firstLen > 1) {
+ if (isPathSeparator(firstPart.charCodeAt(1))) {
+ ++slashCount;
+ if (firstLen > 2) {
+ if (isPathSeparator(firstPart.charCodeAt(2))) ++slashCount;
+ else {
+ // We matched a UNC path in the first part
+ needsReplace = false;
+ }
+ }
+ }
+ }
+ }
+ let joined = paths.join("\\");
+ if (needsReplace) {
+ // Find any more consecutive slashes we need to replace
+ for(; slashCount < joined.length; ++slashCount){
+ if (!isPathSeparator(joined.charCodeAt(slashCount))) break;
+ }
+ // Replace the slashes if needed
+ if (slashCount >= 2) joined = `\\${joined.slice(slashCount)}`;
+ }
+ return normalize(joined);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Return a `ParsedPath` object of the `path`.
+ *
+ * @example Usage
+ * ```ts
+ * import { parse } from "@std/path/windows/parse";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const parsed = parse("C:\\foo\\bar\\baz.ext");
+ * assertEquals(parsed, {
+ * root: "C:\\",
+ * dir: "C:\\foo\\bar",
+ * base: "baz.ext",
+ * ext: ".ext",
+ * name: "baz",
+ * });
+ * ```
+ *
+ * @param path The path to parse.
+ * @returns The `ParsedPath` object.
+ */ function parse(path) {
+ assertPath(path);
+ const ret = {
+ root: "",
+ dir: "",
+ base: "",
+ ext: "",
+ name: ""
+ };
+ const len = path.length;
+ if (len === 0) return ret;
+ let rootEnd = 0;
+ let code = path.charCodeAt(0);
+ // Try to match a root
+ if (len > 1) {
+ if (isPathSeparator(code)) {
+ // Possible UNC root
+ rootEnd = 1;
+ if (isPathSeparator(path.charCodeAt(1))) {
+ // Matched double path separator at beginning
+ let j = 2;
+ let last = j;
+ // Match 1 or more non-path separators
+ for(; j < len; ++j){
+ if (isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j < len && j !== last) {
+ // Matched!
+ last = j;
+ // Match 1 or more path separators
+ for(; j < len; ++j){
+ if (!isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j < len && j !== last) {
+ // Matched!
+ last = j;
+ // Match 1 or more non-path separators
+ for(; j < len; ++j){
+ if (isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j === len) {
+ // We matched a UNC root only
+ rootEnd = j;
+ } else if (j !== last) {
+ // We matched a UNC root with leftovers
+ rootEnd = j + 1;
+ }
+ }
+ }
+ }
+ } else if (isWindowsDeviceRoot(code)) {
+ // Possible device root
+ if (path.charCodeAt(1) === CHAR_COLON) {
+ rootEnd = 2;
+ if (len > 2) {
+ if (isPathSeparator(path.charCodeAt(2))) {
+ if (len === 3) {
+ // `path` contains just a drive root, exit early to avoid
+ // unnecessary work
+ ret.root = ret.dir = path;
+ ret.base = "\\";
+ return ret;
+ }
+ rootEnd = 3;
+ }
+ } else {
+ // `path` contains just a relative drive root, exit early to avoid
+ // unnecessary work
+ ret.root = ret.dir = path;
+ return ret;
+ }
+ }
+ }
+ } else if (isPathSeparator(code)) {
+ // `path` contains just a path separator, exit early to avoid
+ // unnecessary work
+ ret.root = ret.dir = path;
+ ret.base = "\\";
+ return ret;
+ }
+ if (rootEnd > 0) ret.root = path.slice(0, rootEnd);
+ let startDot = -1;
+ let startPart = rootEnd;
+ let end = -1;
+ let matchedSlash = true;
+ let i = path.length - 1;
+ // Track the state of characters (if any) we see before our first dot and
+ // after any path separator we find
+ let preDotState = 0;
+ // Get non-dir info
+ for(; i >= rootEnd; --i){
+ code = path.charCodeAt(i);
+ if (isPathSeparator(code)) {
+ // If we reached a path separator that was not part of a set of path
+ // separators at the end of the string, stop now
+ if (!matchedSlash) {
+ startPart = i + 1;
+ break;
+ }
+ continue;
+ }
+ if (end === -1) {
+ // We saw the first non-path separator, mark this as the end of our
+ // extension
+ matchedSlash = false;
+ end = i + 1;
+ }
+ if (code === CHAR_DOT) {
+ // If this is our first dot, mark it as the start of our extension
+ if (startDot === -1) startDot = i;
+ else if (preDotState !== 1) preDotState = 1;
+ } else if (startDot !== -1) {
+ // We saw a non-dot and non-path separator before our dot, so we should
+ // have a good chance at having a non-empty extension
+ preDotState = -1;
+ }
+ }
+ if (startDot === -1 || end === -1 || // We saw a non-dot character immediately before the dot
+ preDotState === 0 || // The (right-most) trimmed path component is exactly '..'
+ preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
+ if (end !== -1) {
+ ret.base = ret.name = path.slice(startPart, end);
+ }
+ } else {
+ ret.name = path.slice(startPart, startDot);
+ ret.base = path.slice(startPart, end);
+ ret.ext = path.slice(startDot, end);
+ }
+ // Fallback to '\' in case there is no basename
+ ret.base = ret.base || "\\";
+ // If the directory is the root, use the entire root as the `dir` including
+ // the trailing slash if any (`C:\abc` -> `C:\`). Otherwise, strip out the
+ // trailing slash (`C:\abc\def` -> `C:\abc`).
+ if (startPart > 0 && startPart !== rootEnd) {
+ ret.dir = path.slice(0, startPart - 1);
+ } else ret.dir = ret.root;
+ return ret;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Resolves path segments into a `path`.
+ *
+ * @example Usage
+ * ```ts
+ * import { resolve } from "@std/path/windows/resolve";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const resolved = resolve("C:\\foo\\bar", "..\\baz");
+ * assertEquals(resolved, "C:\\foo\\baz");
+ * ```
+ *
+ * @param pathSegments The path segments to process to path
+ * @returns The resolved path
+ */ function resolve(...pathSegments) {
+ let resolvedDevice = "";
+ let resolvedTail = "";
+ let resolvedAbsolute = false;
+ for(let i = pathSegments.length - 1; i >= -1; i--){
+ let path;
+ // deno-lint-ignore no-explicit-any
+ const { Deno } = globalThis;
+ if (i >= 0) {
+ path = pathSegments[i];
+ } else if (!resolvedDevice) {
+ if (typeof Deno?.cwd !== "function") {
+ throw new TypeError("Resolved a drive-letter-less path without a current working directory (CWD)");
+ }
+ path = Deno.cwd();
+ } else {
+ if (typeof Deno?.env?.get !== "function" || typeof Deno?.cwd !== "function") {
+ throw new TypeError("Resolved a relative path without a current working directory (CWD)");
+ }
+ path = Deno.cwd();
+ // Verify that a cwd was found and that it actually points
+ // to our drive. If not, default to the drive's root.
+ if (path === undefined || path.slice(0, 3).toLowerCase() !== `${resolvedDevice.toLowerCase()}\\`) {
+ path = `${resolvedDevice}\\`;
+ }
+ }
+ assertPath(path);
+ const len = path.length;
+ // Skip empty entries
+ if (len === 0) continue;
+ let rootEnd = 0;
+ let device = "";
+ let isAbsolute = false;
+ const code = path.charCodeAt(0);
+ // Try to match a root
+ if (len > 1) {
+ if (isPathSeparator(code)) {
+ // Possible UNC root
+ // If we started with a separator, we know we at least have an
+ // absolute path of some kind (UNC or otherwise)
+ isAbsolute = true;
+ if (isPathSeparator(path.charCodeAt(1))) {
+ // Matched double path separator at beginning
+ let j = 2;
+ let last = j;
+ // Match 1 or more non-path separators
+ for(; j < len; ++j){
+ if (isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j < len && j !== last) {
+ const firstPart = path.slice(last, j);
+ // Matched!
+ last = j;
+ // Match 1 or more path separators
+ for(; j < len; ++j){
+ if (!isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j < len && j !== last) {
+ // Matched!
+ last = j;
+ // Match 1 or more non-path separators
+ for(; j < len; ++j){
+ if (isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j === len) {
+ // We matched a UNC root only
+ device = `\\\\${firstPart}\\${path.slice(last)}`;
+ rootEnd = j;
+ } else if (j !== last) {
+ // We matched a UNC root with leftovers
+ device = `\\\\${firstPart}\\${path.slice(last, j)}`;
+ rootEnd = j;
+ }
+ }
+ }
+ } else {
+ rootEnd = 1;
+ }
+ } else if (isWindowsDeviceRoot(code)) {
+ // Possible device root
+ if (path.charCodeAt(1) === CHAR_COLON) {
+ device = path.slice(0, 2);
+ rootEnd = 2;
+ if (len > 2) {
+ if (isPathSeparator(path.charCodeAt(2))) {
+ // Treat separator following drive name as an absolute path
+ // indicator
+ isAbsolute = true;
+ rootEnd = 3;
+ }
+ }
+ }
+ }
+ } else if (isPathSeparator(code)) {
+ // `path` contains just a path separator
+ rootEnd = 1;
+ isAbsolute = true;
+ }
+ if (device.length > 0 && resolvedDevice.length > 0 && device.toLowerCase() !== resolvedDevice.toLowerCase()) {
+ continue;
+ }
+ if (resolvedDevice.length === 0 && device.length > 0) {
+ resolvedDevice = device;
+ }
+ if (!resolvedAbsolute) {
+ resolvedTail = `${path.slice(rootEnd)}\\${resolvedTail}`;
+ resolvedAbsolute = isAbsolute;
+ }
+ if (resolvedAbsolute && resolvedDevice.length > 0) break;
+ }
+ // At this point the path should be resolved to a full absolute path,
+ // but handle relative paths to be safe (might happen when Deno.cwd()
+ // fails)
+ // Normalize the tail path
+ resolvedTail = normalizeString(resolvedTail, !resolvedAbsolute, "\\", isPathSeparator);
+ return resolvedDevice + (resolvedAbsolute ? "\\" : "") + resolvedTail || ".";
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function assertArgs(from, to) {
+ assertPath(from);
+ assertPath(to);
+ if (from === to) return "";
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Return the relative path from `from` to `to` based on current working directory.
+ *
+ * An example in windws, for instance:
+ * from = 'C:\\orandea\\test\\aaa'
+ * to = 'C:\\orandea\\impl\\bbb'
+ * The output of the function should be: '..\\..\\impl\\bbb'
+ *
+ * @example Usage
+ * ```ts
+ * import { relative } from "@std/path/windows/relative";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const relativePath = relative("C:\\foobar\\test\\aaa", "C:\\foobar\\impl\\bbb");
+ * assertEquals(relativePath, "..\\..\\impl\\bbb");
+ * ```
+ *
+ * @param from The path from which to calculate the relative path
+ * @param to The path to which to calculate the relative path
+ * @returns The relative path from `from` to `to`
+ */ function relative(from, to) {
+ assertArgs(from, to);
+ const fromOrig = resolve(from);
+ const toOrig = resolve(to);
+ if (fromOrig === toOrig) return "";
+ from = fromOrig.toLowerCase();
+ to = toOrig.toLowerCase();
+ if (from === to) return "";
+ // Trim any leading backslashes
+ let fromStart = 0;
+ let fromEnd = from.length;
+ for(; fromStart < fromEnd; ++fromStart){
+ if (from.charCodeAt(fromStart) !== CHAR_BACKWARD_SLASH) break;
+ }
+ // Trim trailing backslashes (applicable to UNC paths only)
+ for(; fromEnd - 1 > fromStart; --fromEnd){
+ if (from.charCodeAt(fromEnd - 1) !== CHAR_BACKWARD_SLASH) break;
+ }
+ const fromLen = fromEnd - fromStart;
+ // Trim any leading backslashes
+ let toStart = 0;
+ let toEnd = to.length;
+ for(; toStart < toEnd; ++toStart){
+ if (to.charCodeAt(toStart) !== CHAR_BACKWARD_SLASH) break;
+ }
+ // Trim trailing backslashes (applicable to UNC paths only)
+ for(; toEnd - 1 > toStart; --toEnd){
+ if (to.charCodeAt(toEnd - 1) !== CHAR_BACKWARD_SLASH) break;
+ }
+ const toLen = toEnd - toStart;
+ // Compare paths to find the longest common path from root
+ const length = fromLen < toLen ? fromLen : toLen;
+ let lastCommonSep = -1;
+ let i = 0;
+ for(; i <= length; ++i){
+ if (i === length) {
+ if (toLen > length) {
+ if (to.charCodeAt(toStart + i) === CHAR_BACKWARD_SLASH) {
+ // We get here if `from` is the exact base path for `to`.
+ // For example: from='C:\\foo\\bar'; to='C:\\foo\\bar\\baz'
+ return toOrig.slice(toStart + i + 1);
+ } else if (i === 2) {
+ // We get here if `from` is the device root.
+ // For example: from='C:\\'; to='C:\\foo'
+ return toOrig.slice(toStart + i);
+ }
+ }
+ if (fromLen > length) {
+ if (from.charCodeAt(fromStart + i) === CHAR_BACKWARD_SLASH) {
+ // We get here if `to` is the exact base path for `from`.
+ // For example: from='C:\\foo\\bar'; to='C:\\foo'
+ lastCommonSep = i;
+ } else if (i === 2) {
+ // We get here if `to` is the device root.
+ // For example: from='C:\\foo\\bar'; to='C:\\'
+ lastCommonSep = 3;
+ }
+ }
+ break;
+ }
+ const fromCode = from.charCodeAt(fromStart + i);
+ const toCode = to.charCodeAt(toStart + i);
+ if (fromCode !== toCode) break;
+ else if (fromCode === CHAR_BACKWARD_SLASH) lastCommonSep = i;
+ }
+ // We found a mismatch before the first common path separator was seen, so
+ // return the original `to`.
+ if (i !== length && lastCommonSep === -1) {
+ return toOrig;
+ }
+ let out = "";
+ if (lastCommonSep === -1) lastCommonSep = 0;
+ // Generate the relative path based on the path difference between `to` and
+ // `from`
+ for(i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i){
+ if (i === fromEnd || from.charCodeAt(i) === CHAR_BACKWARD_SLASH) {
+ if (out.length === 0) out += "..";
+ else out += "\\..";
+ }
+ }
+ // Lastly, append the rest of the destination (`to`) path that comes after
+ // the common path parts
+ if (out.length > 0) {
+ return out + toOrig.slice(toStart + lastCommonSep, toEnd);
+ } else {
+ toStart += lastCommonSep;
+ if (toOrig.charCodeAt(toStart) === CHAR_BACKWARD_SLASH) ++toStart;
+ return toOrig.slice(toStart, toEnd);
+ }
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+const WHITESPACE_ENCODINGS = {
+ "\u0009": "%09",
+ "\u000A": "%0A",
+ "\u000B": "%0B",
+ "\u000C": "%0C",
+ "\u000D": "%0D",
+ "\u0020": "%20"
+};
+function encodeWhitespace(string) {
+ return string.replaceAll(/[\s]/g, (c)=>{
+ return WHITESPACE_ENCODINGS[c] ?? c;
+ });
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Converts a path string to a file URL.
+ *
+ * @example Usage
+ * ```ts
+ * import { toFileUrl } from "@std/path/windows/to-file-url";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(toFileUrl("\\home\\foo"), new URL("file:///home/foo"));
+ * assertEquals(toFileUrl("C:\\Users\\foo"), new URL("file:///C:/Users/foo"));
+ * assertEquals(toFileUrl("\\\\127.0.0.1\\home\\foo"), new URL("file://127.0.0.1/home/foo"));
+ * ```
+ * @param path The path to convert.
+ * @returns The file URL.
+ */ function toFileUrl(path) {
+ if (!isAbsolute(path)) {
+ throw new TypeError(`Path must be absolute: received "${path}"`);
+ }
+ const [, hostname, pathname] = path.match(/^(?:[/\\]{2}([^/\\]+)(?=[/\\](?:[^/\\]|$)))?(.*)/);
+ const url = new URL("file:///");
+ url.pathname = encodeWhitespace(pathname.replace(/%/g, "%25"));
+ if (hostname !== undefined && hostname !== "localhost") {
+ url.hostname = hostname;
+ if (!url.hostname) {
+ throw new TypeError(`Invalid hostname: "${url.hostname}"`);
+ }
+ }
+ return url;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Resolves path to a namespace path
+ *
+ * @example Usage
+ * ```ts
+ * import { toNamespacedPath } from "@std/path/windows/to-namespaced-path";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const namespaced = toNamespacedPath("C:\\foo\\bar");
+ * assertEquals(namespaced, "\\\\?\\C:\\foo\\bar");
+ * ```
+ *
+ * @param path The path to resolve to namespaced path
+ * @returns The resolved namespaced path
+ */ function toNamespacedPath(path) {
+ // Note: this will *probably* throw somewhere.
+ if (typeof path !== "string") return path;
+ if (path.length === 0) return "";
+ const resolvedPath = resolve(path);
+ if (resolvedPath.length >= 3) {
+ if (resolvedPath.charCodeAt(0) === CHAR_BACKWARD_SLASH) {
+ // Possible UNC root
+ if (resolvedPath.charCodeAt(1) === CHAR_BACKWARD_SLASH) {
+ const code = resolvedPath.charCodeAt(2);
+ if (code !== CHAR_QUESTION_MARK && code !== CHAR_DOT) {
+ // Matched non-long UNC root, convert the path to a long UNC path
+ return `\\\\?\\UNC\\${resolvedPath.slice(2)}`;
+ }
+ }
+ } else if (isWindowsDeviceRoot(resolvedPath.charCodeAt(0))) {
+ // Possible device root
+ if (resolvedPath.charCodeAt(1) === CHAR_COLON && resolvedPath.charCodeAt(2) === CHAR_BACKWARD_SLASH) {
+ // Matched device root, convert the path to a long UNC path
+ return `\\\\?\\${resolvedPath}`;
+ }
+ }
+ }
+ return path;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function common$1(paths, sep) {
+ const [first = "", ...remaining] = paths;
+ const parts = first.split(sep);
+ let endOfPrefix = parts.length;
+ let append = "";
+ for (const path of remaining){
+ const compare = path.split(sep);
+ if (compare.length <= endOfPrefix) {
+ endOfPrefix = compare.length;
+ append = "";
+ }
+ for(let i = 0; i < endOfPrefix; i++){
+ if (compare[i] !== parts[i]) {
+ endOfPrefix = i;
+ append = i === 0 ? "" : sep;
+ break;
+ }
+ }
+ }
+ return parts.slice(0, endOfPrefix).join(sep) + append;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Determines the common path from a set of paths for Windows systems.
+ *
+ * @example Usage
+ * ```ts
+ * import { common } from "@std/path/windows/common";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const path = common([
+ * "C:\\foo\\bar",
+ * "C:\\foo\\baz",
+ * ]);
+ * assertEquals(path, "C:\\foo\\");
+ * ```
+ *
+ * @param paths The paths to compare.
+ * @returns The common path.
+ */ function common(paths) {
+ return common$1(paths, SEPARATOR);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Options for {@linkcode globToRegExp}, {@linkcode joinGlobs},
+ * {@linkcode normalizeGlob} and {@linkcode expandGlob}.
+ */ const REG_EXP_ESCAPE_CHARS = [
+ "!",
+ "$",
+ "(",
+ ")",
+ "*",
+ "+",
+ ".",
+ "=",
+ "?",
+ "[",
+ "\\",
+ "^",
+ "{",
+ "|"
+];
+const RANGE_ESCAPE_CHARS = [
+ "-",
+ "\\",
+ "]"
+];
+function _globToRegExp(c, glob, { extended = true, globstar: globstarOption = true, // os = osType,
+caseInsensitive = false } = {}) {
+ if (glob === "") {
+ return /(?!)/;
+ }
+ // Remove trailing separators.
+ let newLength = glob.length;
+ for(; newLength > 1 && c.seps.includes(glob[newLength - 1]); newLength--);
+ glob = glob.slice(0, newLength);
+ let regExpString = "";
+ // Terminates correctly. Trust that `j` is incremented every iteration.
+ for(let j = 0; j < glob.length;){
+ let segment = "";
+ const groupStack = [];
+ let inRange = false;
+ let inEscape = false;
+ let endsWithSep = false;
+ let i = j;
+ // Terminates with `i` at the non-inclusive end of the current segment.
+ for(; i < glob.length && !c.seps.includes(glob[i]); i++){
+ if (inEscape) {
+ inEscape = false;
+ const escapeChars = inRange ? RANGE_ESCAPE_CHARS : REG_EXP_ESCAPE_CHARS;
+ segment += escapeChars.includes(glob[i]) ? `\\${glob[i]}` : glob[i];
+ continue;
+ }
+ if (glob[i] === c.escapePrefix) {
+ inEscape = true;
+ continue;
+ }
+ if (glob[i] === "[") {
+ if (!inRange) {
+ inRange = true;
+ segment += "[";
+ if (glob[i + 1] === "!") {
+ i++;
+ segment += "^";
+ } else if (glob[i + 1] === "^") {
+ i++;
+ segment += "\\^";
+ }
+ continue;
+ } else if (glob[i + 1] === ":") {
+ let k = i + 1;
+ let value = "";
+ while(glob[k + 1] !== undefined && glob[k + 1] !== ":"){
+ value += glob[k + 1];
+ k++;
+ }
+ if (glob[k + 1] === ":" && glob[k + 2] === "]") {
+ i = k + 2;
+ if (value === "alnum") segment += "\\dA-Za-z";
+ else if (value === "alpha") segment += "A-Za-z";
+ else if (value === "ascii") segment += "\x00-\x7F";
+ else if (value === "blank") segment += "\t ";
+ else if (value === "cntrl") segment += "\x00-\x1F\x7F";
+ else if (value === "digit") segment += "\\d";
+ else if (value === "graph") segment += "\x21-\x7E";
+ else if (value === "lower") segment += "a-z";
+ else if (value === "print") segment += "\x20-\x7E";
+ else if (value === "punct") {
+ segment += "!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_‘{|}~";
+ } else if (value === "space") segment += "\\s\v";
+ else if (value === "upper") segment += "A-Z";
+ else if (value === "word") segment += "\\w";
+ else if (value === "xdigit") segment += "\\dA-Fa-f";
+ continue;
+ }
+ }
+ }
+ if (glob[i] === "]" && inRange) {
+ inRange = false;
+ segment += "]";
+ continue;
+ }
+ if (inRange) {
+ segment += glob[i];
+ continue;
+ }
+ if (glob[i] === ")" && groupStack.length > 0 && groupStack[groupStack.length - 1] !== "BRACE") {
+ segment += ")";
+ const type = groupStack.pop();
+ if (type === "!") {
+ segment += c.wildcard;
+ } else if (type !== "@") {
+ segment += type;
+ }
+ continue;
+ }
+ if (glob[i] === "|" && groupStack.length > 0 && groupStack[groupStack.length - 1] !== "BRACE") {
+ segment += "|";
+ continue;
+ }
+ if (glob[i] === "+" && extended && glob[i + 1] === "(") {
+ i++;
+ groupStack.push("+");
+ segment += "(?:";
+ continue;
+ }
+ if (glob[i] === "@" && extended && glob[i + 1] === "(") {
+ i++;
+ groupStack.push("@");
+ segment += "(?:";
+ continue;
+ }
+ if (glob[i] === "?") {
+ if (extended && glob[i + 1] === "(") {
+ i++;
+ groupStack.push("?");
+ segment += "(?:";
+ } else {
+ segment += ".";
+ }
+ continue;
+ }
+ if (glob[i] === "!" && extended && glob[i + 1] === "(") {
+ i++;
+ groupStack.push("!");
+ segment += "(?!";
+ continue;
+ }
+ if (glob[i] === "{") {
+ groupStack.push("BRACE");
+ segment += "(?:";
+ continue;
+ }
+ if (glob[i] === "}" && groupStack[groupStack.length - 1] === "BRACE") {
+ groupStack.pop();
+ segment += ")";
+ continue;
+ }
+ if (glob[i] === "," && groupStack[groupStack.length - 1] === "BRACE") {
+ segment += "|";
+ continue;
+ }
+ if (glob[i] === "*") {
+ if (extended && glob[i + 1] === "(") {
+ i++;
+ groupStack.push("*");
+ segment += "(?:";
+ } else {
+ const prevChar = glob[i - 1];
+ let numStars = 1;
+ while(glob[i + 1] === "*"){
+ i++;
+ numStars++;
+ }
+ const nextChar = glob[i + 1];
+ if (globstarOption && numStars === 2 && [
+ ...c.seps,
+ undefined
+ ].includes(prevChar) && [
+ ...c.seps,
+ undefined
+ ].includes(nextChar)) {
+ segment += c.globstar;
+ endsWithSep = true;
+ } else {
+ segment += c.wildcard;
+ }
+ }
+ continue;
+ }
+ segment += REG_EXP_ESCAPE_CHARS.includes(glob[i]) ? `\\${glob[i]}` : glob[i];
+ }
+ // Check for unclosed groups or a dangling backslash.
+ if (groupStack.length > 0 || inRange || inEscape) {
+ // Parse failure. Take all characters from this segment literally.
+ segment = "";
+ for (const c of glob.slice(j, i)){
+ segment += REG_EXP_ESCAPE_CHARS.includes(c) ? `\\${c}` : c;
+ endsWithSep = false;
+ }
+ }
+ regExpString += segment;
+ if (!endsWithSep) {
+ regExpString += i < glob.length ? c.sep : c.sepMaybe;
+ endsWithSep = true;
+ }
+ // Terminates with `i` at the start of the next segment.
+ while(c.seps.includes(glob[i]))i++;
+ j = i;
+ }
+ regExpString = `^${regExpString}$`;
+ return new RegExp(regExpString, caseInsensitive ? "i" : "");
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+const constants = {
+ sep: "(?:\\\\|/)+",
+ sepMaybe: "(?:\\\\|/)*",
+ seps: [
+ "\\",
+ "/"
+ ],
+ globstar: "(?:[^\\\\/]*(?:\\\\|/|$)+)*",
+ wildcard: "[^\\\\/]*",
+ escapePrefix: "`"
+};
+/** Convert a glob string to a regular expression.
+ *
+ * Tries to match bash glob expansion as closely as possible.
+ *
+ * Basic glob syntax:
+ * - `*` - Matches everything without leaving the path segment.
+ * - `?` - Matches any single character.
+ * - `{foo,bar}` - Matches `foo` or `bar`.
+ * - `[abcd]` - Matches `a`, `b`, `c` or `d`.
+ * - `[a-d]` - Matches `a`, `b`, `c` or `d`.
+ * - `[!abcd]` - Matches any single character besides `a`, `b`, `c` or `d`.
+ * - `[[::]]` - Matches any character belonging to ``.
+ * - `[[:alnum:]]` - Matches any digit or letter.
+ * - `[[:digit:]abc]` - Matches any digit, `a`, `b` or `c`.
+ * - See https://facelessuser.github.io/wcmatch/glob/#posix-character-classes
+ * for a complete list of supported character classes.
+ * - `\` - Escapes the next character for an `os` other than `"windows"`.
+ * - \` - Escapes the next character for `os` set to `"windows"`.
+ * - `/` - Path separator.
+ * - `\` - Additional path separator only for `os` set to `"windows"`.
+ *
+ * Extended syntax:
+ * - Requires `{ extended: true }`.
+ * - `?(foo|bar)` - Matches 0 or 1 instance of `{foo,bar}`.
+ * - `@(foo|bar)` - Matches 1 instance of `{foo,bar}`. They behave the same.
+ * - `*(foo|bar)` - Matches _n_ instances of `{foo,bar}`.
+ * - `+(foo|bar)` - Matches _n > 0_ instances of `{foo,bar}`.
+ * - `!(foo|bar)` - Matches anything other than `{foo,bar}`.
+ * - See https://www.linuxjournal.com/content/bash-extended-globbing.
+ *
+ * Globstar syntax:
+ * - Requires `{ globstar: true }`.
+ * - `**` - Matches any number of any path segments.
+ * - Must comprise its entire path segment in the provided glob.
+ * - See https://www.linuxjournal.com/content/globstar-new-bash-globbing-option.
+ *
+ * Note the following properties:
+ * - The generated `RegExp` is anchored at both start and end.
+ * - Repeating and trailing separators are tolerated. Trailing separators in the
+ * provided glob have no meaning and are discarded.
+ * - Absolute globs will only match absolute paths, etc.
+ * - Empty globs will match nothing.
+ * - Any special glob syntax must be contained to one path segment. For example,
+ * `?(foo|bar/baz)` is invalid. The separator will take precedence and the
+ * first segment ends with an unclosed group.
+ * - If a path segment ends with unclosed groups or a dangling escape prefix, a
+ * parse error has occurred. Every character for that segment is taken
+ * literally in this event.
+ *
+ * Limitations:
+ * - A negative group like `!(foo|bar)` will wrongly be converted to a negative
+ * look-ahead followed by a wildcard. This means that `!(foo).js` will wrongly
+ * fail to match `foobar.js`, even though `foobar` is not `foo`. Effectively,
+ * `!(foo|bar)` is treated like `!(@(foo|bar)*)`. This will work correctly if
+ * the group occurs not nested at the end of the segment.
+ *
+ * @example Usage
+ * ```ts
+ * import { globToRegExp } from "@std/path/windows/glob-to-regexp";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(globToRegExp("*.js"), /^[^\\/]*\.js(?:\\|\/)*$/);
+ * ```
+ *
+ * @param glob Glob string to convert.
+ * @param options Conversion options.
+ * @returns The regular expression equivalent to the glob.
+ */ function globToRegExp(glob, options = {}) {
+ return _globToRegExp(constants, glob, options);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Test whether the given string is a glob.
+ *
+ * @example Usage
+ * ```ts
+ * import { isGlob } from "@std/path/is-glob";
+ * import { assert } from "@std/assert";
+ *
+ * assert(!isGlob("foo/bar/../baz"));
+ * assert(isGlob("foo/*ar/../baz"));
+ * ```
+ *
+ * @param str String to test.
+ * @returns `true` if the given string is a glob, otherwise `false`
+ */ function isGlob(str) {
+ const chars = {
+ "{": "}",
+ "(": ")",
+ "[": "]"
+ };
+ const regex = /\\(.)|(^!|\*|\?|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/;
+ if (str === "") {
+ return false;
+ }
+ let match;
+ while(match = regex.exec(str)){
+ if (match[2]) return true;
+ let idx = match.index + match[0].length;
+ // if an open bracket/brace/paren is escaped,
+ // set the index to the next closing character
+ const open = match[1];
+ const close = open ? chars[open] : null;
+ if (open && close) {
+ const n = str.indexOf(close, idx);
+ if (n !== -1) {
+ idx = n + 1;
+ }
+ }
+ str = str.slice(idx);
+ }
+ return false;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Like normalize(), but doesn't collapse "**\/.." when `globstar` is true.
+ *
+ * @example Usage
+ * ```ts
+ * import { normalizeGlob } from "@std/path/windows/normalize-glob";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const normalized = normalizeGlob("**\\foo\\..\\bar", { globstar: true });
+ * assertEquals(normalized, "**\\bar");
+ * ```
+ *
+ * @param glob The glob pattern to normalize.
+ * @param options The options for glob pattern.
+ * @returns The normalized glob pattern.
+ */ function normalizeGlob(glob, { globstar = false } = {}) {
+ if (glob.match(/\0/g)) {
+ throw new Error(`Glob contains invalid characters: "${glob}"`);
+ }
+ if (!globstar) {
+ return normalize(glob);
+ }
+ const s = SEPARATOR_PATTERN.source;
+ const badParentPattern = new RegExp(`(?<=(${s}|^)\\*\\*${s})\\.\\.(?=${s}|$)`, "g");
+ return normalize(glob.replace(badParentPattern, "\0")).replace(/\0/g, "..");
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Like join(), but doesn't collapse "**\/.." when `globstar` is true.
+ *
+ * @example Usage
+ *
+ * ```ts
+ * import { joinGlobs } from "@std/path/windows/join-globs";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const joined = joinGlobs(["foo", "**", "bar"], { globstar: true });
+ * assertEquals(joined, "foo\\**\\bar");
+ * ```
+ *
+ * @param globs The globs to join.
+ * @param options The options for glob pattern.
+ * @returns The joined glob pattern.
+ */ function joinGlobs(globs, { extended = true, globstar = false } = {}) {
+ if (!globstar || globs.length === 0) {
+ return join(...globs);
+ }
+ let joined;
+ for (const glob of globs){
+ const path = glob;
+ if (path.length > 0) {
+ if (!joined) joined = path;
+ else joined += `${SEPARATOR}${path}`;
+ }
+ }
+ if (!joined) return ".";
+ return normalizeGlob(joined, {
+ extended,
+ globstar
+ });
+}
+
+exports.DELIMITER = DELIMITER;
+exports.SEPARATOR = SEPARATOR;
+exports.SEPARATOR_PATTERN = SEPARATOR_PATTERN;
+exports.basename = basename;
+exports.common = common;
+exports.dirname = dirname;
+exports.extname = extname;
+exports.format = format;
+exports.fromFileUrl = fromFileUrl;
+exports.globToRegExp = globToRegExp;
+exports.isAbsolute = isAbsolute;
+exports.isGlob = isGlob;
+exports.join = join;
+exports.joinGlobs = joinGlobs;
+exports.normalize = normalize;
+exports.normalizeGlob = normalizeGlob;
+exports.parse = parse;
+exports.relative = relative;
+exports.resolve = resolve;
+exports.toFileUrl = toFileUrl;
+exports.toNamespacedPath = toNamespacedPath;
diff --git a/node_modules/@eslint/config-array/dist/esm/index.d.ts b/node_modules/@eslint/config-array/dist/esm/index.d.ts
index ee7f48b4a..6fb977e03 100644
--- a/node_modules/@eslint/config-array/dist/esm/index.d.ts
+++ b/node_modules/@eslint/config-array/dist/esm/index.d.ts
@@ -4,6 +4,7 @@ export type ObjectDefinition = import("@eslint/object-schema").ObjectDefinition;
export type ConfigObject = import("./types.ts").ConfigObject;
export type IMinimatchStatic = import("minimatch").IMinimatchStatic;
export type IMinimatch = import("minimatch").IMinimatch;
+export type PathImpl = typeof import("@jsr/std__path");
export type ObjectSchemaInstance = import("@eslint/object-schema").ObjectSchema;
/**
* Represents an array of config objects and provides method for working with
@@ -15,7 +16,8 @@ export class ConfigArray extends Array {
* @param {Iterable|Function|Object} configs An iterable yielding config
* objects, or a config function, or a config object.
* @param {Object} options The options for the ConfigArray.
- * @param {string} [options.basePath=""] The path of the config file
+ * @param {string} [options.basePath="/"] The absolute path of the config file directory.
+ * Defaults to `"/"`.
* @param {boolean} [options.normalized=false] Flag indicating if the
* configs have already been normalized.
* @param {Object} [options.schema] The additional schema
@@ -77,7 +79,7 @@ export class ConfigArray extends Array {
normalizeSync(context?: any): ConfigArray;
/**
* Returns the config object for a given file path and a status that can be used to determine why a file has no config.
- * @param {string} filePath The complete path of a file to get a config for.
+ * @param {string} filePath The path of a file to get a config for.
* @returns {{ config?: Object, status: "ignored"|"external"|"unconfigured"|"matched" }}
* An object with an optional property `config` and property `status`.
* `config` is the config object for the specified file as returned by {@linkcode ConfigArray.getConfig},
@@ -89,13 +91,13 @@ export class ConfigArray extends Array {
};
/**
* Returns the config object for a given file path.
- * @param {string} filePath The complete path of a file to get a config for.
+ * @param {string} filePath The path of a file to get a config for.
* @returns {Object|undefined} The config object for this file or `undefined`.
*/
getConfig(filePath: string): any | undefined;
/**
* Determines whether a file has a config or why it doesn't.
- * @param {string} filePath The complete path of the file to check.
+ * @param {string} filePath The path of the file to check.
* @returns {"ignored"|"external"|"unconfigured"|"matched"} One of the following values:
* * `"ignored"`: the file is ignored
* * `"external"`: the file is outside the base path
@@ -105,14 +107,14 @@ export class ConfigArray extends Array {
getConfigStatus(filePath: string): "ignored" | "external" | "unconfigured" | "matched";
/**
* Determines if the given filepath is ignored based on the configs.
- * @param {string} filePath The complete path of a file to check.
+ * @param {string} filePath The path of a file to check.
* @returns {boolean} True if the path is ignored, false if not.
* @deprecated Use `isFileIgnored` instead.
*/
isIgnored(filePath: string): boolean;
/**
* Determines if the given filepath is ignored based on the configs.
- * @param {string} filePath The complete path of a file to check.
+ * @param {string} filePath The path of a file to check.
* @returns {boolean} True if the path is ignored, false if not.
*/
isFileIgnored(filePath: string): boolean;
@@ -122,12 +124,13 @@ export class ConfigArray extends Array {
* same config. A pattern such as `/foo` be considered to ignore the directory
* while a pattern such as `/foo/**` is not considered to ignore the
* directory because it is matching files.
- * @param {string} directoryPath The complete path of a directory to check.
+ * @param {string} directoryPath The path of a directory to check.
* @returns {boolean} True if the directory is ignored, false if not. Will
* return true for any directory that is not inside of `basePath`.
* @throws {Error} When the `ConfigArray` is not normalized.
*/
isDirectoryIgnored(directoryPath: string): boolean;
+ #private;
}
export namespace ConfigArraySymbol {
let isNormalized: symbol;
diff --git a/node_modules/@eslint/config-array/dist/esm/index.js b/node_modules/@eslint/config-array/dist/esm/index.js
index 42c21ce63..1e68f33e3 100644
--- a/node_modules/@eslint/config-array/dist/esm/index.js
+++ b/node_modules/@eslint/config-array/dist/esm/index.js
@@ -1,5 +1,6 @@
// @ts-self-types="./index.d.ts"
-import path from 'node:path';
+import * as posixPath from './std__path/posix.js';
+import * as windowsPath from './std__path/windows.js';
import minimatch from 'minimatch';
import createDebug from 'debug';
import { ObjectSchema } from '@eslint/object-schema';
@@ -170,6 +171,7 @@ const filesAndIgnoresSchema = Object.freeze({
/** @typedef {import("./types.ts").ConfigObject} ConfigObject */
/** @typedef {import("minimatch").IMinimatchStatic} IMinimatchStatic */
/** @typedef {import("minimatch").IMinimatch} IMinimatch */
+/** @typedef {import("@jsr/std__path")} PathImpl */
/*
* This is a bit of a hack to make TypeScript happy with the Rollup-created
@@ -235,6 +237,9 @@ const CONFIG_WITH_STATUS_UNCONFIGURED = Object.freeze({
status: "unconfigured",
});
+// Match two leading dots followed by a slash or the end of input.
+const EXTERNAL_PATH_REGEX = /^\.\.(?:\/|$)/u;
+
/**
* Wrapper error for config validation errors that adds a name to the front of the
* error message.
@@ -493,16 +498,12 @@ function normalizeSync(items, context, extraConfigTypes) {
* Determines if a given file path should be ignored based on the given
* matcher.
* @param {Array boolean)>} ignores The ignore patterns to check.
- * @param {string} filePath The absolute path of the file to check.
- * @param {string} relativeFilePath The relative path of the file to check.
+ * @param {string} filePath The unprocessed file path to check.
+ * @param {string} relativeFilePath The path of the file to check relative to the base path,
+ * using forward slash (`"/"`) as a separator.
* @returns {boolean} True if the path should be ignored and false if not.
*/
function shouldIgnorePath(ignores, filePath, relativeFilePath) {
- // all files outside of the basePath are ignored
- if (relativeFilePath.startsWith("..")) {
- return true;
- }
-
return ignores.reduce((ignored, matcher) => {
if (!ignored) {
if (typeof matcher === "function") {
@@ -532,20 +533,14 @@ function shouldIgnorePath(ignores, filePath, relativeFilePath) {
/**
* Determines if a given file path is matched by a config based on
* `ignores` only.
- * @param {string} filePath The absolute file path to check.
- * @param {string} basePath The base path for the config.
+ * @param {string} filePath The unprocessed file path to check.
+ * @param {string} relativeFilePath The path of the file to check relative to the base path,
+ * using forward slash (`"/"`) as a separator.
* @param {Object} config The config object to check.
* @returns {boolean} True if the file path is matched by the config,
* false if not.
*/
-function pathMatchesIgnores(filePath, basePath, config) {
- /*
- * For both files and ignores, functions are passed the absolute
- * file path while strings are compared against the relative
- * file path.
- */
- const relativeFilePath = path.relative(basePath, filePath);
-
+function pathMatchesIgnores(filePath, relativeFilePath, config) {
return (
Object.keys(config).filter(key => !META_FIELDS.has(key)).length > 1 &&
!shouldIgnorePath(config.ignores, filePath, relativeFilePath)
@@ -557,20 +552,14 @@ function pathMatchesIgnores(filePath, basePath, config) {
* has no `files` field, then it matches; otherwise, if a `files` field
* is present then we match the globs in `files` and exclude any globs in
* `ignores`.
- * @param {string} filePath The absolute file path to check.
- * @param {string} basePath The base path for the config.
+ * @param {string} filePath The unprocessed file path to check.
+ * @param {string} relativeFilePath The path of the file to check relative to the base path,
+ * using forward slash (`"/"`) as a separator.
* @param {Object} config The config object to check.
* @returns {boolean} True if the file path is matched by the config,
* false if not.
*/
-function pathMatches(filePath, basePath, config) {
- /*
- * For both files and ignores, functions are passed the absolute
- * file path while strings are compared against the relative
- * file path.
- */
- const relativeFilePath = path.relative(basePath, filePath);
-
+function pathMatches(filePath, relativeFilePath, config) {
// match both strings and functions
function match(pattern) {
if (isString(pattern)) {
@@ -645,6 +634,44 @@ function assertExtraConfigTypes(extraConfigTypes) {
}
}
+/**
+ * Returns path-handling implementations for Unix or Windows, depending on a given absolute path.
+ * @param {string} fileOrDirPath The absolute path to check.
+ * @returns {PathImpl} Path-handling implementations for the specified path.
+ * @throws An error is thrown if the specified argument is not an absolute path.
+ */
+function getPathImpl(fileOrDirPath) {
+ // Posix absolute paths always start with a slash.
+ if (fileOrDirPath.startsWith("/")) {
+ return posixPath;
+ }
+
+ // Windows absolute paths start with a letter followed by a colon and at least one backslash,
+ // or with two backslashes in the case of UNC paths.
+ // Forward slashed are automatically normalized to backslashes.
+ if (/^(?:[A-Za-z]:[/\\]|[/\\]{2})/u.test(fileOrDirPath)) {
+ return windowsPath;
+ }
+
+ throw new Error(
+ `Expected an absolute path but received "${fileOrDirPath}"`,
+ );
+}
+
+/**
+ * Converts a given path to a relative path with all separator characters replaced by forward slashes (`"/"`).
+ * @param {string} fileOrDirPath The unprocessed path to convert.
+ * @param {string} namespacedBasePath The namespaced base path of the directory to which the calculated path shall be relative.
+ * @param {PathImpl} path Path-handling implementations.
+ * @returns {string} A relative path with all separator characters replaced by forward slashes.
+ */
+function toRelativePath(fileOrDirPath, namespacedBasePath, path) {
+ const fullPath = path.resolve(namespacedBasePath, fileOrDirPath);
+ const namespacedFullPath = path.toNamespacedPath(fullPath);
+ const relativePath = path.relative(namespacedBasePath, namespacedFullPath);
+ return relativePath.replaceAll(path.SEPARATOR, "/");
+}
+
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
@@ -665,12 +692,25 @@ const dataCache = new WeakMap();
* those config objects.
*/
class ConfigArray extends Array {
+ /**
+ * The namespaced path of the config file directory.
+ * @type {string}
+ */
+ #namespacedBasePath;
+
+ /**
+ * Path-handling implementations.
+ * @type {PathImpl}
+ */
+ #path;
+
/**
* Creates a new instance of ConfigArray.
* @param {Iterable|Function|Object} configs An iterable yielding config
* objects, or a config function, or a config object.
* @param {Object} options The options for the ConfigArray.
- * @param {string} [options.basePath=""] The path of the config file
+ * @param {string} [options.basePath="/"] The absolute path of the config file directory.
+ * Defaults to `"/"`.
* @param {boolean} [options.normalized=false] Flag indicating if the
* configs have already been normalized.
* @param {Object} [options.schema] The additional schema
@@ -680,7 +720,7 @@ class ConfigArray extends Array {
constructor(
configs,
{
- basePath = "",
+ basePath = "/",
normalized = false,
schema: customSchema,
extraConfigTypes = [],
@@ -706,6 +746,10 @@ class ConfigArray extends Array {
Object.assign({}, customSchema, baseSchema),
);
+ if (!isString(basePath) || !basePath) {
+ throw new TypeError("basePath must be a non-empty string");
+ }
+
/**
* The path of the config file that this array was loaded from.
* This is used to calculate filename matches.
@@ -745,6 +789,14 @@ class ConfigArray extends Array {
} else {
this.push(configs);
}
+
+ // select path-handling implementations depending on the base path
+ this.#path = getPathImpl(basePath);
+
+ // On Windows, `path.relative()` returns an absolute path when given two paths on different drives.
+ // The namespaced base path is useful to make sure that calculated relative paths are always relative.
+ // On Unix, it is identical to the base path.
+ this.#namespacedBasePath = this.#path.toNamespacedPath(basePath);
}
/**
@@ -932,7 +984,7 @@ class ConfigArray extends Array {
/**
* Returns the config object for a given file path and a status that can be used to determine why a file has no config.
- * @param {string} filePath The complete path of a file to get a config for.
+ * @param {string} filePath The path of a file to get a config for.
* @returns {{ config?: Object, status: "ignored"|"external"|"unconfigured"|"matched" }}
* An object with an optional property `config` and property `status`.
* `config` is the config object for the specified file as returned by {@linkcode ConfigArray.getConfig},
@@ -950,9 +1002,13 @@ class ConfigArray extends Array {
// check to see if the file is outside the base path
- const relativeFilePath = path.relative(this.basePath, filePath);
+ const relativeFilePath = toRelativePath(
+ filePath,
+ this.#namespacedBasePath,
+ this.#path,
+ );
- if (relativeFilePath.startsWith("..")) {
+ if (EXTERNAL_PATH_REGEX.test(relativeFilePath)) {
debug(`No config for file ${filePath} outside of base path`);
// cache and return result
@@ -963,7 +1019,7 @@ class ConfigArray extends Array {
// next check to see if the file should be ignored
// check if this should be ignored due to its directory
- if (this.isDirectoryIgnored(path.dirname(filePath))) {
+ if (this.isDirectoryIgnored(this.#path.dirname(filePath))) {
debug(`Ignoring ${filePath} based on directory pattern`);
// cache and return result
@@ -988,12 +1044,12 @@ class ConfigArray extends Array {
this.forEach((config, index) => {
if (!config.files) {
if (!config.ignores) {
- debug(`Anonymous universal config found for ${filePath}`);
+ debug(`Universal config found for ${filePath}`);
matchingConfigIndices.push(index);
return;
}
- if (pathMatchesIgnores(filePath, this.basePath, config)) {
+ if (pathMatchesIgnores(filePath, relativeFilePath, config)) {
debug(
`Matching config found for ${filePath} (based on ignores: ${config.ignores})`,
);
@@ -1029,7 +1085,7 @@ class ConfigArray extends Array {
// check that the config matches without the non-universal files first
if (
nonUniversalFiles.length &&
- pathMatches(filePath, this.basePath, {
+ pathMatches(filePath, relativeFilePath, {
files: nonUniversalFiles,
ignores: config.ignores,
})
@@ -1043,7 +1099,7 @@ class ConfigArray extends Array {
// if there wasn't a match then check if it matches with universal files
if (
universalFiles.length &&
- pathMatches(filePath, this.basePath, {
+ pathMatches(filePath, relativeFilePath, {
files: universalFiles,
ignores: config.ignores,
})
@@ -1058,7 +1114,7 @@ class ConfigArray extends Array {
}
// the normal case
- if (pathMatches(filePath, this.basePath, config)) {
+ if (pathMatches(filePath, relativeFilePath, config)) {
debug(`Matching config found for ${filePath}`);
matchingConfigIndices.push(index);
matchFound = true;
@@ -1113,7 +1169,7 @@ class ConfigArray extends Array {
/**
* Returns the config object for a given file path.
- * @param {string} filePath The complete path of a file to get a config for.
+ * @param {string} filePath The path of a file to get a config for.
* @returns {Object|undefined} The config object for this file or `undefined`.
*/
getConfig(filePath) {
@@ -1122,7 +1178,7 @@ class ConfigArray extends Array {
/**
* Determines whether a file has a config or why it doesn't.
- * @param {string} filePath The complete path of the file to check.
+ * @param {string} filePath The path of the file to check.
* @returns {"ignored"|"external"|"unconfigured"|"matched"} One of the following values:
* * `"ignored"`: the file is ignored
* * `"external"`: the file is outside the base path
@@ -1135,7 +1191,7 @@ class ConfigArray extends Array {
/**
* Determines if the given filepath is ignored based on the configs.
- * @param {string} filePath The complete path of a file to check.
+ * @param {string} filePath The path of a file to check.
* @returns {boolean} True if the path is ignored, false if not.
* @deprecated Use `isFileIgnored` instead.
*/
@@ -1145,7 +1201,7 @@ class ConfigArray extends Array {
/**
* Determines if the given filepath is ignored based on the configs.
- * @param {string} filePath The complete path of a file to check.
+ * @param {string} filePath The path of a file to check.
* @returns {boolean} True if the path is ignored, false if not.
*/
isFileIgnored(filePath) {
@@ -1158,7 +1214,7 @@ class ConfigArray extends Array {
* same config. A pattern such as `/foo` be considered to ignore the directory
* while a pattern such as `/foo/**` is not considered to ignore the
* directory because it is matching files.
- * @param {string} directoryPath The complete path of a directory to check.
+ * @param {string} directoryPath The path of a directory to check.
* @returns {boolean} True if the directory is ignored, false if not. Will
* return true for any directory that is not inside of `basePath`.
* @throws {Error} When the `ConfigArray` is not normalized.
@@ -1166,16 +1222,18 @@ class ConfigArray extends Array {
isDirectoryIgnored(directoryPath) {
assertNormalized(this);
- const relativeDirectoryPath = path
- .relative(this.basePath, directoryPath)
- .replace(/\\/gu, "/");
+ const relativeDirectoryPath = toRelativePath(
+ directoryPath,
+ this.#namespacedBasePath,
+ this.#path,
+ );
// basePath directory can never be ignored
if (relativeDirectoryPath === "") {
return false;
}
- if (relativeDirectoryPath.startsWith("..")) {
+ if (EXTERNAL_PATH_REGEX.test(relativeDirectoryPath)) {
return true;
}
@@ -1204,7 +1262,7 @@ class ConfigArray extends Array {
result = shouldIgnorePath(
this.ignores,
- path.join(this.basePath, relativeDirectoryToCheck),
+ this.#path.join(this.basePath, relativeDirectoryToCheck),
relativeDirectoryToCheck,
);
diff --git a/node_modules/@eslint/config-array/dist/esm/std__path/posix.js b/node_modules/@eslint/config-array/dist/esm/std__path/posix.js
new file mode 100644
index 000000000..f96609697
--- /dev/null
+++ b/node_modules/@eslint/config-array/dist/esm/std__path/posix.js
@@ -0,0 +1,1301 @@
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// Copyright the Browserify authors. MIT License.
+function assertPath(path) {
+ if (typeof path !== "string") {
+ throw new TypeError(`Path must be a string, received "${JSON.stringify(path)}"`);
+ }
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function stripSuffix(name, suffix) {
+ if (suffix.length >= name.length) {
+ return name;
+ }
+ const lenDiff = name.length - suffix.length;
+ for(let i = suffix.length - 1; i >= 0; --i){
+ if (name.charCodeAt(lenDiff + i) !== suffix.charCodeAt(i)) {
+ return name;
+ }
+ }
+ return name.slice(0, -suffix.length);
+}
+function lastPathSegment(path, isSep, start = 0) {
+ let matchedNonSeparator = false;
+ let end = path.length;
+ for(let i = path.length - 1; i >= start; --i){
+ if (isSep(path.charCodeAt(i))) {
+ if (matchedNonSeparator) {
+ start = i + 1;
+ break;
+ }
+ } else if (!matchedNonSeparator) {
+ matchedNonSeparator = true;
+ end = i + 1;
+ }
+ }
+ return path.slice(start, end);
+}
+function assertArgs$1(path, suffix) {
+ assertPath(path);
+ if (path.length === 0) return path;
+ if (typeof suffix !== "string") {
+ throw new TypeError(`Suffix must be a string, received "${JSON.stringify(suffix)}"`);
+ }
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// Copyright the Browserify authors. MIT License.
+// Ported from https://github.com/browserify/path-browserify/
+// This module is browser compatible.
+function stripTrailingSeparators(segment, isSep) {
+ if (segment.length <= 1) {
+ return segment;
+ }
+ let end = segment.length;
+ for(let i = segment.length - 1; i > 0; i--){
+ if (isSep(segment.charCodeAt(i))) {
+ end = i;
+ } else {
+ break;
+ }
+ }
+ return segment.slice(0, end);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// Copyright the Browserify authors. MIT License.
+// Ported from https://github.com/browserify/path-browserify/
+// This module is browser compatible.
+// Alphabet chars.
+// Non-alphabetic chars.
+const CHAR_DOT = 46; /* . */
+const CHAR_FORWARD_SLASH = 47; /* / */
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// Copyright the Browserify authors. MIT License.
+// Ported from https://github.com/browserify/path-browserify/
+// This module is browser compatible.
+function isPosixPathSeparator(code) {
+ return code === CHAR_FORWARD_SLASH;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Return the last portion of a `path`.
+ * Trailing directory separators are ignored, and optional suffix is removed.
+ *
+ * @example Usage
+ * ```ts
+ * import { basename } from "@std/path/posix/basename";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(basename("/home/user/Documents/"), "Documents");
+ * assertEquals(basename("/home/user/Documents/image.png"), "image.png");
+ * assertEquals(basename("/home/user/Documents/image.png", ".png"), "image");
+ * ```
+ *
+ * @example Working with URLs
+ *
+ * Note: This function doesn't automatically strip hash and query parts from
+ * URLs. If your URL contains a hash or query, remove them before passing the
+ * URL to the function. This can be done by passing the URL to `new URL(url)`,
+ * and setting the `hash` and `search` properties to empty strings.
+ *
+ * ```ts
+ * import { basename } from "@std/path/posix/basename";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(basename("https://deno.land/std/path/mod.ts"), "mod.ts");
+ * assertEquals(basename("https://deno.land/std/path/mod.ts", ".ts"), "mod");
+ * assertEquals(basename("https://deno.land/std/path/mod.ts?a=b"), "mod.ts?a=b");
+ * assertEquals(basename("https://deno.land/std/path/mod.ts#header"), "mod.ts#header");
+ * ```
+ *
+ * Note: If you are working with file URLs,
+ * use the new version of `basename` from `@std/path/posix/unstable-basename`.
+ *
+ * @param path The path to extract the name from.
+ * @param suffix The suffix to remove from extracted name.
+ * @returns The extracted name.
+ */ function basename(path, suffix = "") {
+ assertArgs$1(path, suffix);
+ const lastSegment = lastPathSegment(path, isPosixPathSeparator);
+ const strippedSegment = stripTrailingSeparators(lastSegment, isPosixPathSeparator);
+ return suffix ? stripSuffix(strippedSegment, suffix) : strippedSegment;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * The character used to separate entries in the PATH environment variable.
+ */ const DELIMITER = ":";
+/**
+ * The character used to separate components of a file path.
+ */ const SEPARATOR = "/";
+/**
+ * A regular expression that matches one or more path separators.
+ */ const SEPARATOR_PATTERN = /\/+/;
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function assertArg$3(path) {
+ assertPath(path);
+ if (path.length === 0) return ".";
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Return the directory path of a `path`.
+ *
+ * @example Usage
+ * ```ts
+ * import { dirname } from "@std/path/posix/dirname";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(dirname("/home/user/Documents/"), "/home/user");
+ * assertEquals(dirname("/home/user/Documents/image.png"), "/home/user/Documents");
+ * assertEquals(dirname("https://deno.land/std/path/mod.ts"), "https://deno.land/std/path");
+ * ```
+ *
+ * @example Working with URLs
+ *
+ * ```ts
+ * import { dirname } from "@std/path/posix/dirname";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(dirname("https://deno.land/std/path/mod.ts"), "https://deno.land/std/path");
+ * assertEquals(dirname("https://deno.land/std/path/mod.ts?a=b"), "https://deno.land/std/path");
+ * assertEquals(dirname("https://deno.land/std/path/mod.ts#header"), "https://deno.land/std/path");
+ * ```
+ *
+ * Note: If you are working with file URLs,
+ * use the new version of `dirname` from `@std/path/posix/unstable-dirname`.
+ *
+ * @param path The path to get the directory from.
+ * @returns The directory path.
+ */ function dirname(path) {
+ assertArg$3(path);
+ let end = -1;
+ let matchedNonSeparator = false;
+ for(let i = path.length - 1; i >= 1; --i){
+ if (isPosixPathSeparator(path.charCodeAt(i))) {
+ if (matchedNonSeparator) {
+ end = i;
+ break;
+ }
+ } else {
+ matchedNonSeparator = true;
+ }
+ }
+ // No matches. Fallback based on provided path:
+ //
+ // - leading slashes paths
+ // "/foo" => "/"
+ // "///foo" => "/"
+ // - no slash path
+ // "foo" => "."
+ if (end === -1) {
+ return isPosixPathSeparator(path.charCodeAt(0)) ? "/" : ".";
+ }
+ return stripTrailingSeparators(path.slice(0, end), isPosixPathSeparator);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Return the extension of the `path` with leading period.
+ *
+ * @example Usage
+ * ```ts
+ * import { extname } from "@std/path/posix/extname";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(extname("/home/user/Documents/file.ts"), ".ts");
+ * assertEquals(extname("/home/user/Documents/"), "");
+ * assertEquals(extname("/home/user/Documents/image.png"), ".png");
+ * ```
+ *
+ * @example Working with URLs
+ *
+ * Note: This function doesn't automatically strip hash and query parts from
+ * URLs. If your URL contains a hash or query, remove them before passing the
+ * URL to the function. This can be done by passing the URL to `new URL(url)`,
+ * and setting the `hash` and `search` properties to empty strings.
+ *
+ * ```ts
+ * import { extname } from "@std/path/posix/extname";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(extname("https://deno.land/std/path/mod.ts"), ".ts");
+ * assertEquals(extname("https://deno.land/std/path/mod.ts?a=b"), ".ts?a=b");
+ * assertEquals(extname("https://deno.land/std/path/mod.ts#header"), ".ts#header");
+ * ```
+ *
+ * Note: If you are working with file URLs,
+ * use the new version of `extname` from `@std/path/posix/unstable-extname`.
+ *
+ * @param path The path to get the extension from.
+ * @returns The extension (ex. for `file.ts` returns `.ts`).
+ */ function extname(path) {
+ assertPath(path);
+ let startDot = -1;
+ let startPart = 0;
+ let end = -1;
+ let matchedSlash = true;
+ // Track the state of characters (if any) we see before our first dot and
+ // after any path separator we find
+ let preDotState = 0;
+ for(let i = path.length - 1; i >= 0; --i){
+ const code = path.charCodeAt(i);
+ if (isPosixPathSeparator(code)) {
+ // If we reached a path separator that was not part of a set of path
+ // separators at the end of the string, stop now
+ if (!matchedSlash) {
+ startPart = i + 1;
+ break;
+ }
+ continue;
+ }
+ if (end === -1) {
+ // We saw the first non-path separator, mark this as the end of our
+ // extension
+ matchedSlash = false;
+ end = i + 1;
+ }
+ if (code === CHAR_DOT) {
+ // If this is our first dot, mark it as the start of our extension
+ if (startDot === -1) startDot = i;
+ else if (preDotState !== 1) preDotState = 1;
+ } else if (startDot !== -1) {
+ // We saw a non-dot and non-path separator before our dot, so we should
+ // have a good chance at having a non-empty extension
+ preDotState = -1;
+ }
+ }
+ if (startDot === -1 || end === -1 || // We saw a non-dot character immediately before the dot
+ preDotState === 0 || // The (right-most) trimmed path component is exactly '..'
+ preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
+ return "";
+ }
+ return path.slice(startDot, end);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function _format(sep, pathObject) {
+ const dir = pathObject.dir || pathObject.root;
+ const base = pathObject.base || (pathObject.name ?? "") + (pathObject.ext ?? "");
+ if (!dir) return base;
+ if (base === sep) return dir;
+ if (dir === pathObject.root) return dir + base;
+ return dir + sep + base;
+}
+function assertArg$2(pathObject) {
+ if (pathObject === null || typeof pathObject !== "object") {
+ throw new TypeError(`The "pathObject" argument must be of type Object, received type "${typeof pathObject}"`);
+ }
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Generate a path from `ParsedPath` object.
+ *
+ * @example Usage
+ * ```ts
+ * import { format } from "@std/path/posix/format";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const path = format({
+ * root: "/",
+ * dir: "/path/dir",
+ * base: "file.txt",
+ * ext: ".txt",
+ * name: "file"
+ * });
+ * assertEquals(path, "/path/dir/file.txt");
+ * ```
+ *
+ * @param pathObject The path object to format.
+ * @returns The formatted path.
+ */ function format(pathObject) {
+ assertArg$2(pathObject);
+ return _format("/", pathObject);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function assertArg$1(url) {
+ url = url instanceof URL ? url : new URL(url);
+ if (url.protocol !== "file:") {
+ throw new TypeError(`URL must be a file URL: received "${url.protocol}"`);
+ }
+ return url;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Converts a file URL to a path string.
+ *
+ * @example Usage
+ * ```ts
+ * import { fromFileUrl } from "@std/path/posix/from-file-url";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(fromFileUrl(new URL("file:///home/foo")), "/home/foo");
+ * ```
+ *
+ * @param url The file URL to convert.
+ * @returns The path string.
+ */ function fromFileUrl(url) {
+ url = assertArg$1(url);
+ return decodeURIComponent(url.pathname.replace(/%(?![0-9A-Fa-f]{2})/g, "%25"));
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Verifies whether provided path is absolute.
+ *
+ * @example Usage
+ * ```ts
+ * import { isAbsolute } from "@std/path/posix/is-absolute";
+ * import { assert, assertFalse } from "@std/assert";
+ *
+ * assert(isAbsolute("/home/user/Documents/"));
+ * assertFalse(isAbsolute("home/user/Documents/"));
+ * ```
+ *
+ * @param path The path to verify.
+ * @returns Whether the path is absolute.
+ */ function isAbsolute(path) {
+ assertPath(path);
+ return path.length > 0 && isPosixPathSeparator(path.charCodeAt(0));
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function assertArg(path) {
+ assertPath(path);
+ if (path.length === 0) return ".";
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// Copyright the Browserify authors. MIT License.
+// Ported from https://github.com/browserify/path-browserify/
+// This module is browser compatible.
+// Resolves . and .. elements in a path with directory names
+function normalizeString(path, allowAboveRoot, separator, isPathSeparator) {
+ let res = "";
+ let lastSegmentLength = 0;
+ let lastSlash = -1;
+ let dots = 0;
+ let code;
+ for(let i = 0; i <= path.length; ++i){
+ if (i < path.length) code = path.charCodeAt(i);
+ else if (isPathSeparator(code)) break;
+ else code = CHAR_FORWARD_SLASH;
+ if (isPathSeparator(code)) {
+ if (lastSlash === i - 1 || dots === 1) ; else if (lastSlash !== i - 1 && dots === 2) {
+ if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== CHAR_DOT || res.charCodeAt(res.length - 2) !== CHAR_DOT) {
+ if (res.length > 2) {
+ const lastSlashIndex = res.lastIndexOf(separator);
+ if (lastSlashIndex === -1) {
+ res = "";
+ lastSegmentLength = 0;
+ } else {
+ res = res.slice(0, lastSlashIndex);
+ lastSegmentLength = res.length - 1 - res.lastIndexOf(separator);
+ }
+ lastSlash = i;
+ dots = 0;
+ continue;
+ } else if (res.length === 2 || res.length === 1) {
+ res = "";
+ lastSegmentLength = 0;
+ lastSlash = i;
+ dots = 0;
+ continue;
+ }
+ }
+ if (allowAboveRoot) {
+ if (res.length > 0) res += `${separator}..`;
+ else res = "..";
+ lastSegmentLength = 2;
+ }
+ } else {
+ if (res.length > 0) res += separator + path.slice(lastSlash + 1, i);
+ else res = path.slice(lastSlash + 1, i);
+ lastSegmentLength = i - lastSlash - 1;
+ }
+ lastSlash = i;
+ dots = 0;
+ } else if (code === CHAR_DOT && dots !== -1) {
+ ++dots;
+ } else {
+ dots = -1;
+ }
+ }
+ return res;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Normalize the `path`, resolving `'..'` and `'.'` segments.
+ * Note that resolving these segments does not necessarily mean that all will be eliminated.
+ * A `'..'` at the top-level will be preserved, and an empty path is canonically `'.'`.
+ *
+ * @example Usage
+ * ```ts
+ * import { normalize } from "@std/path/posix/normalize";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const path = normalize("/foo/bar//baz/asdf/quux/..");
+ * assertEquals(path, "/foo/bar/baz/asdf");
+ * ```
+ *
+ * @example Working with URLs
+ *
+ * Note: This function will remove the double slashes from a URL's scheme.
+ * Hence, do not pass a full URL to this function. Instead, pass the pathname of
+ * the URL.
+ *
+ * ```ts
+ * import { normalize } from "@std/path/posix/normalize";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const url = new URL("https://deno.land");
+ * url.pathname = normalize("//std//assert//.//mod.ts");
+ * assertEquals(url.href, "https://deno.land/std/assert/mod.ts");
+ *
+ * url.pathname = normalize("std/assert/../async/retry.ts");
+ * assertEquals(url.href, "https://deno.land/std/async/retry.ts");
+ * ```
+ *
+ * Note: If you are working with file URLs,
+ * use the new version of `normalize` from `@std/path/posix/unstable-normalize`.
+ *
+ * @param path The path to normalize.
+ * @returns The normalized path.
+ */ function normalize(path) {
+ assertArg(path);
+ const isAbsolute = isPosixPathSeparator(path.charCodeAt(0));
+ const trailingSeparator = isPosixPathSeparator(path.charCodeAt(path.length - 1));
+ // Normalize the path
+ path = normalizeString(path, !isAbsolute, "/", isPosixPathSeparator);
+ if (path.length === 0 && !isAbsolute) path = ".";
+ if (path.length > 0 && trailingSeparator) path += "/";
+ if (isAbsolute) return `/${path}`;
+ return path;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Join all given a sequence of `paths`,then normalizes the resulting path.
+ *
+ * @example Usage
+ * ```ts
+ * import { join } from "@std/path/posix/join";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const path = join("/foo", "bar", "baz/asdf", "quux", "..");
+ * assertEquals(path, "/foo/bar/baz/asdf");
+ * ```
+ *
+ * @example Working with URLs
+ * ```ts
+ * import { join } from "@std/path/posix/join";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const url = new URL("https://deno.land");
+ * url.pathname = join("std", "path", "mod.ts");
+ * assertEquals(url.href, "https://deno.land/std/path/mod.ts");
+ *
+ * url.pathname = join("//std", "path/", "/mod.ts");
+ * assertEquals(url.href, "https://deno.land/std/path/mod.ts");
+ * ```
+ *
+ * Note: If you are working with file URLs,
+ * use the new version of `join` from `@std/path/posix/unstable-join`.
+ *
+ * @param paths The paths to join.
+ * @returns The joined path.
+ */ function join(...paths) {
+ if (paths.length === 0) return ".";
+ paths.forEach((path)=>assertPath(path));
+ const joined = paths.filter((path)=>path.length > 0).join("/");
+ return joined === "" ? "." : normalize(joined);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Return a `ParsedPath` object of the `path`.
+ *
+ * @example Usage
+ * ```ts
+ * import { parse } from "@std/path/posix/parse";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const path = parse("/home/user/file.txt");
+ * assertEquals(path, {
+ * root: "/",
+ * dir: "/home/user",
+ * base: "file.txt",
+ * ext: ".txt",
+ * name: "file"
+ * });
+ * ```
+ *
+ * @param path The path to parse.
+ * @returns The parsed path object.
+ */ function parse(path) {
+ assertPath(path);
+ const ret = {
+ root: "",
+ dir: "",
+ base: "",
+ ext: "",
+ name: ""
+ };
+ if (path.length === 0) return ret;
+ const isAbsolute = isPosixPathSeparator(path.charCodeAt(0));
+ let start;
+ if (isAbsolute) {
+ ret.root = "/";
+ start = 1;
+ } else {
+ start = 0;
+ }
+ let startDot = -1;
+ let startPart = 0;
+ let end = -1;
+ let matchedSlash = true;
+ let i = path.length - 1;
+ // Track the state of characters (if any) we see before our first dot and
+ // after any path separator we find
+ let preDotState = 0;
+ // Get non-dir info
+ for(; i >= start; --i){
+ const code = path.charCodeAt(i);
+ if (isPosixPathSeparator(code)) {
+ // If we reached a path separator that was not part of a set of path
+ // separators at the end of the string, stop now
+ if (!matchedSlash) {
+ startPart = i + 1;
+ break;
+ }
+ continue;
+ }
+ if (end === -1) {
+ // We saw the first non-path separator, mark this as the end of our
+ // extension
+ matchedSlash = false;
+ end = i + 1;
+ }
+ if (code === CHAR_DOT) {
+ // If this is our first dot, mark it as the start of our extension
+ if (startDot === -1) startDot = i;
+ else if (preDotState !== 1) preDotState = 1;
+ } else if (startDot !== -1) {
+ // We saw a non-dot and non-path separator before our dot, so we should
+ // have a good chance at having a non-empty extension
+ preDotState = -1;
+ }
+ }
+ if (startDot === -1 || end === -1 || // We saw a non-dot character immediately before the dot
+ preDotState === 0 || // The (right-most) trimmed path component is exactly '..'
+ preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
+ if (end !== -1) {
+ if (startPart === 0 && isAbsolute) {
+ ret.base = ret.name = path.slice(1, end);
+ } else {
+ ret.base = ret.name = path.slice(startPart, end);
+ }
+ }
+ // Fallback to '/' in case there is no basename
+ ret.base = ret.base || "/";
+ } else {
+ if (startPart === 0 && isAbsolute) {
+ ret.name = path.slice(1, startDot);
+ ret.base = path.slice(1, end);
+ } else {
+ ret.name = path.slice(startPart, startDot);
+ ret.base = path.slice(startPart, end);
+ }
+ ret.ext = path.slice(startDot, end);
+ }
+ if (startPart > 0) {
+ ret.dir = stripTrailingSeparators(path.slice(0, startPart - 1), isPosixPathSeparator);
+ } else if (isAbsolute) ret.dir = "/";
+ return ret;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Resolves path segments into a `path`.
+ *
+ * @example Usage
+ * ```ts
+ * import { resolve } from "@std/path/posix/resolve";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const path = resolve("/foo", "bar", "baz/asdf", "quux", "..");
+ * assertEquals(path, "/foo/bar/baz/asdf");
+ * ```
+ *
+ * @param pathSegments The path segments to resolve.
+ * @returns The resolved path.
+ */ function resolve(...pathSegments) {
+ let resolvedPath = "";
+ let resolvedAbsolute = false;
+ for(let i = pathSegments.length - 1; i >= -1 && !resolvedAbsolute; i--){
+ let path;
+ if (i >= 0) path = pathSegments[i];
+ else {
+ // deno-lint-ignore no-explicit-any
+ const { Deno } = globalThis;
+ if (typeof Deno?.cwd !== "function") {
+ throw new TypeError("Resolved a relative path without a current working directory (CWD)");
+ }
+ path = Deno.cwd();
+ }
+ assertPath(path);
+ // Skip empty entries
+ if (path.length === 0) {
+ continue;
+ }
+ resolvedPath = `${path}/${resolvedPath}`;
+ resolvedAbsolute = isPosixPathSeparator(path.charCodeAt(0));
+ }
+ // At this point the path should be resolved to a full absolute path, but
+ // handle relative paths to be safe (might happen when Deno.cwd() fails)
+ // Normalize the path
+ resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute, "/", isPosixPathSeparator);
+ if (resolvedAbsolute) {
+ if (resolvedPath.length > 0) return `/${resolvedPath}`;
+ else return "/";
+ } else if (resolvedPath.length > 0) return resolvedPath;
+ else return ".";
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function assertArgs(from, to) {
+ assertPath(from);
+ assertPath(to);
+ if (from === to) return "";
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Return the relative path from `from` to `to` based on current working directory.
+ *
+ * If `from` and `to` are the same, return an empty string.
+ *
+ * @example Usage
+ * ```ts
+ * import { relative } from "@std/path/posix/relative";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const path = relative("/data/orandea/test/aaa", "/data/orandea/impl/bbb");
+ * assertEquals(path, "../../impl/bbb");
+ * ```
+ *
+ * @param from The path to start from.
+ * @param to The path to reach.
+ * @returns The relative path.
+ */ function relative(from, to) {
+ assertArgs(from, to);
+ from = resolve(from);
+ to = resolve(to);
+ if (from === to) return "";
+ // Trim any leading backslashes
+ let fromStart = 1;
+ const fromEnd = from.length;
+ for(; fromStart < fromEnd; ++fromStart){
+ if (!isPosixPathSeparator(from.charCodeAt(fromStart))) break;
+ }
+ const fromLen = fromEnd - fromStart;
+ // Trim any leading backslashes
+ let toStart = 1;
+ const toEnd = to.length;
+ for(; toStart < toEnd; ++toStart){
+ if (!isPosixPathSeparator(to.charCodeAt(toStart))) break;
+ }
+ const toLen = toEnd - toStart;
+ // Compare paths to find the longest common path from root
+ const length = fromLen < toLen ? fromLen : toLen;
+ let lastCommonSep = -1;
+ let i = 0;
+ for(; i <= length; ++i){
+ if (i === length) {
+ if (toLen > length) {
+ if (isPosixPathSeparator(to.charCodeAt(toStart + i))) {
+ // We get here if `from` is the exact base path for `to`.
+ // For example: from='/foo/bar'; to='/foo/bar/baz'
+ return to.slice(toStart + i + 1);
+ } else if (i === 0) {
+ // We get here if `from` is the root
+ // For example: from='/'; to='/foo'
+ return to.slice(toStart + i);
+ }
+ } else if (fromLen > length) {
+ if (isPosixPathSeparator(from.charCodeAt(fromStart + i))) {
+ // We get here if `to` is the exact base path for `from`.
+ // For example: from='/foo/bar/baz'; to='/foo/bar'
+ lastCommonSep = i;
+ } else if (i === 0) {
+ // We get here if `to` is the root.
+ // For example: from='/foo'; to='/'
+ lastCommonSep = 0;
+ }
+ }
+ break;
+ }
+ const fromCode = from.charCodeAt(fromStart + i);
+ const toCode = to.charCodeAt(toStart + i);
+ if (fromCode !== toCode) break;
+ else if (isPosixPathSeparator(fromCode)) lastCommonSep = i;
+ }
+ let out = "";
+ // Generate the relative path based on the path difference between `to`
+ // and `from`
+ for(i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i){
+ if (i === fromEnd || isPosixPathSeparator(from.charCodeAt(i))) {
+ if (out.length === 0) out += "..";
+ else out += "/..";
+ }
+ }
+ // Lastly, append the rest of the destination (`to`) path that comes after
+ // the common path parts
+ if (out.length > 0) return out + to.slice(toStart + lastCommonSep);
+ else {
+ toStart += lastCommonSep;
+ if (isPosixPathSeparator(to.charCodeAt(toStart))) ++toStart;
+ return to.slice(toStart);
+ }
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+const WHITESPACE_ENCODINGS = {
+ "\u0009": "%09",
+ "\u000A": "%0A",
+ "\u000B": "%0B",
+ "\u000C": "%0C",
+ "\u000D": "%0D",
+ "\u0020": "%20"
+};
+function encodeWhitespace(string) {
+ return string.replaceAll(/[\s]/g, (c)=>{
+ return WHITESPACE_ENCODINGS[c] ?? c;
+ });
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Converts a path string to a file URL.
+ *
+ * @example Usage
+ * ```ts
+ * import { toFileUrl } from "@std/path/posix/to-file-url";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(toFileUrl("/home/foo"), new URL("file:///home/foo"));
+ * assertEquals(toFileUrl("/home/foo bar"), new URL("file:///home/foo%20bar"));
+ * ```
+ *
+ * @param path The path to convert.
+ * @returns The file URL.
+ */ function toFileUrl(path) {
+ if (!isAbsolute(path)) {
+ throw new TypeError(`Path must be absolute: received "${path}"`);
+ }
+ const url = new URL("file:///");
+ url.pathname = encodeWhitespace(path.replace(/%/g, "%25").replace(/\\/g, "%5C"));
+ return url;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Converts a path to a namespaced path. This function returns the path as is on posix.
+ *
+ * @example Usage
+ * ```ts
+ * import { toNamespacedPath } from "@std/path/posix/to-namespaced-path";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(toNamespacedPath("/home/foo"), "/home/foo");
+ * ```
+ *
+ * @param path The path.
+ * @returns The namespaced path.
+ */ function toNamespacedPath(path) {
+ // Non-op on posix systems
+ return path;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function common$1(paths, sep) {
+ const [first = "", ...remaining] = paths;
+ const parts = first.split(sep);
+ let endOfPrefix = parts.length;
+ let append = "";
+ for (const path of remaining){
+ const compare = path.split(sep);
+ if (compare.length <= endOfPrefix) {
+ endOfPrefix = compare.length;
+ append = "";
+ }
+ for(let i = 0; i < endOfPrefix; i++){
+ if (compare[i] !== parts[i]) {
+ endOfPrefix = i;
+ append = i === 0 ? "" : sep;
+ break;
+ }
+ }
+ }
+ return parts.slice(0, endOfPrefix).join(sep) + append;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/** Determines the common path from a set of paths for POSIX systems.
+ *
+ * @example Usage
+ * ```ts
+ * import { common } from "@std/path/posix/common";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const path = common([
+ * "./deno/std/path/mod.ts",
+ * "./deno/std/fs/mod.ts",
+ * ]);
+ * assertEquals(path, "./deno/std/");
+ * ```
+ *
+ * @param paths The paths to compare.
+ * @returns The common path.
+ */ function common(paths) {
+ return common$1(paths, SEPARATOR);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Options for {@linkcode globToRegExp}, {@linkcode joinGlobs},
+ * {@linkcode normalizeGlob} and {@linkcode expandGlob}.
+ */ const REG_EXP_ESCAPE_CHARS = [
+ "!",
+ "$",
+ "(",
+ ")",
+ "*",
+ "+",
+ ".",
+ "=",
+ "?",
+ "[",
+ "\\",
+ "^",
+ "{",
+ "|"
+];
+const RANGE_ESCAPE_CHARS = [
+ "-",
+ "\\",
+ "]"
+];
+function _globToRegExp(c, glob, { extended = true, globstar: globstarOption = true, // os = osType,
+caseInsensitive = false } = {}) {
+ if (glob === "") {
+ return /(?!)/;
+ }
+ // Remove trailing separators.
+ let newLength = glob.length;
+ for(; newLength > 1 && c.seps.includes(glob[newLength - 1]); newLength--);
+ glob = glob.slice(0, newLength);
+ let regExpString = "";
+ // Terminates correctly. Trust that `j` is incremented every iteration.
+ for(let j = 0; j < glob.length;){
+ let segment = "";
+ const groupStack = [];
+ let inRange = false;
+ let inEscape = false;
+ let endsWithSep = false;
+ let i = j;
+ // Terminates with `i` at the non-inclusive end of the current segment.
+ for(; i < glob.length && !c.seps.includes(glob[i]); i++){
+ if (inEscape) {
+ inEscape = false;
+ const escapeChars = inRange ? RANGE_ESCAPE_CHARS : REG_EXP_ESCAPE_CHARS;
+ segment += escapeChars.includes(glob[i]) ? `\\${glob[i]}` : glob[i];
+ continue;
+ }
+ if (glob[i] === c.escapePrefix) {
+ inEscape = true;
+ continue;
+ }
+ if (glob[i] === "[") {
+ if (!inRange) {
+ inRange = true;
+ segment += "[";
+ if (glob[i + 1] === "!") {
+ i++;
+ segment += "^";
+ } else if (glob[i + 1] === "^") {
+ i++;
+ segment += "\\^";
+ }
+ continue;
+ } else if (glob[i + 1] === ":") {
+ let k = i + 1;
+ let value = "";
+ while(glob[k + 1] !== undefined && glob[k + 1] !== ":"){
+ value += glob[k + 1];
+ k++;
+ }
+ if (glob[k + 1] === ":" && glob[k + 2] === "]") {
+ i = k + 2;
+ if (value === "alnum") segment += "\\dA-Za-z";
+ else if (value === "alpha") segment += "A-Za-z";
+ else if (value === "ascii") segment += "\x00-\x7F";
+ else if (value === "blank") segment += "\t ";
+ else if (value === "cntrl") segment += "\x00-\x1F\x7F";
+ else if (value === "digit") segment += "\\d";
+ else if (value === "graph") segment += "\x21-\x7E";
+ else if (value === "lower") segment += "a-z";
+ else if (value === "print") segment += "\x20-\x7E";
+ else if (value === "punct") {
+ segment += "!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_‘{|}~";
+ } else if (value === "space") segment += "\\s\v";
+ else if (value === "upper") segment += "A-Z";
+ else if (value === "word") segment += "\\w";
+ else if (value === "xdigit") segment += "\\dA-Fa-f";
+ continue;
+ }
+ }
+ }
+ if (glob[i] === "]" && inRange) {
+ inRange = false;
+ segment += "]";
+ continue;
+ }
+ if (inRange) {
+ segment += glob[i];
+ continue;
+ }
+ if (glob[i] === ")" && groupStack.length > 0 && groupStack[groupStack.length - 1] !== "BRACE") {
+ segment += ")";
+ const type = groupStack.pop();
+ if (type === "!") {
+ segment += c.wildcard;
+ } else if (type !== "@") {
+ segment += type;
+ }
+ continue;
+ }
+ if (glob[i] === "|" && groupStack.length > 0 && groupStack[groupStack.length - 1] !== "BRACE") {
+ segment += "|";
+ continue;
+ }
+ if (glob[i] === "+" && extended && glob[i + 1] === "(") {
+ i++;
+ groupStack.push("+");
+ segment += "(?:";
+ continue;
+ }
+ if (glob[i] === "@" && extended && glob[i + 1] === "(") {
+ i++;
+ groupStack.push("@");
+ segment += "(?:";
+ continue;
+ }
+ if (glob[i] === "?") {
+ if (extended && glob[i + 1] === "(") {
+ i++;
+ groupStack.push("?");
+ segment += "(?:";
+ } else {
+ segment += ".";
+ }
+ continue;
+ }
+ if (glob[i] === "!" && extended && glob[i + 1] === "(") {
+ i++;
+ groupStack.push("!");
+ segment += "(?!";
+ continue;
+ }
+ if (glob[i] === "{") {
+ groupStack.push("BRACE");
+ segment += "(?:";
+ continue;
+ }
+ if (glob[i] === "}" && groupStack[groupStack.length - 1] === "BRACE") {
+ groupStack.pop();
+ segment += ")";
+ continue;
+ }
+ if (glob[i] === "," && groupStack[groupStack.length - 1] === "BRACE") {
+ segment += "|";
+ continue;
+ }
+ if (glob[i] === "*") {
+ if (extended && glob[i + 1] === "(") {
+ i++;
+ groupStack.push("*");
+ segment += "(?:";
+ } else {
+ const prevChar = glob[i - 1];
+ let numStars = 1;
+ while(glob[i + 1] === "*"){
+ i++;
+ numStars++;
+ }
+ const nextChar = glob[i + 1];
+ if (globstarOption && numStars === 2 && [
+ ...c.seps,
+ undefined
+ ].includes(prevChar) && [
+ ...c.seps,
+ undefined
+ ].includes(nextChar)) {
+ segment += c.globstar;
+ endsWithSep = true;
+ } else {
+ segment += c.wildcard;
+ }
+ }
+ continue;
+ }
+ segment += REG_EXP_ESCAPE_CHARS.includes(glob[i]) ? `\\${glob[i]}` : glob[i];
+ }
+ // Check for unclosed groups or a dangling backslash.
+ if (groupStack.length > 0 || inRange || inEscape) {
+ // Parse failure. Take all characters from this segment literally.
+ segment = "";
+ for (const c of glob.slice(j, i)){
+ segment += REG_EXP_ESCAPE_CHARS.includes(c) ? `\\${c}` : c;
+ endsWithSep = false;
+ }
+ }
+ regExpString += segment;
+ if (!endsWithSep) {
+ regExpString += i < glob.length ? c.sep : c.sepMaybe;
+ endsWithSep = true;
+ }
+ // Terminates with `i` at the start of the next segment.
+ while(c.seps.includes(glob[i]))i++;
+ j = i;
+ }
+ regExpString = `^${regExpString}$`;
+ return new RegExp(regExpString, caseInsensitive ? "i" : "");
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+const constants = {
+ sep: "/+",
+ sepMaybe: "/*",
+ seps: [
+ "/"
+ ],
+ globstar: "(?:[^/]*(?:/|$)+)*",
+ wildcard: "[^/]*",
+ escapePrefix: "\\"
+};
+/** Convert a glob string to a regular expression.
+ *
+ * Tries to match bash glob expansion as closely as possible.
+ *
+ * Basic glob syntax:
+ * - `*` - Matches everything without leaving the path segment.
+ * - `?` - Matches any single character.
+ * - `{foo,bar}` - Matches `foo` or `bar`.
+ * - `[abcd]` - Matches `a`, `b`, `c` or `d`.
+ * - `[a-d]` - Matches `a`, `b`, `c` or `d`.
+ * - `[!abcd]` - Matches any single character besides `a`, `b`, `c` or `d`.
+ * - `[[::]]` - Matches any character belonging to ``.
+ * - `[[:alnum:]]` - Matches any digit or letter.
+ * - `[[:digit:]abc]` - Matches any digit, `a`, `b` or `c`.
+ * - See https://facelessuser.github.io/wcmatch/glob/#posix-character-classes
+ * for a complete list of supported character classes.
+ * - `\` - Escapes the next character for an `os` other than `"windows"`.
+ * - \` - Escapes the next character for `os` set to `"windows"`.
+ * - `/` - Path separator.
+ * - `\` - Additional path separator only for `os` set to `"windows"`.
+ *
+ * Extended syntax:
+ * - Requires `{ extended: true }`.
+ * - `?(foo|bar)` - Matches 0 or 1 instance of `{foo,bar}`.
+ * - `@(foo|bar)` - Matches 1 instance of `{foo,bar}`. They behave the same.
+ * - `*(foo|bar)` - Matches _n_ instances of `{foo,bar}`.
+ * - `+(foo|bar)` - Matches _n > 0_ instances of `{foo,bar}`.
+ * - `!(foo|bar)` - Matches anything other than `{foo,bar}`.
+ * - See https://www.linuxjournal.com/content/bash-extended-globbing.
+ *
+ * Globstar syntax:
+ * - Requires `{ globstar: true }`.
+ * - `**` - Matches any number of any path segments.
+ * - Must comprise its entire path segment in the provided glob.
+ * - See https://www.linuxjournal.com/content/globstar-new-bash-globbing-option.
+ *
+ * Note the following properties:
+ * - The generated `RegExp` is anchored at both start and end.
+ * - Repeating and trailing separators are tolerated. Trailing separators in the
+ * provided glob have no meaning and are discarded.
+ * - Absolute globs will only match absolute paths, etc.
+ * - Empty globs will match nothing.
+ * - Any special glob syntax must be contained to one path segment. For example,
+ * `?(foo|bar/baz)` is invalid. The separator will take precedence and the
+ * first segment ends with an unclosed group.
+ * - If a path segment ends with unclosed groups or a dangling escape prefix, a
+ * parse error has occurred. Every character for that segment is taken
+ * literally in this event.
+ *
+ * Limitations:
+ * - A negative group like `!(foo|bar)` will wrongly be converted to a negative
+ * look-ahead followed by a wildcard. This means that `!(foo).js` will wrongly
+ * fail to match `foobar.js`, even though `foobar` is not `foo`. Effectively,
+ * `!(foo|bar)` is treated like `!(@(foo|bar)*)`. This will work correctly if
+ * the group occurs not nested at the end of the segment.
+ *
+ * @example Usage
+ * ```ts
+ * import { globToRegExp } from "@std/path/posix/glob-to-regexp";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(globToRegExp("*.js"), /^[^/]*\.js\/*$/);
+ * ```
+ *
+ * @param glob Glob string to convert.
+ * @param options Conversion options.
+ * @returns The regular expression equivalent to the glob.
+ */ function globToRegExp(glob, options = {}) {
+ return _globToRegExp(constants, glob, options);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Test whether the given string is a glob.
+ *
+ * @example Usage
+ * ```ts
+ * import { isGlob } from "@std/path/is-glob";
+ * import { assert } from "@std/assert";
+ *
+ * assert(!isGlob("foo/bar/../baz"));
+ * assert(isGlob("foo/*ar/../baz"));
+ * ```
+ *
+ * @param str String to test.
+ * @returns `true` if the given string is a glob, otherwise `false`
+ */ function isGlob(str) {
+ const chars = {
+ "{": "}",
+ "(": ")",
+ "[": "]"
+ };
+ const regex = /\\(.)|(^!|\*|\?|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/;
+ if (str === "") {
+ return false;
+ }
+ let match;
+ while(match = regex.exec(str)){
+ if (match[2]) return true;
+ let idx = match.index + match[0].length;
+ // if an open bracket/brace/paren is escaped,
+ // set the index to the next closing character
+ const open = match[1];
+ const close = open ? chars[open] : null;
+ if (open && close) {
+ const n = str.indexOf(close, idx);
+ if (n !== -1) {
+ idx = n + 1;
+ }
+ }
+ str = str.slice(idx);
+ }
+ return false;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Like normalize(), but doesn't collapse "**\/.." when `globstar` is true.
+ *
+ * @example Usage
+ * ```ts
+ * import { normalizeGlob } from "@std/path/posix/normalize-glob";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const path = normalizeGlob("foo/bar/../*", { globstar: true });
+ * assertEquals(path, "foo/*");
+ * ```
+ *
+ * @param glob The glob to normalize.
+ * @param options The options to use.
+ * @returns The normalized path.
+ */ function normalizeGlob(glob, { globstar = false } = {}) {
+ if (glob.match(/\0/g)) {
+ throw new Error(`Glob contains invalid characters: "${glob}"`);
+ }
+ if (!globstar) {
+ return normalize(glob);
+ }
+ const s = SEPARATOR_PATTERN.source;
+ const badParentPattern = new RegExp(`(?<=(${s}|^)\\*\\*${s})\\.\\.(?=${s}|$)`, "g");
+ return normalize(glob.replace(badParentPattern, "\0")).replace(/\0/g, "..");
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Like join(), but doesn't collapse "**\/.." when `globstar` is true.
+ *
+ * @example Usage
+ * ```ts
+ * import { joinGlobs } from "@std/path/posix/join-globs";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const path = joinGlobs(["foo", "bar", "**"], { globstar: true });
+ * assertEquals(path, "foo/bar/**");
+ * ```
+ *
+ * @param globs The globs to join.
+ * @param options The options to use.
+ * @returns The joined path.
+ */ function joinGlobs(globs, { extended = true, globstar = false } = {}) {
+ if (!globstar || globs.length === 0) {
+ return join(...globs);
+ }
+ let joined;
+ for (const glob of globs){
+ const path = glob;
+ if (path.length > 0) {
+ if (!joined) joined = path;
+ else joined += `${SEPARATOR}${path}`;
+ }
+ }
+ if (!joined) return ".";
+ return normalizeGlob(joined, {
+ extended,
+ globstar
+ });
+}
+
+export { DELIMITER, SEPARATOR, SEPARATOR_PATTERN, basename, common, dirname, extname, format, fromFileUrl, globToRegExp, isAbsolute, isGlob, join, joinGlobs, normalize, normalizeGlob, parse, relative, resolve, toFileUrl, toNamespacedPath };
diff --git a/node_modules/@eslint/config-array/dist/esm/std__path/windows.js b/node_modules/@eslint/config-array/dist/esm/std__path/windows.js
new file mode 100644
index 000000000..ae8759d8f
--- /dev/null
+++ b/node_modules/@eslint/config-array/dist/esm/std__path/windows.js
@@ -0,0 +1,1647 @@
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// Copyright the Browserify authors. MIT License.
+function assertPath(path) {
+ if (typeof path !== "string") {
+ throw new TypeError(`Path must be a string, received "${JSON.stringify(path)}"`);
+ }
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function stripSuffix(name, suffix) {
+ if (suffix.length >= name.length) {
+ return name;
+ }
+ const lenDiff = name.length - suffix.length;
+ for(let i = suffix.length - 1; i >= 0; --i){
+ if (name.charCodeAt(lenDiff + i) !== suffix.charCodeAt(i)) {
+ return name;
+ }
+ }
+ return name.slice(0, -suffix.length);
+}
+function lastPathSegment(path, isSep, start = 0) {
+ let matchedNonSeparator = false;
+ let end = path.length;
+ for(let i = path.length - 1; i >= start; --i){
+ if (isSep(path.charCodeAt(i))) {
+ if (matchedNonSeparator) {
+ start = i + 1;
+ break;
+ }
+ } else if (!matchedNonSeparator) {
+ matchedNonSeparator = true;
+ end = i + 1;
+ }
+ }
+ return path.slice(start, end);
+}
+function assertArgs$1(path, suffix) {
+ assertPath(path);
+ if (path.length === 0) return path;
+ if (typeof suffix !== "string") {
+ throw new TypeError(`Suffix must be a string, received "${JSON.stringify(suffix)}"`);
+ }
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// Copyright the Browserify authors. MIT License.
+// Ported from https://github.com/browserify/path-browserify/
+// This module is browser compatible.
+// Alphabet chars.
+const CHAR_UPPERCASE_A = 65; /* A */
+const CHAR_LOWERCASE_A = 97; /* a */
+const CHAR_UPPERCASE_Z = 90; /* Z */
+const CHAR_LOWERCASE_Z = 122; /* z */
+// Non-alphabetic chars.
+const CHAR_DOT = 46; /* . */
+const CHAR_FORWARD_SLASH = 47; /* / */
+const CHAR_BACKWARD_SLASH = 92; /* \ */
+const CHAR_COLON = 58; /* : */
+const CHAR_QUESTION_MARK = 63; /* ? */
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// Copyright the Browserify authors. MIT License.
+// Ported from https://github.com/browserify/path-browserify/
+// This module is browser compatible.
+function stripTrailingSeparators(segment, isSep) {
+ if (segment.length <= 1) {
+ return segment;
+ }
+ let end = segment.length;
+ for(let i = segment.length - 1; i > 0; i--){
+ if (isSep(segment.charCodeAt(i))) {
+ end = i;
+ } else {
+ break;
+ }
+ }
+ return segment.slice(0, end);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// Copyright the Browserify authors. MIT License.
+// Ported from https://github.com/browserify/path-browserify/
+// This module is browser compatible.
+function isPosixPathSeparator(code) {
+ return code === CHAR_FORWARD_SLASH;
+}
+function isPathSeparator(code) {
+ return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;
+}
+function isWindowsDeviceRoot(code) {
+ return code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z || code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Return the last portion of a `path`.
+ * Trailing directory separators are ignored, and optional suffix is removed.
+ *
+ * @example Usage
+ * ```ts
+ * import { basename } from "@std/path/windows/basename";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(basename("C:\\user\\Documents\\"), "Documents");
+ * assertEquals(basename("C:\\user\\Documents\\image.png"), "image.png");
+ * assertEquals(basename("C:\\user\\Documents\\image.png", ".png"), "image");
+ * ```
+ *
+ * Note: If you are working with file URLs,
+ * use the new version of `basename` from `@std/path/windows/unstable-basename`.
+ *
+ * @param path The path to extract the name from.
+ * @param suffix The suffix to remove from extracted name.
+ * @returns The extracted name.
+ */ function basename(path, suffix = "") {
+ assertArgs$1(path, suffix);
+ // Check for a drive letter prefix so as not to mistake the following
+ // path separator as an extra separator at the end of the path that can be
+ // disregarded
+ let start = 0;
+ if (path.length >= 2) {
+ const drive = path.charCodeAt(0);
+ if (isWindowsDeviceRoot(drive)) {
+ if (path.charCodeAt(1) === CHAR_COLON) start = 2;
+ }
+ }
+ const lastSegment = lastPathSegment(path, isPathSeparator, start);
+ const strippedSegment = stripTrailingSeparators(lastSegment, isPathSeparator);
+ return suffix ? stripSuffix(strippedSegment, suffix) : strippedSegment;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * The character used to separate entries in the PATH environment variable.
+ */ const DELIMITER = ";";
+/**
+ * The character used to separate components of a file path.
+ */ const SEPARATOR = "\\";
+/**
+ * A regular expression that matches one or more path separators.
+ */ const SEPARATOR_PATTERN = /[\\/]+/;
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function assertArg$3(path) {
+ assertPath(path);
+ if (path.length === 0) return ".";
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Return the directory path of a `path`.
+ *
+ * @example Usage
+ * ```ts
+ * import { dirname } from "@std/path/windows/dirname";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const dir = dirname("C:\\foo\\bar\\baz.ext");
+ * assertEquals(dir, "C:\\foo\\bar");
+ * ```
+ *
+ * Note: If you are working with file URLs,
+ * use the new version of `dirname` from `@std/path/windows/unstable-dirname`.
+ *
+ * @param path The path to get the directory from.
+ * @returns The directory path.
+ */ function dirname(path) {
+ assertArg$3(path);
+ const len = path.length;
+ let rootEnd = -1;
+ let end = -1;
+ let matchedSlash = true;
+ let offset = 0;
+ const code = path.charCodeAt(0);
+ // Try to match a root
+ if (len > 1) {
+ if (isPathSeparator(code)) {
+ // Possible UNC root
+ rootEnd = offset = 1;
+ if (isPathSeparator(path.charCodeAt(1))) {
+ // Matched double path separator at beginning
+ let j = 2;
+ let last = j;
+ // Match 1 or more non-path separators
+ for(; j < len; ++j){
+ if (isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j < len && j !== last) {
+ // Matched!
+ last = j;
+ // Match 1 or more path separators
+ for(; j < len; ++j){
+ if (!isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j < len && j !== last) {
+ // Matched!
+ last = j;
+ // Match 1 or more non-path separators
+ for(; j < len; ++j){
+ if (isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j === len) {
+ // We matched a UNC root only
+ return path;
+ }
+ if (j !== last) {
+ // We matched a UNC root with leftovers
+ // Offset by 1 to include the separator after the UNC root to
+ // treat it as a "normal root" on top of a (UNC) root
+ rootEnd = offset = j + 1;
+ }
+ }
+ }
+ }
+ } else if (isWindowsDeviceRoot(code)) {
+ // Possible device root
+ if (path.charCodeAt(1) === CHAR_COLON) {
+ rootEnd = offset = 2;
+ if (len > 2) {
+ if (isPathSeparator(path.charCodeAt(2))) rootEnd = offset = 3;
+ }
+ }
+ }
+ } else if (isPathSeparator(code)) {
+ // `path` contains just a path separator, exit early to avoid
+ // unnecessary work
+ return path;
+ }
+ for(let i = len - 1; i >= offset; --i){
+ if (isPathSeparator(path.charCodeAt(i))) {
+ if (!matchedSlash) {
+ end = i;
+ break;
+ }
+ } else {
+ // We saw the first non-path separator
+ matchedSlash = false;
+ }
+ }
+ if (end === -1) {
+ if (rootEnd === -1) return ".";
+ else end = rootEnd;
+ }
+ return stripTrailingSeparators(path.slice(0, end), isPosixPathSeparator);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Return the extension of the `path` with leading period.
+ *
+ * @example Usage
+ * ```ts
+ * import { extname } from "@std/path/windows/extname";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const ext = extname("file.ts");
+ * assertEquals(ext, ".ts");
+ * ```
+ *
+ * Note: If you are working with file URLs,
+ * use the new version of `extname` from `@std/path/windows/unstable-extname`.
+ *
+ * @param path The path to get the extension from.
+ * @returns The extension of the `path`.
+ */ function extname(path) {
+ assertPath(path);
+ let start = 0;
+ let startDot = -1;
+ let startPart = 0;
+ let end = -1;
+ let matchedSlash = true;
+ // Track the state of characters (if any) we see before our first dot and
+ // after any path separator we find
+ let preDotState = 0;
+ // Check for a drive letter prefix so as not to mistake the following
+ // path separator as an extra separator at the end of the path that can be
+ // disregarded
+ if (path.length >= 2 && path.charCodeAt(1) === CHAR_COLON && isWindowsDeviceRoot(path.charCodeAt(0))) {
+ start = startPart = 2;
+ }
+ for(let i = path.length - 1; i >= start; --i){
+ const code = path.charCodeAt(i);
+ if (isPathSeparator(code)) {
+ // If we reached a path separator that was not part of a set of path
+ // separators at the end of the string, stop now
+ if (!matchedSlash) {
+ startPart = i + 1;
+ break;
+ }
+ continue;
+ }
+ if (end === -1) {
+ // We saw the first non-path separator, mark this as the end of our
+ // extension
+ matchedSlash = false;
+ end = i + 1;
+ }
+ if (code === CHAR_DOT) {
+ // If this is our first dot, mark it as the start of our extension
+ if (startDot === -1) startDot = i;
+ else if (preDotState !== 1) preDotState = 1;
+ } else if (startDot !== -1) {
+ // We saw a non-dot and non-path separator before our dot, so we should
+ // have a good chance at having a non-empty extension
+ preDotState = -1;
+ }
+ }
+ if (startDot === -1 || end === -1 || // We saw a non-dot character immediately before the dot
+ preDotState === 0 || // The (right-most) trimmed path component is exactly '..'
+ preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
+ return "";
+ }
+ return path.slice(startDot, end);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function _format(sep, pathObject) {
+ const dir = pathObject.dir || pathObject.root;
+ const base = pathObject.base || (pathObject.name ?? "") + (pathObject.ext ?? "");
+ if (!dir) return base;
+ if (base === sep) return dir;
+ if (dir === pathObject.root) return dir + base;
+ return dir + sep + base;
+}
+function assertArg$2(pathObject) {
+ if (pathObject === null || typeof pathObject !== "object") {
+ throw new TypeError(`The "pathObject" argument must be of type Object, received type "${typeof pathObject}"`);
+ }
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Generate a path from `ParsedPath` object.
+ *
+ * @example Usage
+ * ```ts
+ * import { format } from "@std/path/windows/format";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const path = format({
+ * root: "C:\\",
+ * dir: "C:\\path\\dir",
+ * base: "file.txt",
+ * ext: ".txt",
+ * name: "file"
+ * });
+ * assertEquals(path, "C:\\path\\dir\\file.txt");
+ * ```
+ *
+ * @param pathObject The path object to format.
+ * @returns The formatted path.
+ */ function format(pathObject) {
+ assertArg$2(pathObject);
+ return _format("\\", pathObject);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function assertArg$1(url) {
+ url = url instanceof URL ? url : new URL(url);
+ if (url.protocol !== "file:") {
+ throw new TypeError(`URL must be a file URL: received "${url.protocol}"`);
+ }
+ return url;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Converts a file URL to a path string.
+ *
+ * @example Usage
+ * ```ts
+ * import { fromFileUrl } from "@std/path/windows/from-file-url";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(fromFileUrl("file:///home/foo"), "\\home\\foo");
+ * assertEquals(fromFileUrl("file:///C:/Users/foo"), "C:\\Users\\foo");
+ * assertEquals(fromFileUrl("file://localhost/home/foo"), "\\home\\foo");
+ * ```
+ *
+ * @param url The file URL to convert.
+ * @returns The path string.
+ */ function fromFileUrl(url) {
+ url = assertArg$1(url);
+ let path = decodeURIComponent(url.pathname.replace(/\//g, "\\").replace(/%(?![0-9A-Fa-f]{2})/g, "%25")).replace(/^\\*([A-Za-z]:)(\\|$)/, "$1\\");
+ if (url.hostname !== "") {
+ // Note: The `URL` implementation guarantees that the drive letter and
+ // hostname are mutually exclusive. Otherwise it would not have been valid
+ // to append the hostname and path like this.
+ path = `\\\\${url.hostname}${path}`;
+ }
+ return path;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Verifies whether provided path is absolute.
+ *
+ * @example Usage
+ * ```ts
+ * import { isAbsolute } from "@std/path/windows/is-absolute";
+ * import { assert, assertFalse } from "@std/assert";
+ *
+ * assert(isAbsolute("C:\\foo\\bar"));
+ * assertFalse(isAbsolute("..\\baz"));
+ * ```
+ *
+ * @param path The path to verify.
+ * @returns `true` if the path is absolute, `false` otherwise.
+ */ function isAbsolute(path) {
+ assertPath(path);
+ const len = path.length;
+ if (len === 0) return false;
+ const code = path.charCodeAt(0);
+ if (isPathSeparator(code)) {
+ return true;
+ } else if (isWindowsDeviceRoot(code)) {
+ // Possible device root
+ if (len > 2 && path.charCodeAt(1) === CHAR_COLON) {
+ if (isPathSeparator(path.charCodeAt(2))) return true;
+ }
+ }
+ return false;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function assertArg(path) {
+ assertPath(path);
+ if (path.length === 0) return ".";
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// Copyright the Browserify authors. MIT License.
+// Ported from https://github.com/browserify/path-browserify/
+// This module is browser compatible.
+// Resolves . and .. elements in a path with directory names
+function normalizeString(path, allowAboveRoot, separator, isPathSeparator) {
+ let res = "";
+ let lastSegmentLength = 0;
+ let lastSlash = -1;
+ let dots = 0;
+ let code;
+ for(let i = 0; i <= path.length; ++i){
+ if (i < path.length) code = path.charCodeAt(i);
+ else if (isPathSeparator(code)) break;
+ else code = CHAR_FORWARD_SLASH;
+ if (isPathSeparator(code)) {
+ if (lastSlash === i - 1 || dots === 1) ; else if (lastSlash !== i - 1 && dots === 2) {
+ if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== CHAR_DOT || res.charCodeAt(res.length - 2) !== CHAR_DOT) {
+ if (res.length > 2) {
+ const lastSlashIndex = res.lastIndexOf(separator);
+ if (lastSlashIndex === -1) {
+ res = "";
+ lastSegmentLength = 0;
+ } else {
+ res = res.slice(0, lastSlashIndex);
+ lastSegmentLength = res.length - 1 - res.lastIndexOf(separator);
+ }
+ lastSlash = i;
+ dots = 0;
+ continue;
+ } else if (res.length === 2 || res.length === 1) {
+ res = "";
+ lastSegmentLength = 0;
+ lastSlash = i;
+ dots = 0;
+ continue;
+ }
+ }
+ if (allowAboveRoot) {
+ if (res.length > 0) res += `${separator}..`;
+ else res = "..";
+ lastSegmentLength = 2;
+ }
+ } else {
+ if (res.length > 0) res += separator + path.slice(lastSlash + 1, i);
+ else res = path.slice(lastSlash + 1, i);
+ lastSegmentLength = i - lastSlash - 1;
+ }
+ lastSlash = i;
+ dots = 0;
+ } else if (code === CHAR_DOT && dots !== -1) {
+ ++dots;
+ } else {
+ dots = -1;
+ }
+ }
+ return res;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Normalize the `path`, resolving `'..'` and `'.'` segments.
+ * Note that resolving these segments does not necessarily mean that all will be eliminated.
+ * A `'..'` at the top-level will be preserved, and an empty path is canonically `'.'`.
+ *
+ * @example Usage
+ * ```ts
+ * import { normalize } from "@std/path/windows/normalize";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const normalized = normalize("C:\\foo\\..\\bar");
+ * assertEquals(normalized, "C:\\bar");
+ * ```
+ *
+ * Note: If you are working with file URLs,
+ * use the new version of `normalize` from `@std/path/windows/unstable-normalize`.
+ *
+ * @param path The path to normalize
+ * @returns The normalized path
+ */ function normalize(path) {
+ assertArg(path);
+ const len = path.length;
+ let rootEnd = 0;
+ let device;
+ let isAbsolute = false;
+ const code = path.charCodeAt(0);
+ // Try to match a root
+ if (len > 1) {
+ if (isPathSeparator(code)) {
+ // Possible UNC root
+ // If we started with a separator, we know we at least have an absolute
+ // path of some kind (UNC or otherwise)
+ isAbsolute = true;
+ if (isPathSeparator(path.charCodeAt(1))) {
+ // Matched double path separator at beginning
+ let j = 2;
+ let last = j;
+ // Match 1 or more non-path separators
+ for(; j < len; ++j){
+ if (isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j < len && j !== last) {
+ const firstPart = path.slice(last, j);
+ // Matched!
+ last = j;
+ // Match 1 or more path separators
+ for(; j < len; ++j){
+ if (!isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j < len && j !== last) {
+ // Matched!
+ last = j;
+ // Match 1 or more non-path separators
+ for(; j < len; ++j){
+ if (isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j === len) {
+ // We matched a UNC root only
+ // Return the normalized version of the UNC root since there
+ // is nothing left to process
+ return `\\\\${firstPart}\\${path.slice(last)}\\`;
+ } else if (j !== last) {
+ // We matched a UNC root with leftovers
+ device = `\\\\${firstPart}\\${path.slice(last, j)}`;
+ rootEnd = j;
+ }
+ }
+ }
+ } else {
+ rootEnd = 1;
+ }
+ } else if (isWindowsDeviceRoot(code)) {
+ // Possible device root
+ if (path.charCodeAt(1) === CHAR_COLON) {
+ device = path.slice(0, 2);
+ rootEnd = 2;
+ if (len > 2) {
+ if (isPathSeparator(path.charCodeAt(2))) {
+ // Treat separator following drive name as an absolute path
+ // indicator
+ isAbsolute = true;
+ rootEnd = 3;
+ }
+ }
+ }
+ }
+ } else if (isPathSeparator(code)) {
+ // `path` contains just a path separator, exit early to avoid unnecessary
+ // work
+ return "\\";
+ }
+ let tail;
+ if (rootEnd < len) {
+ tail = normalizeString(path.slice(rootEnd), !isAbsolute, "\\", isPathSeparator);
+ } else {
+ tail = "";
+ }
+ if (tail.length === 0 && !isAbsolute) tail = ".";
+ if (tail.length > 0 && isPathSeparator(path.charCodeAt(len - 1))) {
+ tail += "\\";
+ }
+ if (device === undefined) {
+ if (isAbsolute) {
+ if (tail.length > 0) return `\\${tail}`;
+ else return "\\";
+ }
+ return tail;
+ } else if (isAbsolute) {
+ if (tail.length > 0) return `${device}\\${tail}`;
+ else return `${device}\\`;
+ }
+ return device + tail;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Join all given a sequence of `paths`,then normalizes the resulting path.
+ *
+ * @example Usage
+ * ```ts
+ * import { join } from "@std/path/windows/join";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const joined = join("C:\\foo", "bar", "baz\\..");
+ * assertEquals(joined, "C:\\foo\\bar");
+ * ```
+ *
+ * Note: If you are working with file URLs,
+ * use the new version of `join` from `@std/path/windows/unstable-join`.
+ *
+ * @param paths The paths to join.
+ * @returns The joined path.
+ */ function join(...paths) {
+ paths.forEach((path)=>assertPath(path));
+ paths = paths.filter((path)=>path.length > 0);
+ if (paths.length === 0) return ".";
+ // Make sure that the joined path doesn't start with two slashes, because
+ // normalize() will mistake it for an UNC path then.
+ //
+ // This step is skipped when it is very clear that the user actually
+ // intended to point at an UNC path. This is assumed when the first
+ // non-empty string arguments starts with exactly two slashes followed by
+ // at least one more non-slash character.
+ //
+ // Note that for normalize() to treat a path as an UNC path it needs to
+ // have at least 2 components, so we don't filter for that here.
+ // This means that the user can use join to construct UNC paths from
+ // a server name and a share name; for example:
+ // path.join('//server', 'share') -> '\\\\server\\share\\'
+ let needsReplace = true;
+ let slashCount = 0;
+ const firstPart = paths[0];
+ if (isPathSeparator(firstPart.charCodeAt(0))) {
+ ++slashCount;
+ const firstLen = firstPart.length;
+ if (firstLen > 1) {
+ if (isPathSeparator(firstPart.charCodeAt(1))) {
+ ++slashCount;
+ if (firstLen > 2) {
+ if (isPathSeparator(firstPart.charCodeAt(2))) ++slashCount;
+ else {
+ // We matched a UNC path in the first part
+ needsReplace = false;
+ }
+ }
+ }
+ }
+ }
+ let joined = paths.join("\\");
+ if (needsReplace) {
+ // Find any more consecutive slashes we need to replace
+ for(; slashCount < joined.length; ++slashCount){
+ if (!isPathSeparator(joined.charCodeAt(slashCount))) break;
+ }
+ // Replace the slashes if needed
+ if (slashCount >= 2) joined = `\\${joined.slice(slashCount)}`;
+ }
+ return normalize(joined);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Return a `ParsedPath` object of the `path`.
+ *
+ * @example Usage
+ * ```ts
+ * import { parse } from "@std/path/windows/parse";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const parsed = parse("C:\\foo\\bar\\baz.ext");
+ * assertEquals(parsed, {
+ * root: "C:\\",
+ * dir: "C:\\foo\\bar",
+ * base: "baz.ext",
+ * ext: ".ext",
+ * name: "baz",
+ * });
+ * ```
+ *
+ * @param path The path to parse.
+ * @returns The `ParsedPath` object.
+ */ function parse(path) {
+ assertPath(path);
+ const ret = {
+ root: "",
+ dir: "",
+ base: "",
+ ext: "",
+ name: ""
+ };
+ const len = path.length;
+ if (len === 0) return ret;
+ let rootEnd = 0;
+ let code = path.charCodeAt(0);
+ // Try to match a root
+ if (len > 1) {
+ if (isPathSeparator(code)) {
+ // Possible UNC root
+ rootEnd = 1;
+ if (isPathSeparator(path.charCodeAt(1))) {
+ // Matched double path separator at beginning
+ let j = 2;
+ let last = j;
+ // Match 1 or more non-path separators
+ for(; j < len; ++j){
+ if (isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j < len && j !== last) {
+ // Matched!
+ last = j;
+ // Match 1 or more path separators
+ for(; j < len; ++j){
+ if (!isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j < len && j !== last) {
+ // Matched!
+ last = j;
+ // Match 1 or more non-path separators
+ for(; j < len; ++j){
+ if (isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j === len) {
+ // We matched a UNC root only
+ rootEnd = j;
+ } else if (j !== last) {
+ // We matched a UNC root with leftovers
+ rootEnd = j + 1;
+ }
+ }
+ }
+ }
+ } else if (isWindowsDeviceRoot(code)) {
+ // Possible device root
+ if (path.charCodeAt(1) === CHAR_COLON) {
+ rootEnd = 2;
+ if (len > 2) {
+ if (isPathSeparator(path.charCodeAt(2))) {
+ if (len === 3) {
+ // `path` contains just a drive root, exit early to avoid
+ // unnecessary work
+ ret.root = ret.dir = path;
+ ret.base = "\\";
+ return ret;
+ }
+ rootEnd = 3;
+ }
+ } else {
+ // `path` contains just a relative drive root, exit early to avoid
+ // unnecessary work
+ ret.root = ret.dir = path;
+ return ret;
+ }
+ }
+ }
+ } else if (isPathSeparator(code)) {
+ // `path` contains just a path separator, exit early to avoid
+ // unnecessary work
+ ret.root = ret.dir = path;
+ ret.base = "\\";
+ return ret;
+ }
+ if (rootEnd > 0) ret.root = path.slice(0, rootEnd);
+ let startDot = -1;
+ let startPart = rootEnd;
+ let end = -1;
+ let matchedSlash = true;
+ let i = path.length - 1;
+ // Track the state of characters (if any) we see before our first dot and
+ // after any path separator we find
+ let preDotState = 0;
+ // Get non-dir info
+ for(; i >= rootEnd; --i){
+ code = path.charCodeAt(i);
+ if (isPathSeparator(code)) {
+ // If we reached a path separator that was not part of a set of path
+ // separators at the end of the string, stop now
+ if (!matchedSlash) {
+ startPart = i + 1;
+ break;
+ }
+ continue;
+ }
+ if (end === -1) {
+ // We saw the first non-path separator, mark this as the end of our
+ // extension
+ matchedSlash = false;
+ end = i + 1;
+ }
+ if (code === CHAR_DOT) {
+ // If this is our first dot, mark it as the start of our extension
+ if (startDot === -1) startDot = i;
+ else if (preDotState !== 1) preDotState = 1;
+ } else if (startDot !== -1) {
+ // We saw a non-dot and non-path separator before our dot, so we should
+ // have a good chance at having a non-empty extension
+ preDotState = -1;
+ }
+ }
+ if (startDot === -1 || end === -1 || // We saw a non-dot character immediately before the dot
+ preDotState === 0 || // The (right-most) trimmed path component is exactly '..'
+ preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
+ if (end !== -1) {
+ ret.base = ret.name = path.slice(startPart, end);
+ }
+ } else {
+ ret.name = path.slice(startPart, startDot);
+ ret.base = path.slice(startPart, end);
+ ret.ext = path.slice(startDot, end);
+ }
+ // Fallback to '\' in case there is no basename
+ ret.base = ret.base || "\\";
+ // If the directory is the root, use the entire root as the `dir` including
+ // the trailing slash if any (`C:\abc` -> `C:\`). Otherwise, strip out the
+ // trailing slash (`C:\abc\def` -> `C:\abc`).
+ if (startPart > 0 && startPart !== rootEnd) {
+ ret.dir = path.slice(0, startPart - 1);
+ } else ret.dir = ret.root;
+ return ret;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Resolves path segments into a `path`.
+ *
+ * @example Usage
+ * ```ts
+ * import { resolve } from "@std/path/windows/resolve";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const resolved = resolve("C:\\foo\\bar", "..\\baz");
+ * assertEquals(resolved, "C:\\foo\\baz");
+ * ```
+ *
+ * @param pathSegments The path segments to process to path
+ * @returns The resolved path
+ */ function resolve(...pathSegments) {
+ let resolvedDevice = "";
+ let resolvedTail = "";
+ let resolvedAbsolute = false;
+ for(let i = pathSegments.length - 1; i >= -1; i--){
+ let path;
+ // deno-lint-ignore no-explicit-any
+ const { Deno } = globalThis;
+ if (i >= 0) {
+ path = pathSegments[i];
+ } else if (!resolvedDevice) {
+ if (typeof Deno?.cwd !== "function") {
+ throw new TypeError("Resolved a drive-letter-less path without a current working directory (CWD)");
+ }
+ path = Deno.cwd();
+ } else {
+ if (typeof Deno?.env?.get !== "function" || typeof Deno?.cwd !== "function") {
+ throw new TypeError("Resolved a relative path without a current working directory (CWD)");
+ }
+ path = Deno.cwd();
+ // Verify that a cwd was found and that it actually points
+ // to our drive. If not, default to the drive's root.
+ if (path === undefined || path.slice(0, 3).toLowerCase() !== `${resolvedDevice.toLowerCase()}\\`) {
+ path = `${resolvedDevice}\\`;
+ }
+ }
+ assertPath(path);
+ const len = path.length;
+ // Skip empty entries
+ if (len === 0) continue;
+ let rootEnd = 0;
+ let device = "";
+ let isAbsolute = false;
+ const code = path.charCodeAt(0);
+ // Try to match a root
+ if (len > 1) {
+ if (isPathSeparator(code)) {
+ // Possible UNC root
+ // If we started with a separator, we know we at least have an
+ // absolute path of some kind (UNC or otherwise)
+ isAbsolute = true;
+ if (isPathSeparator(path.charCodeAt(1))) {
+ // Matched double path separator at beginning
+ let j = 2;
+ let last = j;
+ // Match 1 or more non-path separators
+ for(; j < len; ++j){
+ if (isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j < len && j !== last) {
+ const firstPart = path.slice(last, j);
+ // Matched!
+ last = j;
+ // Match 1 or more path separators
+ for(; j < len; ++j){
+ if (!isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j < len && j !== last) {
+ // Matched!
+ last = j;
+ // Match 1 or more non-path separators
+ for(; j < len; ++j){
+ if (isPathSeparator(path.charCodeAt(j))) break;
+ }
+ if (j === len) {
+ // We matched a UNC root only
+ device = `\\\\${firstPart}\\${path.slice(last)}`;
+ rootEnd = j;
+ } else if (j !== last) {
+ // We matched a UNC root with leftovers
+ device = `\\\\${firstPart}\\${path.slice(last, j)}`;
+ rootEnd = j;
+ }
+ }
+ }
+ } else {
+ rootEnd = 1;
+ }
+ } else if (isWindowsDeviceRoot(code)) {
+ // Possible device root
+ if (path.charCodeAt(1) === CHAR_COLON) {
+ device = path.slice(0, 2);
+ rootEnd = 2;
+ if (len > 2) {
+ if (isPathSeparator(path.charCodeAt(2))) {
+ // Treat separator following drive name as an absolute path
+ // indicator
+ isAbsolute = true;
+ rootEnd = 3;
+ }
+ }
+ }
+ }
+ } else if (isPathSeparator(code)) {
+ // `path` contains just a path separator
+ rootEnd = 1;
+ isAbsolute = true;
+ }
+ if (device.length > 0 && resolvedDevice.length > 0 && device.toLowerCase() !== resolvedDevice.toLowerCase()) {
+ continue;
+ }
+ if (resolvedDevice.length === 0 && device.length > 0) {
+ resolvedDevice = device;
+ }
+ if (!resolvedAbsolute) {
+ resolvedTail = `${path.slice(rootEnd)}\\${resolvedTail}`;
+ resolvedAbsolute = isAbsolute;
+ }
+ if (resolvedAbsolute && resolvedDevice.length > 0) break;
+ }
+ // At this point the path should be resolved to a full absolute path,
+ // but handle relative paths to be safe (might happen when Deno.cwd()
+ // fails)
+ // Normalize the tail path
+ resolvedTail = normalizeString(resolvedTail, !resolvedAbsolute, "\\", isPathSeparator);
+ return resolvedDevice + (resolvedAbsolute ? "\\" : "") + resolvedTail || ".";
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function assertArgs(from, to) {
+ assertPath(from);
+ assertPath(to);
+ if (from === to) return "";
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Return the relative path from `from` to `to` based on current working directory.
+ *
+ * An example in windws, for instance:
+ * from = 'C:\\orandea\\test\\aaa'
+ * to = 'C:\\orandea\\impl\\bbb'
+ * The output of the function should be: '..\\..\\impl\\bbb'
+ *
+ * @example Usage
+ * ```ts
+ * import { relative } from "@std/path/windows/relative";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const relativePath = relative("C:\\foobar\\test\\aaa", "C:\\foobar\\impl\\bbb");
+ * assertEquals(relativePath, "..\\..\\impl\\bbb");
+ * ```
+ *
+ * @param from The path from which to calculate the relative path
+ * @param to The path to which to calculate the relative path
+ * @returns The relative path from `from` to `to`
+ */ function relative(from, to) {
+ assertArgs(from, to);
+ const fromOrig = resolve(from);
+ const toOrig = resolve(to);
+ if (fromOrig === toOrig) return "";
+ from = fromOrig.toLowerCase();
+ to = toOrig.toLowerCase();
+ if (from === to) return "";
+ // Trim any leading backslashes
+ let fromStart = 0;
+ let fromEnd = from.length;
+ for(; fromStart < fromEnd; ++fromStart){
+ if (from.charCodeAt(fromStart) !== CHAR_BACKWARD_SLASH) break;
+ }
+ // Trim trailing backslashes (applicable to UNC paths only)
+ for(; fromEnd - 1 > fromStart; --fromEnd){
+ if (from.charCodeAt(fromEnd - 1) !== CHAR_BACKWARD_SLASH) break;
+ }
+ const fromLen = fromEnd - fromStart;
+ // Trim any leading backslashes
+ let toStart = 0;
+ let toEnd = to.length;
+ for(; toStart < toEnd; ++toStart){
+ if (to.charCodeAt(toStart) !== CHAR_BACKWARD_SLASH) break;
+ }
+ // Trim trailing backslashes (applicable to UNC paths only)
+ for(; toEnd - 1 > toStart; --toEnd){
+ if (to.charCodeAt(toEnd - 1) !== CHAR_BACKWARD_SLASH) break;
+ }
+ const toLen = toEnd - toStart;
+ // Compare paths to find the longest common path from root
+ const length = fromLen < toLen ? fromLen : toLen;
+ let lastCommonSep = -1;
+ let i = 0;
+ for(; i <= length; ++i){
+ if (i === length) {
+ if (toLen > length) {
+ if (to.charCodeAt(toStart + i) === CHAR_BACKWARD_SLASH) {
+ // We get here if `from` is the exact base path for `to`.
+ // For example: from='C:\\foo\\bar'; to='C:\\foo\\bar\\baz'
+ return toOrig.slice(toStart + i + 1);
+ } else if (i === 2) {
+ // We get here if `from` is the device root.
+ // For example: from='C:\\'; to='C:\\foo'
+ return toOrig.slice(toStart + i);
+ }
+ }
+ if (fromLen > length) {
+ if (from.charCodeAt(fromStart + i) === CHAR_BACKWARD_SLASH) {
+ // We get here if `to` is the exact base path for `from`.
+ // For example: from='C:\\foo\\bar'; to='C:\\foo'
+ lastCommonSep = i;
+ } else if (i === 2) {
+ // We get here if `to` is the device root.
+ // For example: from='C:\\foo\\bar'; to='C:\\'
+ lastCommonSep = 3;
+ }
+ }
+ break;
+ }
+ const fromCode = from.charCodeAt(fromStart + i);
+ const toCode = to.charCodeAt(toStart + i);
+ if (fromCode !== toCode) break;
+ else if (fromCode === CHAR_BACKWARD_SLASH) lastCommonSep = i;
+ }
+ // We found a mismatch before the first common path separator was seen, so
+ // return the original `to`.
+ if (i !== length && lastCommonSep === -1) {
+ return toOrig;
+ }
+ let out = "";
+ if (lastCommonSep === -1) lastCommonSep = 0;
+ // Generate the relative path based on the path difference between `to` and
+ // `from`
+ for(i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i){
+ if (i === fromEnd || from.charCodeAt(i) === CHAR_BACKWARD_SLASH) {
+ if (out.length === 0) out += "..";
+ else out += "\\..";
+ }
+ }
+ // Lastly, append the rest of the destination (`to`) path that comes after
+ // the common path parts
+ if (out.length > 0) {
+ return out + toOrig.slice(toStart + lastCommonSep, toEnd);
+ } else {
+ toStart += lastCommonSep;
+ if (toOrig.charCodeAt(toStart) === CHAR_BACKWARD_SLASH) ++toStart;
+ return toOrig.slice(toStart, toEnd);
+ }
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+const WHITESPACE_ENCODINGS = {
+ "\u0009": "%09",
+ "\u000A": "%0A",
+ "\u000B": "%0B",
+ "\u000C": "%0C",
+ "\u000D": "%0D",
+ "\u0020": "%20"
+};
+function encodeWhitespace(string) {
+ return string.replaceAll(/[\s]/g, (c)=>{
+ return WHITESPACE_ENCODINGS[c] ?? c;
+ });
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Converts a path string to a file URL.
+ *
+ * @example Usage
+ * ```ts
+ * import { toFileUrl } from "@std/path/windows/to-file-url";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(toFileUrl("\\home\\foo"), new URL("file:///home/foo"));
+ * assertEquals(toFileUrl("C:\\Users\\foo"), new URL("file:///C:/Users/foo"));
+ * assertEquals(toFileUrl("\\\\127.0.0.1\\home\\foo"), new URL("file://127.0.0.1/home/foo"));
+ * ```
+ * @param path The path to convert.
+ * @returns The file URL.
+ */ function toFileUrl(path) {
+ if (!isAbsolute(path)) {
+ throw new TypeError(`Path must be absolute: received "${path}"`);
+ }
+ const [, hostname, pathname] = path.match(/^(?:[/\\]{2}([^/\\]+)(?=[/\\](?:[^/\\]|$)))?(.*)/);
+ const url = new URL("file:///");
+ url.pathname = encodeWhitespace(pathname.replace(/%/g, "%25"));
+ if (hostname !== undefined && hostname !== "localhost") {
+ url.hostname = hostname;
+ if (!url.hostname) {
+ throw new TypeError(`Invalid hostname: "${url.hostname}"`);
+ }
+ }
+ return url;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Resolves path to a namespace path
+ *
+ * @example Usage
+ * ```ts
+ * import { toNamespacedPath } from "@std/path/windows/to-namespaced-path";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const namespaced = toNamespacedPath("C:\\foo\\bar");
+ * assertEquals(namespaced, "\\\\?\\C:\\foo\\bar");
+ * ```
+ *
+ * @param path The path to resolve to namespaced path
+ * @returns The resolved namespaced path
+ */ function toNamespacedPath(path) {
+ // Note: this will *probably* throw somewhere.
+ if (typeof path !== "string") return path;
+ if (path.length === 0) return "";
+ const resolvedPath = resolve(path);
+ if (resolvedPath.length >= 3) {
+ if (resolvedPath.charCodeAt(0) === CHAR_BACKWARD_SLASH) {
+ // Possible UNC root
+ if (resolvedPath.charCodeAt(1) === CHAR_BACKWARD_SLASH) {
+ const code = resolvedPath.charCodeAt(2);
+ if (code !== CHAR_QUESTION_MARK && code !== CHAR_DOT) {
+ // Matched non-long UNC root, convert the path to a long UNC path
+ return `\\\\?\\UNC\\${resolvedPath.slice(2)}`;
+ }
+ }
+ } else if (isWindowsDeviceRoot(resolvedPath.charCodeAt(0))) {
+ // Possible device root
+ if (resolvedPath.charCodeAt(1) === CHAR_COLON && resolvedPath.charCodeAt(2) === CHAR_BACKWARD_SLASH) {
+ // Matched device root, convert the path to a long UNC path
+ return `\\\\?\\${resolvedPath}`;
+ }
+ }
+ }
+ return path;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+function common$1(paths, sep) {
+ const [first = "", ...remaining] = paths;
+ const parts = first.split(sep);
+ let endOfPrefix = parts.length;
+ let append = "";
+ for (const path of remaining){
+ const compare = path.split(sep);
+ if (compare.length <= endOfPrefix) {
+ endOfPrefix = compare.length;
+ append = "";
+ }
+ for(let i = 0; i < endOfPrefix; i++){
+ if (compare[i] !== parts[i]) {
+ endOfPrefix = i;
+ append = i === 0 ? "" : sep;
+ break;
+ }
+ }
+ }
+ return parts.slice(0, endOfPrefix).join(sep) + append;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Determines the common path from a set of paths for Windows systems.
+ *
+ * @example Usage
+ * ```ts
+ * import { common } from "@std/path/windows/common";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const path = common([
+ * "C:\\foo\\bar",
+ * "C:\\foo\\baz",
+ * ]);
+ * assertEquals(path, "C:\\foo\\");
+ * ```
+ *
+ * @param paths The paths to compare.
+ * @returns The common path.
+ */ function common(paths) {
+ return common$1(paths, SEPARATOR);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Options for {@linkcode globToRegExp}, {@linkcode joinGlobs},
+ * {@linkcode normalizeGlob} and {@linkcode expandGlob}.
+ */ const REG_EXP_ESCAPE_CHARS = [
+ "!",
+ "$",
+ "(",
+ ")",
+ "*",
+ "+",
+ ".",
+ "=",
+ "?",
+ "[",
+ "\\",
+ "^",
+ "{",
+ "|"
+];
+const RANGE_ESCAPE_CHARS = [
+ "-",
+ "\\",
+ "]"
+];
+function _globToRegExp(c, glob, { extended = true, globstar: globstarOption = true, // os = osType,
+caseInsensitive = false } = {}) {
+ if (glob === "") {
+ return /(?!)/;
+ }
+ // Remove trailing separators.
+ let newLength = glob.length;
+ for(; newLength > 1 && c.seps.includes(glob[newLength - 1]); newLength--);
+ glob = glob.slice(0, newLength);
+ let regExpString = "";
+ // Terminates correctly. Trust that `j` is incremented every iteration.
+ for(let j = 0; j < glob.length;){
+ let segment = "";
+ const groupStack = [];
+ let inRange = false;
+ let inEscape = false;
+ let endsWithSep = false;
+ let i = j;
+ // Terminates with `i` at the non-inclusive end of the current segment.
+ for(; i < glob.length && !c.seps.includes(glob[i]); i++){
+ if (inEscape) {
+ inEscape = false;
+ const escapeChars = inRange ? RANGE_ESCAPE_CHARS : REG_EXP_ESCAPE_CHARS;
+ segment += escapeChars.includes(glob[i]) ? `\\${glob[i]}` : glob[i];
+ continue;
+ }
+ if (glob[i] === c.escapePrefix) {
+ inEscape = true;
+ continue;
+ }
+ if (glob[i] === "[") {
+ if (!inRange) {
+ inRange = true;
+ segment += "[";
+ if (glob[i + 1] === "!") {
+ i++;
+ segment += "^";
+ } else if (glob[i + 1] === "^") {
+ i++;
+ segment += "\\^";
+ }
+ continue;
+ } else if (glob[i + 1] === ":") {
+ let k = i + 1;
+ let value = "";
+ while(glob[k + 1] !== undefined && glob[k + 1] !== ":"){
+ value += glob[k + 1];
+ k++;
+ }
+ if (glob[k + 1] === ":" && glob[k + 2] === "]") {
+ i = k + 2;
+ if (value === "alnum") segment += "\\dA-Za-z";
+ else if (value === "alpha") segment += "A-Za-z";
+ else if (value === "ascii") segment += "\x00-\x7F";
+ else if (value === "blank") segment += "\t ";
+ else if (value === "cntrl") segment += "\x00-\x1F\x7F";
+ else if (value === "digit") segment += "\\d";
+ else if (value === "graph") segment += "\x21-\x7E";
+ else if (value === "lower") segment += "a-z";
+ else if (value === "print") segment += "\x20-\x7E";
+ else if (value === "punct") {
+ segment += "!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_‘{|}~";
+ } else if (value === "space") segment += "\\s\v";
+ else if (value === "upper") segment += "A-Z";
+ else if (value === "word") segment += "\\w";
+ else if (value === "xdigit") segment += "\\dA-Fa-f";
+ continue;
+ }
+ }
+ }
+ if (glob[i] === "]" && inRange) {
+ inRange = false;
+ segment += "]";
+ continue;
+ }
+ if (inRange) {
+ segment += glob[i];
+ continue;
+ }
+ if (glob[i] === ")" && groupStack.length > 0 && groupStack[groupStack.length - 1] !== "BRACE") {
+ segment += ")";
+ const type = groupStack.pop();
+ if (type === "!") {
+ segment += c.wildcard;
+ } else if (type !== "@") {
+ segment += type;
+ }
+ continue;
+ }
+ if (glob[i] === "|" && groupStack.length > 0 && groupStack[groupStack.length - 1] !== "BRACE") {
+ segment += "|";
+ continue;
+ }
+ if (glob[i] === "+" && extended && glob[i + 1] === "(") {
+ i++;
+ groupStack.push("+");
+ segment += "(?:";
+ continue;
+ }
+ if (glob[i] === "@" && extended && glob[i + 1] === "(") {
+ i++;
+ groupStack.push("@");
+ segment += "(?:";
+ continue;
+ }
+ if (glob[i] === "?") {
+ if (extended && glob[i + 1] === "(") {
+ i++;
+ groupStack.push("?");
+ segment += "(?:";
+ } else {
+ segment += ".";
+ }
+ continue;
+ }
+ if (glob[i] === "!" && extended && glob[i + 1] === "(") {
+ i++;
+ groupStack.push("!");
+ segment += "(?!";
+ continue;
+ }
+ if (glob[i] === "{") {
+ groupStack.push("BRACE");
+ segment += "(?:";
+ continue;
+ }
+ if (glob[i] === "}" && groupStack[groupStack.length - 1] === "BRACE") {
+ groupStack.pop();
+ segment += ")";
+ continue;
+ }
+ if (glob[i] === "," && groupStack[groupStack.length - 1] === "BRACE") {
+ segment += "|";
+ continue;
+ }
+ if (glob[i] === "*") {
+ if (extended && glob[i + 1] === "(") {
+ i++;
+ groupStack.push("*");
+ segment += "(?:";
+ } else {
+ const prevChar = glob[i - 1];
+ let numStars = 1;
+ while(glob[i + 1] === "*"){
+ i++;
+ numStars++;
+ }
+ const nextChar = glob[i + 1];
+ if (globstarOption && numStars === 2 && [
+ ...c.seps,
+ undefined
+ ].includes(prevChar) && [
+ ...c.seps,
+ undefined
+ ].includes(nextChar)) {
+ segment += c.globstar;
+ endsWithSep = true;
+ } else {
+ segment += c.wildcard;
+ }
+ }
+ continue;
+ }
+ segment += REG_EXP_ESCAPE_CHARS.includes(glob[i]) ? `\\${glob[i]}` : glob[i];
+ }
+ // Check for unclosed groups or a dangling backslash.
+ if (groupStack.length > 0 || inRange || inEscape) {
+ // Parse failure. Take all characters from this segment literally.
+ segment = "";
+ for (const c of glob.slice(j, i)){
+ segment += REG_EXP_ESCAPE_CHARS.includes(c) ? `\\${c}` : c;
+ endsWithSep = false;
+ }
+ }
+ regExpString += segment;
+ if (!endsWithSep) {
+ regExpString += i < glob.length ? c.sep : c.sepMaybe;
+ endsWithSep = true;
+ }
+ // Terminates with `i` at the start of the next segment.
+ while(c.seps.includes(glob[i]))i++;
+ j = i;
+ }
+ regExpString = `^${regExpString}$`;
+ return new RegExp(regExpString, caseInsensitive ? "i" : "");
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+const constants = {
+ sep: "(?:\\\\|/)+",
+ sepMaybe: "(?:\\\\|/)*",
+ seps: [
+ "\\",
+ "/"
+ ],
+ globstar: "(?:[^\\\\/]*(?:\\\\|/|$)+)*",
+ wildcard: "[^\\\\/]*",
+ escapePrefix: "`"
+};
+/** Convert a glob string to a regular expression.
+ *
+ * Tries to match bash glob expansion as closely as possible.
+ *
+ * Basic glob syntax:
+ * - `*` - Matches everything without leaving the path segment.
+ * - `?` - Matches any single character.
+ * - `{foo,bar}` - Matches `foo` or `bar`.
+ * - `[abcd]` - Matches `a`, `b`, `c` or `d`.
+ * - `[a-d]` - Matches `a`, `b`, `c` or `d`.
+ * - `[!abcd]` - Matches any single character besides `a`, `b`, `c` or `d`.
+ * - `[[::]]` - Matches any character belonging to ``.
+ * - `[[:alnum:]]` - Matches any digit or letter.
+ * - `[[:digit:]abc]` - Matches any digit, `a`, `b` or `c`.
+ * - See https://facelessuser.github.io/wcmatch/glob/#posix-character-classes
+ * for a complete list of supported character classes.
+ * - `\` - Escapes the next character for an `os` other than `"windows"`.
+ * - \` - Escapes the next character for `os` set to `"windows"`.
+ * - `/` - Path separator.
+ * - `\` - Additional path separator only for `os` set to `"windows"`.
+ *
+ * Extended syntax:
+ * - Requires `{ extended: true }`.
+ * - `?(foo|bar)` - Matches 0 or 1 instance of `{foo,bar}`.
+ * - `@(foo|bar)` - Matches 1 instance of `{foo,bar}`. They behave the same.
+ * - `*(foo|bar)` - Matches _n_ instances of `{foo,bar}`.
+ * - `+(foo|bar)` - Matches _n > 0_ instances of `{foo,bar}`.
+ * - `!(foo|bar)` - Matches anything other than `{foo,bar}`.
+ * - See https://www.linuxjournal.com/content/bash-extended-globbing.
+ *
+ * Globstar syntax:
+ * - Requires `{ globstar: true }`.
+ * - `**` - Matches any number of any path segments.
+ * - Must comprise its entire path segment in the provided glob.
+ * - See https://www.linuxjournal.com/content/globstar-new-bash-globbing-option.
+ *
+ * Note the following properties:
+ * - The generated `RegExp` is anchored at both start and end.
+ * - Repeating and trailing separators are tolerated. Trailing separators in the
+ * provided glob have no meaning and are discarded.
+ * - Absolute globs will only match absolute paths, etc.
+ * - Empty globs will match nothing.
+ * - Any special glob syntax must be contained to one path segment. For example,
+ * `?(foo|bar/baz)` is invalid. The separator will take precedence and the
+ * first segment ends with an unclosed group.
+ * - If a path segment ends with unclosed groups or a dangling escape prefix, a
+ * parse error has occurred. Every character for that segment is taken
+ * literally in this event.
+ *
+ * Limitations:
+ * - A negative group like `!(foo|bar)` will wrongly be converted to a negative
+ * look-ahead followed by a wildcard. This means that `!(foo).js` will wrongly
+ * fail to match `foobar.js`, even though `foobar` is not `foo`. Effectively,
+ * `!(foo|bar)` is treated like `!(@(foo|bar)*)`. This will work correctly if
+ * the group occurs not nested at the end of the segment.
+ *
+ * @example Usage
+ * ```ts
+ * import { globToRegExp } from "@std/path/windows/glob-to-regexp";
+ * import { assertEquals } from "@std/assert";
+ *
+ * assertEquals(globToRegExp("*.js"), /^[^\\/]*\.js(?:\\|\/)*$/);
+ * ```
+ *
+ * @param glob Glob string to convert.
+ * @param options Conversion options.
+ * @returns The regular expression equivalent to the glob.
+ */ function globToRegExp(glob, options = {}) {
+ return _globToRegExp(constants, glob, options);
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Test whether the given string is a glob.
+ *
+ * @example Usage
+ * ```ts
+ * import { isGlob } from "@std/path/is-glob";
+ * import { assert } from "@std/assert";
+ *
+ * assert(!isGlob("foo/bar/../baz"));
+ * assert(isGlob("foo/*ar/../baz"));
+ * ```
+ *
+ * @param str String to test.
+ * @returns `true` if the given string is a glob, otherwise `false`
+ */ function isGlob(str) {
+ const chars = {
+ "{": "}",
+ "(": ")",
+ "[": "]"
+ };
+ const regex = /\\(.)|(^!|\*|\?|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/;
+ if (str === "") {
+ return false;
+ }
+ let match;
+ while(match = regex.exec(str)){
+ if (match[2]) return true;
+ let idx = match.index + match[0].length;
+ // if an open bracket/brace/paren is escaped,
+ // set the index to the next closing character
+ const open = match[1];
+ const close = open ? chars[open] : null;
+ if (open && close) {
+ const n = str.indexOf(close, idx);
+ if (n !== -1) {
+ idx = n + 1;
+ }
+ }
+ str = str.slice(idx);
+ }
+ return false;
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Like normalize(), but doesn't collapse "**\/.." when `globstar` is true.
+ *
+ * @example Usage
+ * ```ts
+ * import { normalizeGlob } from "@std/path/windows/normalize-glob";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const normalized = normalizeGlob("**\\foo\\..\\bar", { globstar: true });
+ * assertEquals(normalized, "**\\bar");
+ * ```
+ *
+ * @param glob The glob pattern to normalize.
+ * @param options The options for glob pattern.
+ * @returns The normalized glob pattern.
+ */ function normalizeGlob(glob, { globstar = false } = {}) {
+ if (glob.match(/\0/g)) {
+ throw new Error(`Glob contains invalid characters: "${glob}"`);
+ }
+ if (!globstar) {
+ return normalize(glob);
+ }
+ const s = SEPARATOR_PATTERN.source;
+ const badParentPattern = new RegExp(`(?<=(${s}|^)\\*\\*${s})\\.\\.(?=${s}|$)`, "g");
+ return normalize(glob.replace(badParentPattern, "\0")).replace(/\0/g, "..");
+}
+
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// This module is browser compatible.
+/**
+ * Like join(), but doesn't collapse "**\/.." when `globstar` is true.
+ *
+ * @example Usage
+ *
+ * ```ts
+ * import { joinGlobs } from "@std/path/windows/join-globs";
+ * import { assertEquals } from "@std/assert";
+ *
+ * const joined = joinGlobs(["foo", "**", "bar"], { globstar: true });
+ * assertEquals(joined, "foo\\**\\bar");
+ * ```
+ *
+ * @param globs The globs to join.
+ * @param options The options for glob pattern.
+ * @returns The joined glob pattern.
+ */ function joinGlobs(globs, { extended = true, globstar = false } = {}) {
+ if (!globstar || globs.length === 0) {
+ return join(...globs);
+ }
+ let joined;
+ for (const glob of globs){
+ const path = glob;
+ if (path.length > 0) {
+ if (!joined) joined = path;
+ else joined += `${SEPARATOR}${path}`;
+ }
+ }
+ if (!joined) return ".";
+ return normalizeGlob(joined, {
+ extended,
+ globstar
+ });
+}
+
+export { DELIMITER, SEPARATOR, SEPARATOR_PATTERN, basename, common, dirname, extname, format, fromFileUrl, globToRegExp, isAbsolute, isGlob, join, joinGlobs, normalize, normalizeGlob, parse, relative, resolve, toFileUrl, toNamespacedPath };
diff --git a/node_modules/@eslint/config-array/package.json b/node_modules/@eslint/config-array/package.json
index 2dfdd5e26..299906b66 100644
--- a/node_modules/@eslint/config-array/package.json
+++ b/node_modules/@eslint/config-array/package.json
@@ -1,6 +1,6 @@
{
"name": "@eslint/config-array",
- "version": "0.18.0",
+ "version": "0.19.0",
"description": "General purpose glob-based configuration matching.",
"author": "Nicholas C. Zakas",
"type": "module",
@@ -33,7 +33,8 @@
"scripts": {
"build:dedupe-types": "node ../../tools/dedupe-types.js dist/cjs/index.cjs dist/esm/index.js",
"build:cts": "node -e \"fs.copyFileSync('dist/esm/index.d.ts', 'dist/cjs/index.d.cts')\"",
- "build": "rollup -c && npm run build:dedupe-types && tsc -p tsconfig.esm.json && npm run build:cts",
+ "build:std__path": "rollup -c rollup.std__path-config.js && node fix-std__path-imports",
+ "build": "rollup -c && npm run build:dedupe-types && tsc -p tsconfig.esm.json && npm run build:cts && npm run build:std__path",
"test:jsr": "npx jsr@latest publish --dry-run",
"pretest": "npm run build",
"test": "mocha tests/",
@@ -51,6 +52,7 @@
"minimatch": "^3.1.2"
},
"devDependencies": {
+ "@jsr/std__path": "^1.0.4",
"@types/minimatch": "^3.0.5",
"c8": "^9.1.0",
"mocha": "^10.4.0",
diff --git a/node_modules/@eslint/core/README.md b/node_modules/@eslint/core/README.md
index 999795baa..6a2576f54 100644
--- a/node_modules/@eslint/core/README.md
+++ b/node_modules/@eslint/core/README.md
@@ -21,8 +21,8 @@ to get your logo on our READMEs and [website](https://eslint.org/sponsors).
Platinum Sponsors
Gold Sponsors
Silver Sponsors
-
Bronze Sponsors
-
+
Bronze Sponsors
+
Technology Sponsors
Technology sponsors allow us to use their products and services for free as part of a contribution to the open source ecosystem and our work.
diff --git a/node_modules/@eslint/core/dist/cjs/types.d.cts b/node_modules/@eslint/core/dist/cjs/types.d.cts
index efa28f7ed..4ec26b9c2 100644
--- a/node_modules/@eslint/core/dist/cjs/types.d.cts
+++ b/node_modules/@eslint/core/dist/cjs/types.d.cts
@@ -1,6 +1,7 @@
/**
* @fileoverview Shared types for ESLint Core.
*/
+import { JSONSchema4 } from "json-schema";
/**
* Represents an error inside of a file.
*/
@@ -19,13 +20,6 @@ export interface FileProblem {
message: string;
loc: SourceLocation;
}
-/**
- * Represents an AST node or token with location information in ESLint format.
- */
-export interface SyntaxElement {
- loc: SourceLocation;
- range: SourceRange;
-}
/**
* Represents the start and end coordinates of a node inside the source.
*/
@@ -58,6 +52,331 @@ export interface PositionWithOffset extends Position {
* Represents a range of characters in the source.
*/
export type SourceRange = [number, number];
+/**
+ * What the rule is responsible for finding:
+ * - `problem` means the rule has noticed a potential error.
+ * - `suggestion` means the rule suggests an alternate or better approach.
+ * - `layout` means the rule is looking at spacing, indentation, etc.
+ */
+export type RuleType = "problem" | "suggestion" | "layout";
+/**
+ * The type of fix the rule can provide:
+ * - `code` means the rule can fix syntax.
+ * - `whitespace` means the rule can fix spacing and indentation.
+ */
+export type RuleFixType = "code" | "whitespace";
+/**
+ * An object containing visitor information for a rule. Each method is either the
+ * name of a node type or a selector, or is a method that will be called at specific
+ * times during the traversal.
+ */
+export interface RuleVisitor {
+ /**
+ * Called for each node in the AST or at specific times during the traversal.
+ */
+ [key: string]: (...args: any[]) => void;
+}
+/**
+ * Rule meta information used for documentation.
+ */
+export interface RulesMetaDocs {
+ /**
+ * A short description of the rule.
+ */
+ description?: string | undefined;
+ /**
+ * The URL to the documentation for the rule.
+ */
+ url?: string | undefined;
+ /**
+ * The category the rule falls under.
+ * @deprecated No longer used.
+ */
+ category?: string | undefined;
+ /**
+ * Indicates if the rule is generally recommended for all users.
+ */
+ recommended?: boolean | undefined;
+}
+/**
+ * Meta information about a rule.
+ */
+export interface RulesMeta {
+ /**
+ * Properties that are used when documenting the rule.
+ */
+ docs?: (RulesMetaDocs & ExtRuleDocs) | undefined;
+ /**
+ * The type of rule.
+ */
+ type?: RuleType | undefined;
+ /**
+ * The schema for the rule options. Required if the rule has options.
+ */
+ schema?: JSONSchema4 | JSONSchema4[] | false | undefined;
+ /**
+ * The messages that the rule can report.
+ */
+ messages?: Record;
+ /**
+ * The deprecated rules for the rule.
+ */
+ deprecated?: boolean | undefined;
+ /**
+ * When a rule is deprecated, indicates the rule ID(s) that should be used instead.
+ */
+ replacedBy?: string[] | undefined;
+ /**
+ * Indicates if the rule is fixable, and if so, what type of fix it provides.
+ */
+ fixable?: RuleFixType | undefined;
+ /**
+ * Indicates if the rule may provide suggestions.
+ */
+ hasSuggestions?: boolean | undefined;
+}
+/**
+ * Generic type for `RuleContext`.
+ */
+export interface RuleContextTypeOptions {
+ LangOptions: LanguageOptions;
+ Code: SourceCode;
+ RuleOptions: unknown[];
+ Node: unknown;
+}
+/**
+ * Represents the context object that is passed to a rule. This object contains
+ * information about the current state of the linting process and is the rule's
+ * view into the outside world.
+ */
+export interface RuleContext {
+ /**
+ * The current working directory for the session.
+ */
+ cwd: string;
+ /**
+ * Returns the current working directory for the session.
+ * @deprecated Use `cwd` instead.
+ */
+ getCwd(): string;
+ /**
+ * The filename of the file being linted.
+ */
+ filename: string;
+ /**
+ * Returns the filename of the file being linted.
+ * @deprecated Use `filename` instead.
+ */
+ getFilename(): string;
+ /**
+ * The physical filename of the file being linted.
+ */
+ physicalFilename: string;
+ /**
+ * Returns the physical filename of the file being linted.
+ * @deprecated Use `physicalFilename` instead.
+ */
+ getPhysicalFilename(): string;
+ /**
+ * The source code object that the rule is running on.
+ */
+ sourceCode: Options["Code"];
+ /**
+ * Returns the source code object that the rule is running on.
+ * @deprecated Use `sourceCode` instead.
+ */
+ getSourceCode(): Options["Code"];
+ /**
+ * Shared settings for the configuration.
+ */
+ settings: SettingsConfig;
+ /**
+ * Parser-specific options for the configuration.
+ * @deprecated Use `languageOptions.parserOptions` instead.
+ */
+ parserOptions: Record;
+ /**
+ * The language options for the configuration.
+ */
+ languageOptions: Options["LangOptions"];
+ /**
+ * The CommonJS path to the parser used while parsing this file.
+ * @deprecated No longer used.
+ */
+ parserPath: string | undefined;
+ /**
+ * The rule ID.
+ */
+ id: string;
+ /**
+ * The rule's configured options.
+ */
+ options: Options["RuleOptions"];
+ /**
+ * The report function that the rule should use to report problems.
+ * @param violation The violation to report.
+ */
+ report(violation: ViolationReport): void;
+}
+/**
+ * Manager of text edits for a rule fix.
+ */
+export interface RuleTextEditor {
+ /**
+ * Inserts text after the specified node or token.
+ * @param syntaxElement The node or token to insert after.
+ * @param text The edit to insert after the node or token.
+ */
+ insertTextAfter(syntaxElement: EditableSyntaxElement, text: string): RuleTextEdit;
+ /**
+ * Inserts text after the specified range.
+ * @param range The range to insert after.
+ * @param text The edit to insert after the range.
+ */
+ insertTextAfterRange(range: SourceRange, text: string): RuleTextEdit;
+ /**
+ * Inserts text before the specified node or token.
+ * @param syntaxElement A syntax element with location information to insert before.
+ * @param text The edit to insert before the node or token.
+ */
+ insertTextBefore(syntaxElement: EditableSyntaxElement, text: string): RuleTextEdit;
+ /**
+ * Inserts text before the specified range.
+ * @param range The range to insert before.
+ * @param text The edit to insert before the range.
+ */
+ insertTextBeforeRange(range: SourceRange, text: string): RuleTextEdit;
+ /**
+ * Removes the specified node or token.
+ * @param syntaxElement A syntax element with location information to remove.
+ * @returns The edit to remove the node or token.
+ */
+ remove(syntaxElement: EditableSyntaxElement): RuleTextEdit;
+ /**
+ * Removes the specified range.
+ * @param range The range to remove.
+ * @returns The edit to remove the range.
+ */
+ removeRange(range: SourceRange): RuleTextEdit;
+ /**
+ * Replaces the specified node or token with the given text.
+ * @param syntaxElement A syntax element with location information to replace.
+ * @param text The text to replace the node or token with.
+ * @returns The edit to replace the node or token.
+ */
+ replaceText(syntaxElement: EditableSyntaxElement, text: string): RuleTextEdit;
+ /**
+ * Replaces the specified range with the given text.
+ * @param range The range to replace.
+ * @param text The text to replace the range with.
+ * @returns The edit to replace the range.
+ */
+ replaceTextRange(range: SourceRange, text: string): RuleTextEdit;
+}
+/**
+ * Represents a fix for a rule violation implemented as a text edit.
+ */
+export interface RuleTextEdit {
+ /**
+ * The range to replace.
+ */
+ range: SourceRange;
+ /**
+ * The text to insert.
+ */
+ text: string;
+}
+interface ViolationReportBase {
+ /**
+ * The type of node that the violation is for.
+ * @deprecated May be removed in the future.
+ */
+ nodeType?: string | undefined;
+ /**
+ * The data to insert into the message.
+ */
+ data?: Record | undefined;
+ /**
+ * The fix to be applied for the violation.
+ * @param fixer The text editor to apply the fix.
+ * @returns The fix(es) for the violation.
+ */
+ fix?(fixer: RuleTextEditor): RuleTextEdit | Iterable | null;
+ /**
+ * An array of suggested fixes for the problem. These fixes may change the
+ * behavior of the code, so they are not applied automatically.
+ */
+ suggest?: SuggestedEdit[];
+}
+type ViolationMessage = {
+ message: string;
+} | {
+ messageId: string;
+};
+type ViolationLocation = {
+ loc: SourceLocation;
+} | {
+ node: Node;
+};
+export type ViolationReport = ViolationReportBase & ViolationMessage & ViolationLocation;
+interface SuggestedEditBase {
+ /**
+ * The data to insert into the message.
+ */
+ data?: Record | undefined;
+ /**
+ * The fix to be applied for the suggestion.
+ * @param fixer The text editor to apply the fix.
+ * @returns The fix for the suggestion.
+ */
+ fix?(fixer: RuleTextEditor): RuleTextEdit | Iterable | null;
+}
+type SuggestionMessage = {
+ desc: string;
+} | {
+ messageId: string;
+};
+/**
+ * A suggested edit for a rule violation.
+ */
+export type SuggestedEdit = SuggestedEditBase & SuggestionMessage;
+/**
+ * Generic options for the `RuleDefinition` type.
+ */
+export interface RuleDefinitionTypeOptions {
+ LangOptions: LanguageOptions;
+ Code: SourceCode;
+ RuleOptions: unknown[];
+ Visitor: RuleVisitor;
+ Node: unknown;
+ MessageIds: string;
+ ExtRuleDocs: unknown;
+}
+/**
+ * The definition of an ESLint rule.
+ */
+export interface RuleDefinition {
+ /**
+ * The meta information for the rule.
+ */
+ meta?: RulesMeta;
+ /**
+ * Creates the visitor that ESLint uses to apply the rule during traversal.
+ * @param context The rule context.
+ * @returns The rule visitor.
+ */
+ create(context: RuleContext<{
+ LangOptions: Options["LangOptions"];
+ Code: Options["Code"];
+ RuleOptions: Options["RuleOptions"];
+ Node: Options["Node"];
+ }>): Options["Visitor"];
+}
/**
* The human readable severity level used in a configuration.
*/
@@ -68,7 +387,6 @@ export type SeverityName = "off" | "warn" | "error";
* - `0` means off.
* - `1` means warn.
* - `2` means error.
- *
*/
export type SeverityLevel = 0 | 1 | 2;
/**
@@ -100,10 +418,24 @@ export type RuleConfig = Severity | [Severity, ...unknown[]];
* A collection of rules and their configurations.
*/
export type RulesConfig = Record;
+/**
+ * Generic options for the `Language` type.
+ */
+export interface LanguageTypeOptions {
+ LangOptions: LanguageOptions;
+ Code: SourceCode;
+ RootNode: unknown;
+ Node: unknown;
+}
/**
* Represents a plugin language.
*/
-export interface Language {
+export interface Language {
/**
* Indicates how ESLint should read the file.
*/
@@ -131,24 +463,28 @@ export interface Language {
/**
* Validates languageOptions for this language.
*/
- validateLanguageOptions(languageOptions: LanguageOptions): void;
+ validateLanguageOptions(languageOptions: Options["LangOptions"]): void;
+ /**
+ * Normalizes languageOptions for this language.
+ */
+ normalizeLanguageOptions?(languageOptions: Options["LangOptions"]): Options["LangOptions"];
/**
* Helper for esquery that allows languages to match nodes against
* class. esquery currently has classes like `function` that will
* match all the various function nodes. This method allows languages
* to implement similar shorthands.
*/
- matchesSelectorClass?(className: string, node: object, ancestry: object[]): boolean;
+ matchesSelectorClass?(className: string, node: Options["Node"], ancestry: Options["Node"][]): boolean;
/**
* Parses the given file input into its component parts. This file should not
* throws errors for parsing errors but rather should return any parsing
* errors as parse of the ParseResult object.
*/
- parse(file: File, context: LanguageContext): ParseResult;
+ parse(file: File, context: LanguageContext): ParseResult;
/**
* Creates SourceCode object that ESLint uses to work with a file.
*/
- createSourceCode(file: File, input: OkParseResult, context: LanguageContext): SourceCode;
+ createSourceCode(file: File, input: OkParseResult, context: LanguageContext): Options["Code"];
}
/**
* Plugin-defined options for the language.
@@ -157,8 +493,8 @@ export type LanguageOptions = Record;
/**
* The context object that is passed to the language plugin methods.
*/
-export interface LanguageContext {
- languageOptions: LanguageOptions;
+export interface LanguageContext {
+ languageOptions: LangOptions;
}
/**
* Represents a file read by ESLint.
@@ -188,7 +524,7 @@ export interface File {
/**
* Represents the successful result of parsing a file.
*/
-export interface OkParseResult {
+export interface OkParseResult {
/**
* Indicates if the parse was successful. If true, the parse was successful
* and ESLint should continue on to create a SourceCode object and run rules;
@@ -199,7 +535,7 @@ export interface OkParseResult {
/**
* The abstract syntax tree created by the parser. (only when ok: true)
*/
- ast: T;
+ ast: RootNode;
/**
* Any additional data that the parser wants to provide.
*/
@@ -225,7 +561,7 @@ export interface NotOkParseResult {
*/
[key: string]: any;
}
-export type ParseResult = OkParseResult | NotOkParseResult;
+export type ParseResult = OkParseResult | NotOkParseResult;
/**
* Represents inline configuration found in the source code.
*/
@@ -241,14 +577,28 @@ interface InlineConfigElement {
rules: RulesConfig;
};
}
+/**
+ * Generic options for the `SourceCodeBase` type.
+ */
+interface SourceCodeBaseTypeOptions {
+ LangOptions: LanguageOptions;
+ RootNode: unknown;
+ SyntaxElementWithLoc: unknown;
+ ConfigNode: unknown;
+}
/**
* Represents the basic interface for a source code object.
*/
-interface SourceCodeBase {
+interface SourceCodeBase {
/**
* Root of the AST.
*/
- ast: object;
+ ast: Options["RootNode"];
/**
* The traversal path that tools should take when evaluating the AST.
* When present, this overrides the `visitorKeys` on the language for
@@ -257,12 +607,16 @@ interface SourceCodeBase {
visitorKeys?: Record;
/**
* Retrieves the equivalent of `loc` for a given node or token.
+ * @param syntaxElement The node or token to get the location for.
+ * @returns The location of the node or token.
*/
- getLoc(nodeOrToken: object): SourceLocation;
+ getLoc(syntaxElement: Options["SyntaxElementWithLoc"]): SourceLocation;
/**
* Retrieves the equivalent of `range` for a given node or token.
+ * @param syntaxElement The node or token to get the range for.
+ * @returns The range of the node or token.
*/
- getRange(nodeOrToken: object): SourceRange;
+ getRange(syntaxElement: Options["SyntaxElementWithLoc"]): SourceRange;
/**
* Traversal of AST.
*/
@@ -270,7 +624,7 @@ interface SourceCodeBase {
/**
* Applies language options passed in from the ESLint core.
*/
- applyLanguageOptions?(languageOptions: LanguageOptions): void;
+ applyLanguageOptions?(languageOptions: Options["LangOptions"]): void;
/**
* Return all of the inline areas where ESLint should be disabled/enabled
* along with any problems found in evaluating the directives.
@@ -283,7 +637,7 @@ interface SourceCodeBase {
* Returns an array of all inline configuration nodes found in the
* source code.
*/
- getInlineConfigNodes?(): object[];
+ getInlineConfigNodes?(): Options["ConfigNode"][];
/**
* Applies configuration found inside of the source code. This method is only
* called when ESLint is running with inline configuration allowed.
@@ -303,7 +657,12 @@ interface SourceCodeBase {
/**
* Represents the source of a text file being linted.
*/
-export interface TextSourceCode extends SourceCodeBase {
+export interface TextSourceCode extends SourceCodeBase {
/**
* The body of the file that you'd like rule developers to access.
*/
@@ -312,13 +671,23 @@ export interface TextSourceCode extends SourceCodeBase {
/**
* Represents the source of a binary file being linted.
*/
-export interface BinarySourceCode extends SourceCodeBase {
+export interface BinarySourceCode extends SourceCodeBase {
/**
* The body of the file that you'd like rule developers to access.
*/
body: Uint8Array;
}
-export type SourceCode = TextSourceCode | BinarySourceCode;
+export type SourceCode = TextSourceCode | BinarySourceCode;
/**
* Represents a traversal step visiting the AST.
*/
diff --git a/node_modules/@eslint/core/dist/esm/types.d.ts b/node_modules/@eslint/core/dist/esm/types.d.ts
index efa28f7ed..4ec26b9c2 100644
--- a/node_modules/@eslint/core/dist/esm/types.d.ts
+++ b/node_modules/@eslint/core/dist/esm/types.d.ts
@@ -1,6 +1,7 @@
/**
* @fileoverview Shared types for ESLint Core.
*/
+import { JSONSchema4 } from "json-schema";
/**
* Represents an error inside of a file.
*/
@@ -19,13 +20,6 @@ export interface FileProblem {
message: string;
loc: SourceLocation;
}
-/**
- * Represents an AST node or token with location information in ESLint format.
- */
-export interface SyntaxElement {
- loc: SourceLocation;
- range: SourceRange;
-}
/**
* Represents the start and end coordinates of a node inside the source.
*/
@@ -58,6 +52,331 @@ export interface PositionWithOffset extends Position {
* Represents a range of characters in the source.
*/
export type SourceRange = [number, number];
+/**
+ * What the rule is responsible for finding:
+ * - `problem` means the rule has noticed a potential error.
+ * - `suggestion` means the rule suggests an alternate or better approach.
+ * - `layout` means the rule is looking at spacing, indentation, etc.
+ */
+export type RuleType = "problem" | "suggestion" | "layout";
+/**
+ * The type of fix the rule can provide:
+ * - `code` means the rule can fix syntax.
+ * - `whitespace` means the rule can fix spacing and indentation.
+ */
+export type RuleFixType = "code" | "whitespace";
+/**
+ * An object containing visitor information for a rule. Each method is either the
+ * name of a node type or a selector, or is a method that will be called at specific
+ * times during the traversal.
+ */
+export interface RuleVisitor {
+ /**
+ * Called for each node in the AST or at specific times during the traversal.
+ */
+ [key: string]: (...args: any[]) => void;
+}
+/**
+ * Rule meta information used for documentation.
+ */
+export interface RulesMetaDocs {
+ /**
+ * A short description of the rule.
+ */
+ description?: string | undefined;
+ /**
+ * The URL to the documentation for the rule.
+ */
+ url?: string | undefined;
+ /**
+ * The category the rule falls under.
+ * @deprecated No longer used.
+ */
+ category?: string | undefined;
+ /**
+ * Indicates if the rule is generally recommended for all users.
+ */
+ recommended?: boolean | undefined;
+}
+/**
+ * Meta information about a rule.
+ */
+export interface RulesMeta {
+ /**
+ * Properties that are used when documenting the rule.
+ */
+ docs?: (RulesMetaDocs & ExtRuleDocs) | undefined;
+ /**
+ * The type of rule.
+ */
+ type?: RuleType | undefined;
+ /**
+ * The schema for the rule options. Required if the rule has options.
+ */
+ schema?: JSONSchema4 | JSONSchema4[] | false | undefined;
+ /**
+ * The messages that the rule can report.
+ */
+ messages?: Record;
+ /**
+ * The deprecated rules for the rule.
+ */
+ deprecated?: boolean | undefined;
+ /**
+ * When a rule is deprecated, indicates the rule ID(s) that should be used instead.
+ */
+ replacedBy?: string[] | undefined;
+ /**
+ * Indicates if the rule is fixable, and if so, what type of fix it provides.
+ */
+ fixable?: RuleFixType | undefined;
+ /**
+ * Indicates if the rule may provide suggestions.
+ */
+ hasSuggestions?: boolean | undefined;
+}
+/**
+ * Generic type for `RuleContext`.
+ */
+export interface RuleContextTypeOptions {
+ LangOptions: LanguageOptions;
+ Code: SourceCode;
+ RuleOptions: unknown[];
+ Node: unknown;
+}
+/**
+ * Represents the context object that is passed to a rule. This object contains
+ * information about the current state of the linting process and is the rule's
+ * view into the outside world.
+ */
+export interface RuleContext {
+ /**
+ * The current working directory for the session.
+ */
+ cwd: string;
+ /**
+ * Returns the current working directory for the session.
+ * @deprecated Use `cwd` instead.
+ */
+ getCwd(): string;
+ /**
+ * The filename of the file being linted.
+ */
+ filename: string;
+ /**
+ * Returns the filename of the file being linted.
+ * @deprecated Use `filename` instead.
+ */
+ getFilename(): string;
+ /**
+ * The physical filename of the file being linted.
+ */
+ physicalFilename: string;
+ /**
+ * Returns the physical filename of the file being linted.
+ * @deprecated Use `physicalFilename` instead.
+ */
+ getPhysicalFilename(): string;
+ /**
+ * The source code object that the rule is running on.
+ */
+ sourceCode: Options["Code"];
+ /**
+ * Returns the source code object that the rule is running on.
+ * @deprecated Use `sourceCode` instead.
+ */
+ getSourceCode(): Options["Code"];
+ /**
+ * Shared settings for the configuration.
+ */
+ settings: SettingsConfig;
+ /**
+ * Parser-specific options for the configuration.
+ * @deprecated Use `languageOptions.parserOptions` instead.
+ */
+ parserOptions: Record;
+ /**
+ * The language options for the configuration.
+ */
+ languageOptions: Options["LangOptions"];
+ /**
+ * The CommonJS path to the parser used while parsing this file.
+ * @deprecated No longer used.
+ */
+ parserPath: string | undefined;
+ /**
+ * The rule ID.
+ */
+ id: string;
+ /**
+ * The rule's configured options.
+ */
+ options: Options["RuleOptions"];
+ /**
+ * The report function that the rule should use to report problems.
+ * @param violation The violation to report.
+ */
+ report(violation: ViolationReport): void;
+}
+/**
+ * Manager of text edits for a rule fix.
+ */
+export interface RuleTextEditor {
+ /**
+ * Inserts text after the specified node or token.
+ * @param syntaxElement The node or token to insert after.
+ * @param text The edit to insert after the node or token.
+ */
+ insertTextAfter(syntaxElement: EditableSyntaxElement, text: string): RuleTextEdit;
+ /**
+ * Inserts text after the specified range.
+ * @param range The range to insert after.
+ * @param text The edit to insert after the range.
+ */
+ insertTextAfterRange(range: SourceRange, text: string): RuleTextEdit;
+ /**
+ * Inserts text before the specified node or token.
+ * @param syntaxElement A syntax element with location information to insert before.
+ * @param text The edit to insert before the node or token.
+ */
+ insertTextBefore(syntaxElement: EditableSyntaxElement, text: string): RuleTextEdit;
+ /**
+ * Inserts text before the specified range.
+ * @param range The range to insert before.
+ * @param text The edit to insert before the range.
+ */
+ insertTextBeforeRange(range: SourceRange, text: string): RuleTextEdit;
+ /**
+ * Removes the specified node or token.
+ * @param syntaxElement A syntax element with location information to remove.
+ * @returns The edit to remove the node or token.
+ */
+ remove(syntaxElement: EditableSyntaxElement): RuleTextEdit;
+ /**
+ * Removes the specified range.
+ * @param range The range to remove.
+ * @returns The edit to remove the range.
+ */
+ removeRange(range: SourceRange): RuleTextEdit;
+ /**
+ * Replaces the specified node or token with the given text.
+ * @param syntaxElement A syntax element with location information to replace.
+ * @param text The text to replace the node or token with.
+ * @returns The edit to replace the node or token.
+ */
+ replaceText(syntaxElement: EditableSyntaxElement, text: string): RuleTextEdit;
+ /**
+ * Replaces the specified range with the given text.
+ * @param range The range to replace.
+ * @param text The text to replace the range with.
+ * @returns The edit to replace the range.
+ */
+ replaceTextRange(range: SourceRange, text: string): RuleTextEdit;
+}
+/**
+ * Represents a fix for a rule violation implemented as a text edit.
+ */
+export interface RuleTextEdit {
+ /**
+ * The range to replace.
+ */
+ range: SourceRange;
+ /**
+ * The text to insert.
+ */
+ text: string;
+}
+interface ViolationReportBase {
+ /**
+ * The type of node that the violation is for.
+ * @deprecated May be removed in the future.
+ */
+ nodeType?: string | undefined;
+ /**
+ * The data to insert into the message.
+ */
+ data?: Record | undefined;
+ /**
+ * The fix to be applied for the violation.
+ * @param fixer The text editor to apply the fix.
+ * @returns The fix(es) for the violation.
+ */
+ fix?(fixer: RuleTextEditor): RuleTextEdit | Iterable | null;
+ /**
+ * An array of suggested fixes for the problem. These fixes may change the
+ * behavior of the code, so they are not applied automatically.
+ */
+ suggest?: SuggestedEdit[];
+}
+type ViolationMessage = {
+ message: string;
+} | {
+ messageId: string;
+};
+type ViolationLocation = {
+ loc: SourceLocation;
+} | {
+ node: Node;
+};
+export type ViolationReport = ViolationReportBase & ViolationMessage & ViolationLocation;
+interface SuggestedEditBase {
+ /**
+ * The data to insert into the message.
+ */
+ data?: Record | undefined;
+ /**
+ * The fix to be applied for the suggestion.
+ * @param fixer The text editor to apply the fix.
+ * @returns The fix for the suggestion.
+ */
+ fix?(fixer: RuleTextEditor): RuleTextEdit | Iterable | null;
+}
+type SuggestionMessage = {
+ desc: string;
+} | {
+ messageId: string;
+};
+/**
+ * A suggested edit for a rule violation.
+ */
+export type SuggestedEdit = SuggestedEditBase & SuggestionMessage;
+/**
+ * Generic options for the `RuleDefinition` type.
+ */
+export interface RuleDefinitionTypeOptions {
+ LangOptions: LanguageOptions;
+ Code: SourceCode;
+ RuleOptions: unknown[];
+ Visitor: RuleVisitor;
+ Node: unknown;
+ MessageIds: string;
+ ExtRuleDocs: unknown;
+}
+/**
+ * The definition of an ESLint rule.
+ */
+export interface RuleDefinition {
+ /**
+ * The meta information for the rule.
+ */
+ meta?: RulesMeta;
+ /**
+ * Creates the visitor that ESLint uses to apply the rule during traversal.
+ * @param context The rule context.
+ * @returns The rule visitor.
+ */
+ create(context: RuleContext<{
+ LangOptions: Options["LangOptions"];
+ Code: Options["Code"];
+ RuleOptions: Options["RuleOptions"];
+ Node: Options["Node"];
+ }>): Options["Visitor"];
+}
/**
* The human readable severity level used in a configuration.
*/
@@ -68,7 +387,6 @@ export type SeverityName = "off" | "warn" | "error";
* - `0` means off.
* - `1` means warn.
* - `2` means error.
- *
*/
export type SeverityLevel = 0 | 1 | 2;
/**
@@ -100,10 +418,24 @@ export type RuleConfig = Severity | [Severity, ...unknown[]];
* A collection of rules and their configurations.
*/
export type RulesConfig = Record;
+/**
+ * Generic options for the `Language` type.
+ */
+export interface LanguageTypeOptions {
+ LangOptions: LanguageOptions;
+ Code: SourceCode;
+ RootNode: unknown;
+ Node: unknown;
+}
/**
* Represents a plugin language.
*/
-export interface Language {
+export interface Language {
/**
* Indicates how ESLint should read the file.
*/
@@ -131,24 +463,28 @@ export interface Language {
/**
* Validates languageOptions for this language.
*/
- validateLanguageOptions(languageOptions: LanguageOptions): void;
+ validateLanguageOptions(languageOptions: Options["LangOptions"]): void;
+ /**
+ * Normalizes languageOptions for this language.
+ */
+ normalizeLanguageOptions?(languageOptions: Options["LangOptions"]): Options["LangOptions"];
/**
* Helper for esquery that allows languages to match nodes against
* class. esquery currently has classes like `function` that will
* match all the various function nodes. This method allows languages
* to implement similar shorthands.
*/
- matchesSelectorClass?(className: string, node: object, ancestry: object[]): boolean;
+ matchesSelectorClass?(className: string, node: Options["Node"], ancestry: Options["Node"][]): boolean;
/**
* Parses the given file input into its component parts. This file should not
* throws errors for parsing errors but rather should return any parsing
* errors as parse of the ParseResult object.
*/
- parse(file: File, context: LanguageContext): ParseResult;
+ parse(file: File, context: LanguageContext): ParseResult;
/**
* Creates SourceCode object that ESLint uses to work with a file.
*/
- createSourceCode(file: File, input: OkParseResult, context: LanguageContext): SourceCode;
+ createSourceCode(file: File, input: OkParseResult, context: LanguageContext): Options["Code"];
}
/**
* Plugin-defined options for the language.
@@ -157,8 +493,8 @@ export type LanguageOptions = Record;
/**
* The context object that is passed to the language plugin methods.
*/
-export interface LanguageContext {
- languageOptions: LanguageOptions;
+export interface LanguageContext {
+ languageOptions: LangOptions;
}
/**
* Represents a file read by ESLint.
@@ -188,7 +524,7 @@ export interface File {
/**
* Represents the successful result of parsing a file.
*/
-export interface OkParseResult {
+export interface OkParseResult {
/**
* Indicates if the parse was successful. If true, the parse was successful
* and ESLint should continue on to create a SourceCode object and run rules;
@@ -199,7 +535,7 @@ export interface OkParseResult {
/**
* The abstract syntax tree created by the parser. (only when ok: true)
*/
- ast: T;
+ ast: RootNode;
/**
* Any additional data that the parser wants to provide.
*/
@@ -225,7 +561,7 @@ export interface NotOkParseResult {
*/
[key: string]: any;
}
-export type ParseResult = OkParseResult | NotOkParseResult;
+export type ParseResult = OkParseResult | NotOkParseResult;
/**
* Represents inline configuration found in the source code.
*/
@@ -241,14 +577,28 @@ interface InlineConfigElement {
rules: RulesConfig;
};
}
+/**
+ * Generic options for the `SourceCodeBase` type.
+ */
+interface SourceCodeBaseTypeOptions {
+ LangOptions: LanguageOptions;
+ RootNode: unknown;
+ SyntaxElementWithLoc: unknown;
+ ConfigNode: unknown;
+}
/**
* Represents the basic interface for a source code object.
*/
-interface SourceCodeBase {
+interface SourceCodeBase {
/**
* Root of the AST.
*/
- ast: object;
+ ast: Options["RootNode"];
/**
* The traversal path that tools should take when evaluating the AST.
* When present, this overrides the `visitorKeys` on the language for
@@ -257,12 +607,16 @@ interface SourceCodeBase {
visitorKeys?: Record;
/**
* Retrieves the equivalent of `loc` for a given node or token.
+ * @param syntaxElement The node or token to get the location for.
+ * @returns The location of the node or token.
*/
- getLoc(nodeOrToken: object): SourceLocation;
+ getLoc(syntaxElement: Options["SyntaxElementWithLoc"]): SourceLocation;
/**
* Retrieves the equivalent of `range` for a given node or token.
+ * @param syntaxElement The node or token to get the range for.
+ * @returns The range of the node or token.
*/
- getRange(nodeOrToken: object): SourceRange;
+ getRange(syntaxElement: Options["SyntaxElementWithLoc"]): SourceRange;
/**
* Traversal of AST.
*/
@@ -270,7 +624,7 @@ interface SourceCodeBase {
/**
* Applies language options passed in from the ESLint core.
*/
- applyLanguageOptions?(languageOptions: LanguageOptions): void;
+ applyLanguageOptions?(languageOptions: Options["LangOptions"]): void;
/**
* Return all of the inline areas where ESLint should be disabled/enabled
* along with any problems found in evaluating the directives.
@@ -283,7 +637,7 @@ interface SourceCodeBase {
* Returns an array of all inline configuration nodes found in the
* source code.
*/
- getInlineConfigNodes?(): object[];
+ getInlineConfigNodes?(): Options["ConfigNode"][];
/**
* Applies configuration found inside of the source code. This method is only
* called when ESLint is running with inline configuration allowed.
@@ -303,7 +657,12 @@ interface SourceCodeBase {
/**
* Represents the source of a text file being linted.
*/
-export interface TextSourceCode extends SourceCodeBase {
+export interface TextSourceCode extends SourceCodeBase {
/**
* The body of the file that you'd like rule developers to access.
*/
@@ -312,13 +671,23 @@ export interface TextSourceCode extends SourceCodeBase {
/**
* Represents the source of a binary file being linted.
*/
-export interface BinarySourceCode extends SourceCodeBase {
+export interface BinarySourceCode extends SourceCodeBase {
/**
* The body of the file that you'd like rule developers to access.
*/
body: Uint8Array;
}
-export type SourceCode = TextSourceCode | BinarySourceCode;
+export type SourceCode = TextSourceCode | BinarySourceCode;
/**
* Represents a traversal step visiting the AST.
*/
diff --git a/node_modules/@eslint/core/package.json b/node_modules/@eslint/core/package.json
index 130eddecc..797e3a656 100644
--- a/node_modules/@eslint/core/package.json
+++ b/node_modules/@eslint/core/package.json
@@ -1,6 +1,6 @@
{
"name": "@eslint/core",
- "version": "0.7.0",
+ "version": "0.9.0",
"description": "Runtime-agnostic core of ESLint",
"type": "module",
"types": "./dist/esm/types.d.ts",
@@ -36,6 +36,7 @@
},
"homepage": "https://github.com/eslint/rewrite#readme",
"devDependencies": {
+ "json-schema": "^0.4.0",
"typescript": "^5.4.5"
},
"engines": {
diff --git a/node_modules/@eslint/eslintrc/README.md b/node_modules/@eslint/eslintrc/README.md
index b23d22b63..cdcf0a636 100644
--- a/node_modules/@eslint/eslintrc/README.md
+++ b/node_modules/@eslint/eslintrc/README.md
@@ -40,7 +40,7 @@ const compat = new FlatCompat({
export default [
// mimic ESLintRC-style extends
- ...compat.extends("standard", "example"),
+ ...compat.extends("standard", "example", "plugin:react/recommended"),
// mimic environments
...compat.env({
@@ -49,11 +49,11 @@ export default [
}),
// mimic plugins
- ...compat.plugins("airbnb", "react"),
+ ...compat.plugins("jsx-a11y", "react"),
// translate an entire config
...compat.config({
- plugins: ["airbnb", "react"],
+ plugins: ["jsx-a11y", "react"],
extends: "standard",
env: {
es2020: true,
@@ -84,7 +84,7 @@ const compat = new FlatCompat({
module.exports = [
// mimic ESLintRC-style extends
- ...compat.extends("standard", "example"),
+ ...compat.extends("standard", "example", "plugin:react/recommended"),
// mimic environments
...compat.env({
@@ -93,11 +93,11 @@ module.exports = [
}),
// mimic plugins
- ...compat.plugins("airbnb", "react"),
+ ...compat.plugins("jsx-a11y", "react"),
// translate an entire config
...compat.config({
- plugins: ["airbnb", "react"],
+ plugins: ["jsx-a11y", "react"],
extends: "standard",
env: {
es2020: true,
diff --git a/node_modules/@eslint/eslintrc/dist/eslintrc-universal.cjs b/node_modules/@eslint/eslintrc/dist/eslintrc-universal.cjs
index 98892f61f..c0414cfd6 100644
--- a/node_modules/@eslint/eslintrc/dist/eslintrc-universal.cjs
+++ b/node_modules/@eslint/eslintrc/dist/eslintrc-universal.cjs
@@ -387,6 +387,63 @@ var ajvOrig = (additionalOptions = {}) => {
return ajv;
};
+/**
+ * @fileoverview Applies default rule options
+ * @author JoshuaKGoldberg
+ */
+
+/**
+ * Check if the variable contains an object strictly rejecting arrays
+ * @param {unknown} value an object
+ * @returns {boolean} Whether value is an object
+ */
+function isObjectNotArray(value) {
+ return typeof value === "object" && value !== null && !Array.isArray(value);
+}
+
+/**
+ * Deeply merges second on top of first, creating a new {} object if needed.
+ * @param {T} first Base, default value.
+ * @param {U} second User-specified value.
+ * @returns {T | U | (T & U)} Merged equivalent of second on top of first.
+ */
+function deepMergeObjects(first, second) {
+ if (second === void 0) {
+ return first;
+ }
+
+ if (!isObjectNotArray(first) || !isObjectNotArray(second)) {
+ return second;
+ }
+
+ const result = { ...first, ...second };
+
+ for (const key of Object.keys(second)) {
+ if (Object.prototype.propertyIsEnumerable.call(first, key)) {
+ result[key] = deepMergeObjects(first[key], second[key]);
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Deeply merges second on top of first, creating a new [] array if needed.
+ * @param {T[] | undefined} first Base, default values.
+ * @param {U[] | undefined} second User-specified values.
+ * @returns {(T | U | (T & U))[]} Merged equivalent of second on top of first.
+ */
+function deepMergeArrays(first, second) {
+ if (!first || !second) {
+ return second || first || [];
+ }
+
+ return [
+ ...first.map((value, i) => deepMergeObjects(value, second[i])),
+ ...second.slice(first.length)
+ ];
+}
+
/**
* @fileoverview Defines a schema for configs.
* @author Sylvan Mably
@@ -806,7 +863,10 @@ class ConfigValidator {
const validateRule = ruleValidators.get(rule);
if (validateRule) {
- validateRule(localOptions);
+ const mergedOptions = deepMergeArrays(rule.meta?.defaultOptions, localOptions);
+
+ validateRule(mergedOptions);
+
if (validateRule.errors) {
throw new Error(validateRule.errors.map(
error => `\tValue ${JSON.stringify(error.data)} ${error.message}.\n`
diff --git a/node_modules/@eslint/eslintrc/dist/eslintrc-universal.cjs.map b/node_modules/@eslint/eslintrc/dist/eslintrc-universal.cjs.map
index 8a62039d4..c1c849998 100644
--- a/node_modules/@eslint/eslintrc/dist/eslintrc-universal.cjs.map
+++ b/node_modules/@eslint/eslintrc/dist/eslintrc-universal.cjs.map
@@ -1 +1 @@
-{"version":3,"file":"eslintrc-universal.cjs","sources":["../lib/shared/config-ops.js","../lib/shared/deprecation-warnings.js","../lib/shared/ajv.js","../conf/config-schema.js","../conf/environments.js","../lib/shared/config-validator.js","../lib/shared/naming.js","../lib/index-universal.js"],"sourcesContent":["/**\n * @fileoverview Config file operations. This file must be usable in the browser,\n * so no Node-specific code can be here.\n * @author Nicholas C. Zakas\n */\n\n//------------------------------------------------------------------------------\n// Private\n//------------------------------------------------------------------------------\n\nconst RULE_SEVERITY_STRINGS = [\"off\", \"warn\", \"error\"],\n RULE_SEVERITY = RULE_SEVERITY_STRINGS.reduce((map, value, index) => {\n map[value] = index;\n return map;\n }, {}),\n VALID_SEVERITIES = [0, 1, 2, \"off\", \"warn\", \"error\"];\n\n//------------------------------------------------------------------------------\n// Public Interface\n//------------------------------------------------------------------------------\n\n/**\n * Normalizes the severity value of a rule's configuration to a number\n * @param {(number|string|[number, ...*]|[string, ...*])} ruleConfig A rule's configuration value, generally\n * received from the user. A valid config value is either 0, 1, 2, the string \"off\" (treated the same as 0),\n * the string \"warn\" (treated the same as 1), the string \"error\" (treated the same as 2), or an array\n * whose first element is one of the above values. Strings are matched case-insensitively.\n * @returns {(0|1|2)} The numeric severity value if the config value was valid, otherwise 0.\n */\nfunction getRuleSeverity(ruleConfig) {\n const severityValue = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;\n\n if (severityValue === 0 || severityValue === 1 || severityValue === 2) {\n return severityValue;\n }\n\n if (typeof severityValue === \"string\") {\n return RULE_SEVERITY[severityValue.toLowerCase()] || 0;\n }\n\n return 0;\n}\n\n/**\n * Converts old-style severity settings (0, 1, 2) into new-style\n * severity settings (off, warn, error) for all rules. Assumption is that severity\n * values have already been validated as correct.\n * @param {Object} config The config object to normalize.\n * @returns {void}\n */\nfunction normalizeToStrings(config) {\n\n if (config.rules) {\n Object.keys(config.rules).forEach(ruleId => {\n const ruleConfig = config.rules[ruleId];\n\n if (typeof ruleConfig === \"number\") {\n config.rules[ruleId] = RULE_SEVERITY_STRINGS[ruleConfig] || RULE_SEVERITY_STRINGS[0];\n } else if (Array.isArray(ruleConfig) && typeof ruleConfig[0] === \"number\") {\n ruleConfig[0] = RULE_SEVERITY_STRINGS[ruleConfig[0]] || RULE_SEVERITY_STRINGS[0];\n }\n });\n }\n}\n\n/**\n * Determines if the severity for the given rule configuration represents an error.\n * @param {int|string|Array} ruleConfig The configuration for an individual rule.\n * @returns {boolean} True if the rule represents an error, false if not.\n */\nfunction isErrorSeverity(ruleConfig) {\n return getRuleSeverity(ruleConfig) === 2;\n}\n\n/**\n * Checks whether a given config has valid severity or not.\n * @param {number|string|Array} ruleConfig The configuration for an individual rule.\n * @returns {boolean} `true` if the configuration has valid severity.\n */\nfunction isValidSeverity(ruleConfig) {\n let severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;\n\n if (typeof severity === \"string\") {\n severity = severity.toLowerCase();\n }\n return VALID_SEVERITIES.indexOf(severity) !== -1;\n}\n\n/**\n * Checks whether every rule of a given config has valid severity or not.\n * @param {Object} config The configuration for rules.\n * @returns {boolean} `true` if the configuration has valid severity.\n */\nfunction isEverySeverityValid(config) {\n return Object.keys(config).every(ruleId => isValidSeverity(config[ruleId]));\n}\n\n/**\n * Normalizes a value for a global in a config\n * @param {(boolean|string|null)} configuredValue The value given for a global in configuration or in\n * a global directive comment\n * @returns {(\"readable\"|\"writeable\"|\"off\")} The value normalized as a string\n * @throws Error if global value is invalid\n */\nfunction normalizeConfigGlobal(configuredValue) {\n switch (configuredValue) {\n case \"off\":\n return \"off\";\n\n case true:\n case \"true\":\n case \"writeable\":\n case \"writable\":\n return \"writable\";\n\n case null:\n case false:\n case \"false\":\n case \"readable\":\n case \"readonly\":\n return \"readonly\";\n\n default:\n throw new Error(`'${configuredValue}' is not a valid configuration for a global (use 'readonly', 'writable', or 'off')`);\n }\n}\n\nexport {\n getRuleSeverity,\n normalizeToStrings,\n isErrorSeverity,\n isValidSeverity,\n isEverySeverityValid,\n normalizeConfigGlobal\n};\n","/**\n * @fileoverview Provide the function that emits deprecation warnings.\n * @author Toru Nagashima \n */\n\n//------------------------------------------------------------------------------\n// Requirements\n//------------------------------------------------------------------------------\n\nimport path from \"path\";\n\n//------------------------------------------------------------------------------\n// Private\n//------------------------------------------------------------------------------\n\n// Defitions for deprecation warnings.\nconst deprecationWarningMessages = {\n ESLINT_LEGACY_ECMAFEATURES:\n \"The 'ecmaFeatures' config file property is deprecated and has no effect.\",\n ESLINT_PERSONAL_CONFIG_LOAD:\n \"'~/.eslintrc.*' config files have been deprecated. \" +\n \"Please use a config file per project or the '--config' option.\",\n ESLINT_PERSONAL_CONFIG_SUPPRESS:\n \"'~/.eslintrc.*' config files have been deprecated. \" +\n \"Please remove it or add 'root:true' to the config files in your \" +\n \"projects in order to avoid loading '~/.eslintrc.*' accidentally.\"\n};\n\nconst sourceFileErrorCache = new Set();\n\n/**\n * Emits a deprecation warning containing a given filepath. A new deprecation warning is emitted\n * for each unique file path, but repeated invocations with the same file path have no effect.\n * No warnings are emitted if the `--no-deprecation` or `--no-warnings` Node runtime flags are active.\n * @param {string} source The name of the configuration source to report the warning for.\n * @param {string} errorCode The warning message to show.\n * @returns {void}\n */\nfunction emitDeprecationWarning(source, errorCode) {\n const cacheKey = JSON.stringify({ source, errorCode });\n\n if (sourceFileErrorCache.has(cacheKey)) {\n return;\n }\n sourceFileErrorCache.add(cacheKey);\n\n const rel = path.relative(process.cwd(), source);\n const message = deprecationWarningMessages[errorCode];\n\n process.emitWarning(\n `${message} (found in \"${rel}\")`,\n \"DeprecationWarning\",\n errorCode\n );\n}\n\n//------------------------------------------------------------------------------\n// Public Interface\n//------------------------------------------------------------------------------\n\nexport {\n emitDeprecationWarning\n};\n","/**\n * @fileoverview The instance of Ajv validator.\n * @author Evgeny Poberezkin\n */\n\n//------------------------------------------------------------------------------\n// Requirements\n//------------------------------------------------------------------------------\n\nimport Ajv from \"ajv\";\n\n//-----------------------------------------------------------------------------\n// Helpers\n//-----------------------------------------------------------------------------\n\n/*\n * Copied from ajv/lib/refs/json-schema-draft-04.json\n * The MIT License (MIT)\n * Copyright (c) 2015-2017 Evgeny Poberezkin\n */\nconst metaSchema = {\n id: \"http://json-schema.org/draft-04/schema#\",\n $schema: \"http://json-schema.org/draft-04/schema#\",\n description: \"Core schema meta-schema\",\n definitions: {\n schemaArray: {\n type: \"array\",\n minItems: 1,\n items: { $ref: \"#\" }\n },\n positiveInteger: {\n type: \"integer\",\n minimum: 0\n },\n positiveIntegerDefault0: {\n allOf: [{ $ref: \"#/definitions/positiveInteger\" }, { default: 0 }]\n },\n simpleTypes: {\n enum: [\"array\", \"boolean\", \"integer\", \"null\", \"number\", \"object\", \"string\"]\n },\n stringArray: {\n type: \"array\",\n items: { type: \"string\" },\n minItems: 1,\n uniqueItems: true\n }\n },\n type: \"object\",\n properties: {\n id: {\n type: \"string\"\n },\n $schema: {\n type: \"string\"\n },\n title: {\n type: \"string\"\n },\n description: {\n type: \"string\"\n },\n default: { },\n multipleOf: {\n type: \"number\",\n minimum: 0,\n exclusiveMinimum: true\n },\n maximum: {\n type: \"number\"\n },\n exclusiveMaximum: {\n type: \"boolean\",\n default: false\n },\n minimum: {\n type: \"number\"\n },\n exclusiveMinimum: {\n type: \"boolean\",\n default: false\n },\n maxLength: { $ref: \"#/definitions/positiveInteger\" },\n minLength: { $ref: \"#/definitions/positiveIntegerDefault0\" },\n pattern: {\n type: \"string\",\n format: \"regex\"\n },\n additionalItems: {\n anyOf: [\n { type: \"boolean\" },\n { $ref: \"#\" }\n ],\n default: { }\n },\n items: {\n anyOf: [\n { $ref: \"#\" },\n { $ref: \"#/definitions/schemaArray\" }\n ],\n default: { }\n },\n maxItems: { $ref: \"#/definitions/positiveInteger\" },\n minItems: { $ref: \"#/definitions/positiveIntegerDefault0\" },\n uniqueItems: {\n type: \"boolean\",\n default: false\n },\n maxProperties: { $ref: \"#/definitions/positiveInteger\" },\n minProperties: { $ref: \"#/definitions/positiveIntegerDefault0\" },\n required: { $ref: \"#/definitions/stringArray\" },\n additionalProperties: {\n anyOf: [\n { type: \"boolean\" },\n { $ref: \"#\" }\n ],\n default: { }\n },\n definitions: {\n type: \"object\",\n additionalProperties: { $ref: \"#\" },\n default: { }\n },\n properties: {\n type: \"object\",\n additionalProperties: { $ref: \"#\" },\n default: { }\n },\n patternProperties: {\n type: \"object\",\n additionalProperties: { $ref: \"#\" },\n default: { }\n },\n dependencies: {\n type: \"object\",\n additionalProperties: {\n anyOf: [\n { $ref: \"#\" },\n { $ref: \"#/definitions/stringArray\" }\n ]\n }\n },\n enum: {\n type: \"array\",\n minItems: 1,\n uniqueItems: true\n },\n type: {\n anyOf: [\n { $ref: \"#/definitions/simpleTypes\" },\n {\n type: \"array\",\n items: { $ref: \"#/definitions/simpleTypes\" },\n minItems: 1,\n uniqueItems: true\n }\n ]\n },\n format: { type: \"string\" },\n allOf: { $ref: \"#/definitions/schemaArray\" },\n anyOf: { $ref: \"#/definitions/schemaArray\" },\n oneOf: { $ref: \"#/definitions/schemaArray\" },\n not: { $ref: \"#\" }\n },\n dependencies: {\n exclusiveMaximum: [\"maximum\"],\n exclusiveMinimum: [\"minimum\"]\n },\n default: { }\n};\n\n//------------------------------------------------------------------------------\n// Public Interface\n//------------------------------------------------------------------------------\n\nexport default (additionalOptions = {}) => {\n const ajv = new Ajv({\n meta: false,\n useDefaults: true,\n validateSchema: false,\n missingRefs: \"ignore\",\n verbose: true,\n schemaId: \"auto\",\n ...additionalOptions\n });\n\n ajv.addMetaSchema(metaSchema);\n // eslint-disable-next-line no-underscore-dangle\n ajv._opts.defaultMeta = metaSchema.id;\n\n return ajv;\n};\n","/**\n * @fileoverview Defines a schema for configs.\n * @author Sylvan Mably\n */\n\nconst baseConfigProperties = {\n $schema: { type: \"string\" },\n env: { type: \"object\" },\n extends: { $ref: \"#/definitions/stringOrStrings\" },\n globals: { type: \"object\" },\n overrides: {\n type: \"array\",\n items: { $ref: \"#/definitions/overrideConfig\" },\n additionalItems: false\n },\n parser: { type: [\"string\", \"null\"] },\n parserOptions: { type: \"object\" },\n plugins: { type: \"array\" },\n processor: { type: \"string\" },\n rules: { type: \"object\" },\n settings: { type: \"object\" },\n noInlineConfig: { type: \"boolean\" },\n reportUnusedDisableDirectives: { type: \"boolean\" },\n\n ecmaFeatures: { type: \"object\" } // deprecated; logs a warning when used\n};\n\nconst configSchema = {\n definitions: {\n stringOrStrings: {\n oneOf: [\n { type: \"string\" },\n {\n type: \"array\",\n items: { type: \"string\" },\n additionalItems: false\n }\n ]\n },\n stringOrStringsRequired: {\n oneOf: [\n { type: \"string\" },\n {\n type: \"array\",\n items: { type: \"string\" },\n additionalItems: false,\n minItems: 1\n }\n ]\n },\n\n // Config at top-level.\n objectConfig: {\n type: \"object\",\n properties: {\n root: { type: \"boolean\" },\n ignorePatterns: { $ref: \"#/definitions/stringOrStrings\" },\n ...baseConfigProperties\n },\n additionalProperties: false\n },\n\n // Config in `overrides`.\n overrideConfig: {\n type: \"object\",\n properties: {\n excludedFiles: { $ref: \"#/definitions/stringOrStrings\" },\n files: { $ref: \"#/definitions/stringOrStringsRequired\" },\n ...baseConfigProperties\n },\n required: [\"files\"],\n additionalProperties: false\n }\n },\n\n $ref: \"#/definitions/objectConfig\"\n};\n\nexport default configSchema;\n","/**\n * @fileoverview Defines environment settings and globals.\n * @author Elan Shanker\n */\n\n//------------------------------------------------------------------------------\n// Requirements\n//------------------------------------------------------------------------------\n\nimport globals from \"globals\";\n\n//------------------------------------------------------------------------------\n// Helpers\n//------------------------------------------------------------------------------\n\n/**\n * Get the object that has difference.\n * @param {Record} current The newer object.\n * @param {Record} prev The older object.\n * @returns {Record} The difference object.\n */\nfunction getDiff(current, prev) {\n const retv = {};\n\n for (const [key, value] of Object.entries(current)) {\n if (!Object.hasOwnProperty.call(prev, key)) {\n retv[key] = value;\n }\n }\n\n return retv;\n}\n\nconst newGlobals2015 = getDiff(globals.es2015, globals.es5); // 19 variables such as Promise, Map, ...\nconst newGlobals2017 = {\n Atomics: false,\n SharedArrayBuffer: false\n};\nconst newGlobals2020 = {\n BigInt: false,\n BigInt64Array: false,\n BigUint64Array: false,\n globalThis: false\n};\n\nconst newGlobals2021 = {\n AggregateError: false,\n FinalizationRegistry: false,\n WeakRef: false\n};\n\n//------------------------------------------------------------------------------\n// Public Interface\n//------------------------------------------------------------------------------\n\n/** @type {Map} */\nexport default new Map(Object.entries({\n\n // Language\n builtin: {\n globals: globals.es5\n },\n es6: {\n globals: newGlobals2015,\n parserOptions: {\n ecmaVersion: 6\n }\n },\n es2015: {\n globals: newGlobals2015,\n parserOptions: {\n ecmaVersion: 6\n }\n },\n es2016: {\n globals: newGlobals2015,\n parserOptions: {\n ecmaVersion: 7\n }\n },\n es2017: {\n globals: { ...newGlobals2015, ...newGlobals2017 },\n parserOptions: {\n ecmaVersion: 8\n }\n },\n es2018: {\n globals: { ...newGlobals2015, ...newGlobals2017 },\n parserOptions: {\n ecmaVersion: 9\n }\n },\n es2019: {\n globals: { ...newGlobals2015, ...newGlobals2017 },\n parserOptions: {\n ecmaVersion: 10\n }\n },\n es2020: {\n globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020 },\n parserOptions: {\n ecmaVersion: 11\n }\n },\n es2021: {\n globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020, ...newGlobals2021 },\n parserOptions: {\n ecmaVersion: 12\n }\n },\n es2022: {\n globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020, ...newGlobals2021 },\n parserOptions: {\n ecmaVersion: 13\n }\n },\n es2023: {\n globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020, ...newGlobals2021 },\n parserOptions: {\n ecmaVersion: 14\n }\n },\n es2024: {\n globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020, ...newGlobals2021 },\n parserOptions: {\n ecmaVersion: 15\n }\n },\n\n // Platforms\n browser: {\n globals: globals.browser\n },\n node: {\n globals: globals.node,\n parserOptions: {\n ecmaFeatures: {\n globalReturn: true\n }\n }\n },\n \"shared-node-browser\": {\n globals: globals[\"shared-node-browser\"]\n },\n worker: {\n globals: globals.worker\n },\n serviceworker: {\n globals: globals.serviceworker\n },\n\n // Frameworks\n commonjs: {\n globals: globals.commonjs,\n parserOptions: {\n ecmaFeatures: {\n globalReturn: true\n }\n }\n },\n amd: {\n globals: globals.amd\n },\n mocha: {\n globals: globals.mocha\n },\n jasmine: {\n globals: globals.jasmine\n },\n jest: {\n globals: globals.jest\n },\n phantomjs: {\n globals: globals.phantomjs\n },\n jquery: {\n globals: globals.jquery\n },\n qunit: {\n globals: globals.qunit\n },\n prototypejs: {\n globals: globals.prototypejs\n },\n shelljs: {\n globals: globals.shelljs\n },\n meteor: {\n globals: globals.meteor\n },\n mongo: {\n globals: globals.mongo\n },\n protractor: {\n globals: globals.protractor\n },\n applescript: {\n globals: globals.applescript\n },\n nashorn: {\n globals: globals.nashorn\n },\n atomtest: {\n globals: globals.atomtest\n },\n embertest: {\n globals: globals.embertest\n },\n webextensions: {\n globals: globals.webextensions\n },\n greasemonkey: {\n globals: globals.greasemonkey\n }\n}));\n","/**\n * @fileoverview Validates configs.\n * @author Brandon Mills\n */\n\n/* eslint class-methods-use-this: \"off\" */\n\n//------------------------------------------------------------------------------\n// Typedefs\n//------------------------------------------------------------------------------\n\n/** @typedef {import(\"../shared/types\").Rule} Rule */\n\n//------------------------------------------------------------------------------\n// Requirements\n//------------------------------------------------------------------------------\n\nimport util from \"util\";\nimport * as ConfigOps from \"./config-ops.js\";\nimport { emitDeprecationWarning } from \"./deprecation-warnings.js\";\nimport ajvOrig from \"./ajv.js\";\nimport configSchema from \"../../conf/config-schema.js\";\nimport BuiltInEnvironments from \"../../conf/environments.js\";\n\nconst ajv = ajvOrig();\n\nconst ruleValidators = new WeakMap();\nconst noop = Function.prototype;\n\n//------------------------------------------------------------------------------\n// Private\n//------------------------------------------------------------------------------\nlet validateSchema;\nconst severityMap = {\n error: 2,\n warn: 1,\n off: 0\n};\n\nconst validated = new WeakSet();\n\n// JSON schema that disallows passing any options\nconst noOptionsSchema = Object.freeze({\n type: \"array\",\n minItems: 0,\n maxItems: 0\n});\n\n//-----------------------------------------------------------------------------\n// Exports\n//-----------------------------------------------------------------------------\n\nexport default class ConfigValidator {\n constructor({ builtInRules = new Map() } = {}) {\n this.builtInRules = builtInRules;\n }\n\n /**\n * Gets a complete options schema for a rule.\n * @param {Rule} rule A rule object\n * @throws {TypeError} If `meta.schema` is specified but is not an array, object or `false`.\n * @returns {Object|null} JSON Schema for the rule's options.\n * `null` if rule wasn't passed or its `meta.schema` is `false`.\n */\n getRuleOptionsSchema(rule) {\n if (!rule) {\n return null;\n }\n\n if (!rule.meta) {\n return { ...noOptionsSchema }; // default if `meta.schema` is not specified\n }\n\n const schema = rule.meta.schema;\n\n if (typeof schema === \"undefined\") {\n return { ...noOptionsSchema }; // default if `meta.schema` is not specified\n }\n\n // `schema:false` is an allowed explicit opt-out of options validation for the rule\n if (schema === false) {\n return null;\n }\n\n if (typeof schema !== \"object\" || schema === null) {\n throw new TypeError(\"Rule's `meta.schema` must be an array or object\");\n }\n\n // ESLint-specific array form needs to be converted into a valid JSON Schema definition\n if (Array.isArray(schema)) {\n if (schema.length) {\n return {\n type: \"array\",\n items: schema,\n minItems: 0,\n maxItems: schema.length\n };\n }\n\n // `schema:[]` is an explicit way to specify that the rule does not accept any options\n return { ...noOptionsSchema };\n }\n\n // `schema: