Bump packages to fix linter

This commit is contained in:
Henry Mercer 2023-01-18 20:50:03 +00:00
parent ed9506bbaf
commit 0a11e3fdd9
6063 changed files with 378752 additions and 306784 deletions

198
node_modules/@humanwhocodes/config-array/CHANGELOG.md generated vendored Normal file
View file

@ -0,0 +1,198 @@
# Changelog
## [0.11.8](https://github.com/humanwhocodes/config-array/compare/v0.11.7...v0.11.8) (2022-12-14)
### Bug Fixes
* Ensure gitignore-style directory ignores ([#74](https://github.com/humanwhocodes/config-array/issues/74)) ([8e17f4a](https://github.com/humanwhocodes/config-array/commit/8e17f4a7378cb0b417e1103d60ef397b26d2f917))
## [0.11.7](https://github.com/humanwhocodes/config-array/compare/v0.11.6...v0.11.7) (2022-10-28)
### Bug Fixes
* **deps:** Update minimatch to secure version ([3219294](https://github.com/humanwhocodes/config-array/commit/3219294bf9170c500ee9e212b59e17ef205b7c3c))
## [0.11.6](https://github.com/humanwhocodes/config-array/compare/v0.11.5...v0.11.6) (2022-10-21)
### Bug Fixes
* Only apply universal patterns if others match. ([e69c8fd](https://github.com/humanwhocodes/config-array/commit/e69c8fdbb7696b406821bc723b86b4c5304c4260))
## [0.11.5](https://github.com/humanwhocodes/config-array/compare/v0.11.4...v0.11.5) (2022-10-17)
### Bug Fixes
* Unignoring of directories should work ([e1c9dcd](https://github.com/humanwhocodes/config-array/commit/e1c9dcd05534619effe258596191ea9dc5bb37af))
## [0.11.4](https://github.com/humanwhocodes/config-array/compare/v0.11.3...v0.11.4) (2022-10-14)
### Bug Fixes
* Ensure subdirectories of ignored directories are ignored ([0df450e](https://github.com/humanwhocodes/config-array/commit/0df450eabeb595ae22fe680ce3320dc47edb1e66))
## [0.11.3](https://github.com/humanwhocodes/config-array/compare/v0.11.2...v0.11.3) (2022-10-13)
### Bug Fixes
* Ensure directories can be unignored. ([206404c](https://github.com/humanwhocodes/config-array/commit/206404c490d354a4f39ef9b4a6d0ceaec119abc5))
## [0.11.2](https://github.com/humanwhocodes/config-array/compare/v0.11.1...v0.11.2) (2022-10-03)
### Bug Fixes
* Error conditions for isDirectoryIgnored ([0bd81f5](https://github.com/humanwhocodes/config-array/commit/0bd81f53b7c217d561f70709057c7d77f17e8c6d))
* isDirectoryIgnored should match on relative path. ([3d1eaf6](https://github.com/humanwhocodes/config-array/commit/3d1eaf6389056215e27793cde9c2954c01c78df8))
* isFileIgnored should call isDirectoryIgnored ([270d359](https://github.com/humanwhocodes/config-array/commit/270d359295f376edb0c73905f62a848284d34053))
### Performance Improvements
* Cache isDirectoryIgnored calls ([c5e6720](https://github.com/humanwhocodes/config-array/commit/c5e67208618e253c08bd320efeae4b1f63641e63))
## [0.11.1](https://github.com/humanwhocodes/config-array/compare/v0.11.0...v0.11.1) (2022-09-30)
### Bug Fixes
* isDirectoryIgnored should not test negated patterns ([f6cdb68](https://github.com/humanwhocodes/config-array/commit/f6cdb688784901970fda72eb688eb1a00c44b09a))
## [0.11.0](https://github.com/humanwhocodes/config-array/compare/v0.10.7...v0.11.0) (2022-09-30)
### Features
* Add isDirectoryIgnored; deprecated isIgnored ([e6942f2](https://github.com/humanwhocodes/config-array/commit/e6942f2ce075007d39f23530593b7adb19178a52))
## [0.10.7](https://github.com/humanwhocodes/config-array/compare/v0.10.6...v0.10.7) (2022-09-29)
### Bug Fixes
* Cache negated patterns separately ([fef617b](https://github.com/humanwhocodes/config-array/commit/fef617b6999f9a4b5871d4525c82c4181bc96fb7))
## [0.10.6](https://github.com/humanwhocodes/config-array/compare/v0.10.5...v0.10.6) (2022-09-28)
### Performance Improvements
* Cache Minimatch instances ([5cf9af7](https://github.com/humanwhocodes/config-array/commit/5cf9af7ecaf227d2106be0cebd92d7f5148867e6))
## [0.10.5](https://github.com/humanwhocodes/config-array/compare/v0.10.4...v0.10.5) (2022-09-21)
### Bug Fixes
* Improve caching to improve performance ([#50](https://github.com/humanwhocodes/config-array/issues/50)) ([8a7e8ab](https://github.com/humanwhocodes/config-array/commit/8a7e8ab499bcbb10d7cbdd676197fc686966a64e))
### [0.10.4](https://www.github.com/humanwhocodes/config-array/compare/v0.10.3...v0.10.4) (2022-07-29)
### Bug Fixes
* Global ignores only when no other keys ([1f6b6ae](https://www.github.com/humanwhocodes/config-array/commit/1f6b6ae89152c1ebe118f55e7ea05c37e7c960dc))
* Re-introduce ignores fixes ([b3ec560](https://www.github.com/humanwhocodes/config-array/commit/b3ec560c485bec2f7420fd63a939448b49a073e3))
### [0.10.3](https://www.github.com/humanwhocodes/config-array/compare/v0.10.2...v0.10.3) (2022-07-20)
### Bug Fixes
* Ensure preprocess method has correct 'this' value. ([f86933a](https://www.github.com/humanwhocodes/config-array/commit/f86933a072e5a4069bab2c1ce284dedf0efa715d))
### [0.10.2](https://www.github.com/humanwhocodes/config-array/compare/v0.10.1...v0.10.2) (2022-03-18)
### Bug Fixes
* Files outside of basePath should be ignored ([fc4d7b2](https://www.github.com/humanwhocodes/config-array/commit/fc4d7b2e851959ab9ab84305f6c78c52e9cc2c3c))
### [0.10.1](https://www.github.com/humanwhocodes/config-array/compare/v0.10.0...v0.10.1) (2022-03-03)
### Bug Fixes
* Explicit matching is required against files field ([ab4e428](https://www.github.com/humanwhocodes/config-array/commit/ab4e4282ecea994ef88d273dc47aa24bf3c6972e))
## [0.10.0](https://www.github.com/humanwhocodes/config-array/compare/v0.9.5...v0.10.0) (2022-03-01)
### Features
* Add isExplicitMatch() method ([9ecd90e](https://www.github.com/humanwhocodes/config-array/commit/9ecd90e2a3e984633f535daa4da3cbfb96964fdd))
### [0.9.5](https://www.github.com/humanwhocodes/config-array/compare/v0.9.4...v0.9.5) (2022-02-23)
### Bug Fixes
* Ensure dot directories are matched correctly ([6e8d180](https://www.github.com/humanwhocodes/config-array/commit/6e8d180f43cedf3c2072d8a1229470e9fafabf5b))
* preprocessConfig should have correct 'this' value ([9641540](https://www.github.com/humanwhocodes/config-array/commit/96415402cf0012ccf8e4af6c7b934dfc1a058986))
### [0.9.4](https://www.github.com/humanwhocodes/config-array/compare/v0.9.3...v0.9.4) (2022-01-27)
### Bug Fixes
* Negated patterns to work when files match ([398c811](https://www.github.com/humanwhocodes/config-array/commit/398c8119d359493dc7b82b40df4d92ea6528375f))
### [0.9.3](https://www.github.com/humanwhocodes/config-array/compare/v0.9.2...v0.9.3) (2022-01-26)
### Bug Fixes
* Make negated ignore patterns work like gitignore ([4ee8e99](https://www.github.com/humanwhocodes/config-array/commit/4ee8e998436e2c4538b06476e0bead8a44fe5a1b))
### [0.9.2](https://www.github.com/humanwhocodes/config-array/compare/v0.9.1...v0.9.2) (2021-11-02)
### Bug Fixes
* Object merging error by upgrading object-schema ([377d06d](https://www.github.com/humanwhocodes/config-array/commit/377d06d2a44d781b0bec70b3389c48b3d5a63f94))
### [0.9.1](https://www.github.com/humanwhocodes/config-array/compare/v0.9.0...v0.9.1) (2021-10-05)
### Bug Fixes
* Properly build package for release ([168155f](https://www.github.com/humanwhocodes/config-array/commit/168155f3fed91ab35566c452efd28debf8ec2b85))
## [0.9.0](https://www.github.com/humanwhocodes/config-array/compare/v0.8.0...v0.9.0) (2021-10-04)
### Features
* getConfig() now returns undefined when no configs match. ([a563b82](https://www.github.com/humanwhocodes/config-array/commit/a563b8255d4eb2bb7745314e3f00ef53792b343f))
## [0.8.0](https://www.github.com/humanwhocodes/config-array/compare/v0.7.0...v0.8.0) (2021-10-01)
### Features
* Add isIgnored() method ([343e5a0](https://www.github.com/humanwhocodes/config-array/commit/343e5a0a9e32028bfc6c0bf1ec0c6badf74f47f9))
### Bug Fixes
* Ensure global ignores are honored ([343e5a0](https://www.github.com/humanwhocodes/config-array/commit/343e5a0a9e32028bfc6c0bf1ec0c6badf74f47f9))
## [0.7.0](https://www.github.com/humanwhocodes/config-array/compare/v0.6.0...v0.7.0) (2021-09-24)
### Features
* Only object configs by default ([5645f24](https://www.github.com/humanwhocodes/config-array/commit/5645f241b2412a3263a02ef9e3a9bd19cc86035d))
## [0.6.0](https://www.github.com/humanwhocodes/config-array/compare/v0.5.0...v0.6.0) (2021-04-20)
### Features
* Add the normalizeSync() method ([3e347f9](https://www.github.com/humanwhocodes/config-array/commit/3e347f9d77c5ca2b15995e75ff7bc4fb96b7d66e))
* Allow async config functions ([a9def0f](https://www.github.com/humanwhocodes/config-array/commit/a9def0faf579c223349dfe08d2486756840538c3))

View file

@ -74,11 +74,11 @@ const configs = new ConfigArray(rawConfigs, {
});
```
This example reads in an object or array from `my.config.js` and passes it into the `ConfigArray` constructor as the first argument. The second argument is an object specifying the `basePath` (the directoy in which `my.config.js` is found) and a `schema` to define the additional properties of a config object beyond `files`, `ignores`, and `name`.
This example reads in an object or array from `my.config.js` and passes it into the `ConfigArray` constructor as the first argument. The second argument is an object specifying the `basePath` (the directory in which `my.config.js` is found) and a `schema` to define the additional properties of a config object beyond `files`, `ignores`, and `name`.
### Specifying a Schema
The `schema` option is required for you to use additional properties in config objects. The schema is object that follows the format of an [`ObjectSchema`](https://npmjs.com/package/@humanwhocodes/object-schema). The schema specifies both validation and merge rules that the `ConfigArray` instance needs to combine configs when there are multiple matches. Here's an example:
The `schema` option is required for you to use additional properties in config objects. The schema is an object that follows the format of an [`ObjectSchema`](https://npmjs.com/package/@humanwhocodes/object-schema). The schema specifies both validation and merge rules that the `ConfigArray` instance needs to combine configs when there are multiple matches. Here's an example:
```js
const configFilename = path.resolve(process.cwd(), "my.config.js");
@ -106,14 +106,17 @@ const configs = new ConfigArray(rawConfigs, {
// the path to match filenames from
basePath: process.cwd(),
// additional items in each config
schema: mySchema
// additional item schemas in each config
schema: mySchema,
// additional config types supported (default: [])
extraConfigTypes: ["array", "function"];
});
```
### Config Arrays
Config arrays can be multidimensional, so it's possible for a config array to contain another config array, such as:
Config arrays can be multidimensional, so it's possible for a config array to contain another config array when `extraConfigTypes` contains `"array"`, such as:
```js
export default [
@ -171,11 +174,44 @@ If the `files` array contains a function, then that function is called with the
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.
If a pattern in the files array begins with `!` then it excludes that pattern. In the preceding example, any filename that doesn't end with `.js` will automatically getting a `settings.js` property set to `false`.
If a pattern in the files array begins with `!` then it excludes that pattern. In the preceding example, any filename that doesn't end with `.js` will automatically get a `settings.js` property set to `false`.
You can also specify an `ignores` key that will force files matching those patterns to not be included. If the `ignores` key is in a config object without any other keys, then those ignores will always be applied; otherwise those ignores act as exclusions. Here's an example:
```js
export default [
// Always ignored
{
ignores: ["**/.git/**", "**/node_modules/**"]
},
// .eslintrc.js file is ignored only when .js file matches
{
files: ["**/*.js"],
ignores: [".eslintrc.js"]
handler: jsHandler
}
];
```
You can use negated patterns in `ignores` to exclude a file that was already ignored, such as:
```js
export default [
// Ignore all JSON files except tsconfig.json
{
files: ["**/*"],
ignores: ["**/*.json", "!tsconfig.json"]
},
];
```
### Config Functions
Config arrays can also include config functions. A config function accepts a single parameter, `context` (defined by you), and must return either a config object or a config array (it cannot return another function). Config functions allow end users to execute code in the creation of appropriate config objects. Here's an example:
Config arrays can also include config functions when `extraConfigTypes` contains `"function"`. A config function accepts a single parameter, `context` (defined by you), and must return either a config object or a config array (it cannot return another function). Config functions allow end users to execute code in the creation of appropriate config objects. Here's an example:
```js
export default [
@ -210,7 +246,7 @@ export default [
When a config array is normalized, each function is executed and replaced in the config array with the return value.
**Note:** Config functions cannot be async. This will be added in a future version.
**Note:** Config functions can also be async.
### Normalizing Config Arrays
@ -226,6 +262,14 @@ await configs.normalize({
The `normalize()` method returns a promise, so be sure to use the `await` operator. The config array instance is normalized in-place, so you don't need to create a new variable.
If you want to disallow async config functions, you can call `normalizeSync()` instead. This method is completely synchronous and does not require using the `await` operator as it does not return a promise:
```js
await configs.normalizeSync({
name: "MyApp"
});
```
**Important:** Once a `ConfigArray` is normalized, it cannot be changed further. You can, however, create a new `ConfigArray` and pass in the normalized instance to create an unnormalized copy.
### Getting Config for a File
@ -244,6 +288,46 @@ A few things to keep in mind:
* You must pass in the absolute filename to get a config for.
* 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 ending 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:
```js
const ignored = configs.isFileIgnored('/foo/bar/baz.txt');
```
A file is considered ignored if any of the following is true:
* **It's parent directory is ignored.** For example, if `foo` is in `ignores`, then `foo/a.js` is considered ignored.
* **It has an ancestor directory that is ignored.** For example, if `foo` is in `ignores`, then `foo/baz/a.js` is considered ignored.
* **It matches an ignored file pattern.** For example, if `**/a.js` is in `ignores`, then `foo/a.js` and `foo/baz/a.js` are considered ignored.
* **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:
```js
const ignored = configs.isDirectoryIgnored('/foo/bar/');
```
A directory is considered ignored if any of the following is true:
* **It's parent directory is ignored.** For example, if `foo` is in `ignores`, then `foo/baz` is considered ignored.
* **It has an ancestor directory that is ignored.** For example, if `foo` is in `ignores`, then `foo/bar/baz/a.js` is considered ignored.
* **It matches and ignored file pattern.** For example, if `**/a.js` is in `ignores`, then `foo/a.js` and `foo/baz/a.js` are considered ignored.
* **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.
**Important:** A pattern such as `foo/**` means that `foo` and `foo/` are *not* ignored whereas `foo/bar` is ignored. If you want to ignore `foo` and all of its subdirectories, use the pattern `foo` or `foo/` in `ignores`.
## Caching Mechanisms
Each `ConfigArray` aggressively caches configuration objects to avoid unnecessary work. This caching occurs in two ways:
1. **File-based Caching.** For each filename that is passed into a method, the resulting config is cached against that filename so you're always guaranteed to get the same object returned from `getConfig()` whenever you pass the same filename in.
2. **Index-based Caching.** Whenever a config is calculated, the config elements that were used to create the config are also cached. So if a given filename matches elements 1, 5, and 7, the resulting config is cached with a key of `1,5,7`. That way, if another file is passed that matches the same config elements, the result is already known and doesn't have to be recalculated. That means two files that match all the same elements will return the same config from `getConfig()`.
## Acknowledgements

View file

@ -103,12 +103,18 @@ const baseSchema = Object.freeze({
// Helpers
//------------------------------------------------------------------------------
const Minimatch = minimatch.Minimatch;
const minimatchCache = new Map();
const negatedMinimatchCache = new Map();
const debug = createDebug('@hwc/config-array');
const MINIMATCH_OPTIONS = {
matchBase: true
// matchBase: true,
dot: true
};
const CONFIG_TYPES = new Set(['array', 'function']);
/**
* Shorthand for checking if a value is a string.
* @param {any} value The value to check.
@ -118,27 +124,135 @@ function isString(value) {
return typeof value === 'string';
}
/**
* Asserts that the files key of a config object is a nonempty array.
* @param {object} config The config object to check.
* @returns {void}
* @throws {TypeError} If the files key isn't a nonempty array.
*/
function assertNonEmptyFilesArray(config) {
if (!Array.isArray(config.files) || config.files.length === 0) {
throw new TypeError('The files key must be a non-empty array.');
}
}
/**
* Wrapper around minimatch that caches minimatch patterns for
* faster matching speed over multiple file path evaluations.
* @param {string} filepath The file path to match.
* @param {string} pattern The glob pattern to match against.
* @param {object} options The minimatch options to use.
* @returns
*/
function doMatch(filepath, pattern, options = {}) {
let cache = minimatchCache;
if (options.flipNegate) {
cache = negatedMinimatchCache;
}
let matcher = cache.get(pattern);
if (!matcher) {
matcher = new Minimatch(pattern, Object.assign({}, MINIMATCH_OPTIONS, options));
cache.set(pattern, matcher);
}
return matcher.match(filepath);
}
/**
* Normalizes a `ConfigArray` by flattening it and executing any functions
* that are found inside.
* @param {Array} items The items in a `ConfigArray`.
* @param {Object} context The context object to pass into any function
* found.
* @returns {Array} A flattened array containing only config objects.
* @param {Array<string>} extraConfigTypes The config types to check.
* @returns {Promise<Array>} A flattened array containing only config objects.
* @throws {TypeError} When a config function returns a function.
*/
async function normalize(items, context) {
async function normalize(items, context, extraConfigTypes) {
// TODO: Allow async config functions
const allowFunctions = extraConfigTypes.includes('function');
const allowArrays = extraConfigTypes.includes('array');
function *flatTraverse(array) {
async function* flatTraverse(array) {
for (let item of array) {
if (typeof item === 'function') {
if (!allowFunctions) {
throw new TypeError('Unexpected function.');
}
item = item(context);
if (item.then) {
item = await item;
}
}
if (Array.isArray(item)) {
yield * flatTraverse(item);
if (!allowArrays) {
throw new TypeError('Unexpected array.');
}
yield* flatTraverse(item);
} else if (typeof item === 'function') {
throw new TypeError('A config function can only return an object or array.');
} else {
yield item;
}
}
}
/*
* Async iterables cannot be used with the spread operator, so we need to manually
* create the array to return.
*/
const asyncIterable = await flatTraverse(items);
const configs = [];
for await (const config of asyncIterable) {
configs.push(config);
}
return configs;
}
/**
* Normalizes a `ConfigArray` by flattening it and executing any functions
* that are found inside.
* @param {Array} items The items in a `ConfigArray`.
* @param {Object} context The context object to pass into any function
* found.
* @param {Array<string>} extraConfigTypes The config types to check.
* @returns {Array} A flattened array containing only config objects.
* @throws {TypeError} When a config function returns a function.
*/
function normalizeSync(items, context, extraConfigTypes) {
const allowFunctions = extraConfigTypes.includes('function');
const allowArrays = extraConfigTypes.includes('array');
function* flatTraverse(array) {
for (let item of array) {
if (typeof item === 'function') {
if (!allowFunctions) {
throw new TypeError('Unexpected function.');
}
item = item(context);
if (item.then) {
throw new TypeError('Async config functions are not supported.');
}
}
if (Array.isArray(item)) {
if (!allowArrays) {
throw new TypeError('Unexpected array.');
}
yield* flatTraverse(item);
} else if (typeof item === 'function') {
throw new TypeError('A config function can only return an object or array.');
} else {
@ -150,6 +264,52 @@ async function normalize(items, context) {
return [...flatTraverse(items)];
}
/**
* Determines if a given file path should be ignored based on the given
* matcher.
* @param {Array<string|() => 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.
* @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') {
return matcher(filePath);
}
// don't check negated patterns because we're not ignored yet
if (!matcher.startsWith('!')) {
return doMatch(relativeFilePath, matcher);
}
// otherwise we're still not ignored
return false;
}
// only need to check negated patterns because we're ignored
if (typeof matcher === 'string' && matcher.startsWith('!')) {
return !doMatch(relativeFilePath, matcher, {
flipNegate: true
});
}
return ignored;
}, false);
}
/**
* Determines if a given file path is matched by a config. If the config
* has no `files` field, then it matches; otherwise, if a `files` field
@ -162,31 +322,32 @@ async function normalize(items, context) {
*/
function pathMatches(filePath, basePath, config) {
// a config without a `files` field always matches
if (!config.files) {
return true;
}
/*
* 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);
// if files isn't an array, throw an error
if (!Array.isArray(config.files) || config.files.length === 0) {
throw new TypeError('The files key must be a non-empty array.');
}
const relativeFilePath = path.relative(basePath, filePath);
assertNonEmptyFilesArray(config);
// match both strings and functions
const match = pattern => {
if (isString(pattern)) {
return minimatch(relativeFilePath, pattern, MINIMATCH_OPTIONS);
return doMatch(relativeFilePath, pattern);
}
if (typeof pattern === 'function') {
return pattern(filePath);
}
throw new TypeError(`Unexpected matcher type ${pattern}.`);
};
// check for all matches to config.files
let matches = config.files.some(pattern => {
let filePathMatchesPattern = config.files.some(pattern => {
if (Array.isArray(pattern)) {
return pattern.every(match);
}
@ -198,13 +359,11 @@ function pathMatches(filePath, basePath, config) {
* If the file path matches the config.files patterns, then check to see
* if there are any files to ignore.
*/
if (matches && config.ignores) {
matches = !config.ignores.some(pattern => {
return minimatch(filePath, pattern, MINIMATCH_OPTIONS);
});
if (filePathMatchesPattern && config.ignores) {
filePathMatchesPattern = !shouldIgnorePath(config.ignores, filePath, relativeFilePath);
}
return matches;
return filePathMatchesPattern;
}
/**
@ -220,6 +379,24 @@ function assertNormalized(configArray) {
}
}
/**
* Ensures that config types are valid.
* @param {Array<string>} extraConfigTypes The config types to check.
* @returns {void}
* @throws {Error} When the config types array is invalid.
*/
function assertExtraConfigTypes(extraConfigTypes) {
if (extraConfigTypes.length > 2) {
throw new TypeError('configTypes must be an array with at most two items.');
}
for (const configType of extraConfigTypes) {
if (!CONFIG_TYPES.has(configType)) {
throw new TypeError(`Unexpected config type "${configType}" found. Expected one of: "object", "array", "function".`);
}
}
}
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
@ -232,6 +409,9 @@ const ConfigArraySymbol = {
preprocessConfig: Symbol('preprocessConfig')
};
// used to store calculate data for faster lookup
const dataCache = new WeakMap();
/**
* Represents an array of config objects and provides method for working with
* those config objects.
@ -247,8 +427,15 @@ class ConfigArray extends Array {
* configs have already been normalized.
* @param {Object} [options.schema] The additional schema
* definitions to use for the ConfigArray schema.
* @param {Array<string>} [options.configTypes] List of config types supported.
*/
constructor(configs, { basePath = '', normalized = false, schema: customSchema } = {}) {
constructor(configs, {
basePath = '',
normalized = false,
schema: customSchema,
extraConfigTypes = []
} = {}
) {
super();
/**
@ -265,10 +452,9 @@ class ConfigArray extends Array {
* @type ObjectSchema
* @private
*/
this[ConfigArraySymbol.schema] = new objectSchema.ObjectSchema({
...customSchema,
...baseSchema
});
this[ConfigArraySymbol.schema] = new objectSchema.ObjectSchema(
Object.assign({}, customSchema, baseSchema)
);
/**
* The path of the config file that this array was loaded from.
@ -278,6 +464,15 @@ class ConfigArray extends Array {
*/
this.basePath = basePath;
assertExtraConfigTypes(extraConfigTypes);
/**
* The supported config types.
* @property configTypes
* @type Array<string>
*/
this.extraConfigTypes = Object.freeze([...extraConfigTypes]);
/**
* A cache to store calculated configs for faster repeat lookup.
* @property configCache
@ -286,6 +481,14 @@ class ConfigArray extends Array {
*/
this[ConfigArraySymbol.configCache] = new Map();
// init cache
dataCache.set(this, {
explicitMatches: new Map(),
directoryMatches: new Map(),
files: undefined,
ignores: undefined
});
// load the configs into this array
if (Array.isArray(configs)) {
this.push(...configs);
@ -308,54 +511,110 @@ class ConfigArray extends Array {
/**
* Returns the `files` globs from every config object in the array.
* Negated patterns (those beginning with `!`) are not returned.
* This can be used to determine which files will be matched by a
* config array or to use as a glob pattern when no patterns are provided
* for a command line interface.
* @returns {string[]} An array of string patterns.
* @returns {Array<string|Function>} An array of matchers.
*/
get files() {
assertNormalized(this);
// if this data has been cached, retrieve it
const cache = dataCache.get(this);
if (cache.files) {
return cache.files;
}
// otherwise calculate it
const result = [];
for (const config of this) {
if (config.files) {
config.files.forEach(filePattern => {
if (Array.isArray(filePattern)) {
result.push(...filePattern.filter(pattern => {
return isString(pattern) && !pattern.startsWith('!');
}));
} else if (isString(filePattern) && !filePattern.startsWith('!')) {
result.push(filePattern);
}
result.push(filePattern);
});
}
}
// store result
cache.files = result;
dataCache.set(this, cache);
return result;
}
/**
* Returns the file globs that should always be ignored regardless of
* Returns ignore matchers that should always be ignored regardless of
* the matching `files` fields in any configs. This is necessary to mimic
* the behavior of things like .gitignore and .eslintignore, allowing a
* globbing operation to be faster.
* @returns {string[]} An array of string patterns to be ignored.
* @returns {string[]} An array of string patterns and functions to be ignored.
*/
get ignores() {
assertNormalized(this);
// if this data has been cached, retrieve it
const cache = dataCache.get(this);
if (cache.ignores) {
return cache.ignores;
}
// otherwise calculate it
const result = [];
for (const config of this) {
if (config.ignores && !config.files) {
result.push(...config.ignores.filter(isString));
/*
* We only count ignores if there are no other keys in the object.
* In this case, it acts list a globally ignored pattern. If there
* are additional keys, then ignores act like exclusions.
*/
if (config.ignores && Object.keys(config).length === 1) {
/*
* If there are directory ignores, then we need to double up
* the patterns to be ignored. For instance, `foo` will also
* need `foo/**` in order to account for subdirectories.
*/
config.ignores.forEach(ignore => {
result.push(ignore);
if (typeof ignore === 'string') {
// unignoring files won't work unless we unignore directories too
if (ignore.startsWith('!')) {
if (ignore.endsWith('/**')) {
result.push(ignore.slice(0, ignore.length - 3));
} else if (ignore.endsWith('/*')) {
result.push(ignore.slice(0, ignore.length - 2));
}
}
// directories should work with or without a trailing slash
if (ignore.endsWith('/')) {
result.push(ignore.slice(0, ignore.length - 1));
result.push(ignore + '**');
} else if (!ignore.endsWith('*')) {
result.push(ignore + '/**');
}
}
});
}
}
// store result
cache.ignores = result;
dataCache.set(this, cache);
return result;
}
@ -371,14 +630,35 @@ class ConfigArray extends Array {
* Normalizes a config array by flattening embedded arrays and executing
* config functions.
* @param {ConfigContext} context The context object for config functions.
* @returns {ConfigArray} A new ConfigArray instance that is normalized.
* @returns {Promise<ConfigArray>} The current ConfigArray instance.
*/
async normalize(context = {}) {
if (!this.isNormalized()) {
const normalizedConfigs = await normalize(this, context);
const normalizedConfigs = await normalize(this, context, this.extraConfigTypes);
this.length = 0;
this.push(...normalizedConfigs.map(this[ConfigArraySymbol.preprocessConfig]));
this.push(...normalizedConfigs.map(this[ConfigArraySymbol.preprocessConfig].bind(this)));
this[ConfigArraySymbol.isNormalized] = true;
// prevent further changes
Object.freeze(this);
}
return this;
}
/**
* Normalizes a config array by flattening embedded arrays and executing
* config functions.
* @param {ConfigContext} context The context object for config functions.
* @returns {ConfigArray} The current ConfigArray instance.
*/
normalizeSync(context = {}) {
if (!this.isNormalized()) {
const normalizedConfigs = normalizeSync(this, context, this.extraConfigTypes);
this.length = 0;
this.push(...normalizedConfigs.map(this[ConfigArraySymbol.preprocessConfig].bind(this)));
this[ConfigArraySymbol.isNormalized] = true;
// prevent further changes
@ -411,6 +691,56 @@ class ConfigArray extends Array {
return config;
}
/**
* Determines if a given file path explicitly matches a `files` entry
* and also doesn't match an `ignores` entry. Configs that don't have
* a `files` property are not considered an explicit match.
* @param {string} filePath The complete path of a file to check.
* @returns {boolean} True if the file path matches a `files` entry
* or false if not.
*/
isExplicitMatch(filePath) {
assertNormalized(this);
const cache = dataCache.get(this);
// first check the cache to avoid duplicate work
let result = cache.explicitMatches.get(filePath);
if (typeof result == 'boolean') {
return result;
}
// TODO: Maybe move elsewhere? Maybe combine with getConfig() logic?
const relativeFilePath = path.relative(this.basePath, filePath);
if (shouldIgnorePath(this.ignores, filePath, relativeFilePath)) {
debug(`Ignoring ${filePath}`);
// cache and return result
cache.explicitMatches.set(filePath, false);
return false;
}
// filePath isn't automatically ignored, so try to find a match
for (const config of this) {
if (!config.files) {
continue;
}
if (pathMatches(filePath, this.basePath, config)) {
debug(`Matching config found for ${filePath}`);
cache.explicitMatches.set(filePath, true);
return true;
}
}
return false;
}
/**
* Returns the config object for a given file path.
* @param {string} filePath The complete path of a file to get a config for.
@ -420,37 +750,229 @@ class ConfigArray extends Array {
assertNormalized(this);
// first check the cache to avoid duplicate work
let finalConfig = this[ConfigArraySymbol.configCache].get(filePath);
const cache = this[ConfigArraySymbol.configCache];
// first check the cache for a filename match to avoid duplicate work
let finalConfig = cache.get(filePath);
if (finalConfig) {
return finalConfig;
}
// No config found in cache, so calculate a new one
// next check to see if the file should be ignored
const matchingConfigs = [];
// check if this should be ignored due to its directory
if (this.isDirectoryIgnored(path.dirname(filePath))) {
debug(`Ignoring ${filePath} based on directory pattern`);
for (const config of this) {
if (pathMatches(filePath, this.basePath, config)) {
debug(`Matching config found for ${filePath}`);
matchingConfigs.push(config);
} else {
debug(`No matching config found for ${filePath}`);
}
// cache and return result - finalConfig is undefined at this point
cache.set(filePath, finalConfig);
return finalConfig;
}
finalConfig = matchingConfigs.reduce((result, config) => {
return this[ConfigArraySymbol.schema].merge(result, config);
// TODO: Maybe move elsewhere?
const relativeFilePath = path.relative(this.basePath, filePath);
if (shouldIgnorePath(this.ignores, filePath, relativeFilePath)) {
debug(`Ignoring ${filePath} based on file pattern`);
// cache and return result - finalConfig is undefined at this point
cache.set(filePath, finalConfig);
return finalConfig;
}
// filePath isn't automatically ignored, so try to construct config
const matchingConfigIndices = [];
let matchFound = false;
const universalPattern = /\/\*{1,2}$/;
this.forEach((config, index) => {
if (!config.files) {
debug(`Anonymous universal config found for ${filePath}`);
matchingConfigIndices.push(index);
return;
}
assertNonEmptyFilesArray(config);
/*
* If a config has a files pattern ending in /** or /*, and the
* filePath only matches those patterns, then the config is only
* applied if there is another config where the filePath matches
* a file with a specific extensions such as *.js.
*/
const universalFiles = config.files.filter(
pattern => universalPattern.test(pattern)
);
// universal patterns were found so we need to check the config twice
if (universalFiles.length) {
debug('Universal files patterns found. Checking carefully.');
const nonUniversalFiles = config.files.filter(
pattern => !universalPattern.test(pattern)
);
// check that the config matches without the non-universal files first
if (
nonUniversalFiles.length &&
pathMatches(
filePath, this.basePath,
{ files: nonUniversalFiles, ignores: config.ignores }
)
) {
debug(`Matching config found for ${filePath}`);
matchingConfigIndices.push(index);
matchFound = true;
return;
}
// if there wasn't a match then check if it matches with universal files
if (
universalFiles.length &&
pathMatches(
filePath, this.basePath,
{ files: universalFiles, ignores: config.ignores }
)
) {
debug(`Matching config found for ${filePath}`);
matchingConfigIndices.push(index);
return;
}
// if we make here, then there was no match
return;
}
// the normal case
if (pathMatches(filePath, this.basePath, config)) {
debug(`Matching config found for ${filePath}`);
matchingConfigIndices.push(index);
matchFound = true;
return;
}
});
// if matching both files and ignores, there will be no config to create
if (!matchFound) {
debug(`No matching configs found for ${filePath}`);
// cache and return result - finalConfig is undefined at this point
cache.set(filePath, finalConfig);
return finalConfig;
}
// check to see if there is a config cached by indices
finalConfig = cache.get(matchingConfigIndices.toString());
if (finalConfig) {
// also store for filename for faster lookup next time
cache.set(filePath, finalConfig);
return finalConfig;
}
// otherwise construct the config
finalConfig = matchingConfigIndices.reduce((result, index) => {
return this[ConfigArraySymbol.schema].merge(result, this[index]);
}, {}, this);
finalConfig = this[ConfigArraySymbol.finalizeConfig](finalConfig);
this[ConfigArraySymbol.configCache].set(filePath, finalConfig);
cache.set(filePath, finalConfig);
cache.set(matchingConfigIndices.toString(), finalConfig);
return finalConfig;
}
/**
* Determines if the given filepath is ignored based on the configs.
* @param {string} filePath The complete path of a file to check.
* @returns {boolean} True if the path is ignored, false if not.
* @deprecated Use `isFileIgnored` instead.
*/
isIgnored(filePath) {
return this.isFileIgnored(filePath);
}
/**
* Determines if the given filepath is ignored based on the configs.
* @param {string} filePath The complete path of a file to check.
* @returns {boolean} True if the path is ignored, false if not.
*/
isFileIgnored(filePath) {
return this.getConfig(filePath) === undefined;
}
/**
* Determines if the given directory is ignored based on the configs.
* This checks only default `ignores` that don't have `files` in the
* 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.
* @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) {
assertNormalized(this);
const relativeDirectoryPath = path.relative(this.basePath, directoryPath)
.replace(/\\/g, '/');
if (relativeDirectoryPath.startsWith('..')) {
return true;
}
// first check the cache
const cache = dataCache.get(this).directoryMatches;
if (cache.has(relativeDirectoryPath)) {
return cache.get(relativeDirectoryPath);
}
const directoryParts = relativeDirectoryPath.split('/');
let relativeDirectoryToCheck = '';
let result = false;
/*
* In order to get the correct gitignore-style ignores, where an
* ignored parent directory cannot have any descendants unignored,
* we need to check every directory starting at the parent all
* the way down to the actual requested directory.
*
* We aggressively cache all of this info to make sure we don't
* have to recalculate everything for every call.
*/
do {
relativeDirectoryToCheck += directoryParts.shift() + '/';
result = shouldIgnorePath(
this.ignores,
path.join(this.basePath, relativeDirectoryToCheck),
relativeDirectoryToCheck
);
cache.set(relativeDirectoryToCheck, result);
} while (!result && directoryParts.length);
// also cache the result for the requested path
cache.set(relativeDirectoryPath, result);
return result;
}
}
exports.ConfigArray = ConfigArray;

View file

@ -1,6 +1,6 @@
{
"name": "@humanwhocodes/config-array",
"version": "0.5.0",
"version": "0.11.8",
"description": "Glob-based configuration matching.",
"author": "Nicholas C. Zakas",
"main": "api.js",
@ -19,6 +19,7 @@
"build": "rollup -c",
"format": "nitpik",
"lint": "eslint *.config.js src/*.js tests/*.js",
"lint:fix": "eslint --fix *.config.js src/*.js tests/*.js",
"prepublish": "npm run build",
"test:coverage": "nyc --include src/*.js npm run test",
"test": "mocha -r esm tests/ --recursive"
@ -28,7 +29,6 @@
},
"lint-staged": {
"*.js": [
"nitpik",
"eslint --fix --ignore-pattern '!.eslintrc.js'"
]
},
@ -42,20 +42,20 @@
"node": ">=10.10.0"
},
"dependencies": {
"@humanwhocodes/object-schema": "^1.2.0",
"@humanwhocodes/object-schema": "^1.2.1",
"debug": "^4.1.1",
"minimatch": "^3.0.4"
"minimatch": "^3.0.5"
},
"devDependencies": {
"@nitpik/javascript": "^0.3.3",
"@nitpik/javascript": "0.4.0",
"@nitpik/node": "0.0.5",
"chai": "^4.2.0",
"eslint": "^6.7.1",
"esm": "^3.2.25",
"lint-staged": "^10.2.8",
"mocha": "^6.1.4",
"nyc": "^14.1.1",
"rollup": "^1.12.3",
"yorkie": "^2.0.0"
"chai": "4.3.7",
"eslint": "8.29.0",
"esm": "3.2.25",
"lint-staged": "13.1.0",
"mocha": "6.2.3",
"nyc": "14.1.1",
"rollup": "1.16.6",
"yorkie": "2.0.0"
}
}
}

View file

@ -0,0 +1,15 @@
# Changelog
## [1.0.1](https://github.com/humanwhocodes/module-importer/compare/v1.0.0...v1.0.1) (2022-08-18)
### Bug Fixes
* Ensure CommonJS mode works correctly. ([cf54a0b](https://github.com/humanwhocodes/module-importer/commit/cf54a0b998085066fbe1776dd0b4cacd808cc192)), closes [#6](https://github.com/humanwhocodes/module-importer/issues/6)
## 1.0.0 (2022-08-17)
### Features
* Implement ModuleImporter ([3ce4e82](https://www.github.com/humanwhocodes/module-importer/commit/3ce4e820c30c114e787bfed00a0966ac4772f563))

201
node_modules/@humanwhocodes/module-importer/LICENSE generated vendored Normal file
View file

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

80
node_modules/@humanwhocodes/module-importer/README.md generated vendored Normal file
View file

@ -0,0 +1,80 @@
# ModuleImporter
by [Nicholas C. Zakas](https://humanwhocodes.com)
If you find this useful, please consider supporting my work with a [donation](https://humanwhocodes.com/donate).
## Description
A utility for seamlessly importing modules in Node.js regardless if they are CommonJS or ESM format. Under the hood, this uses `import()` and relies on Node.js's CommonJS compatibility to work correctly. This ensures that the correct locations and formats are used for CommonJS so you can call one method and not worry about any compatibility issues.
The problem with the default `import()` is that it always resolves relative to the file location in which it is called. If you want to resolve from a different location, you need to jump through a few hoops to achieve that. This package makes it easy to both resolve and import modules from any directory.
## Usage
### Node.js
Install using [npm][npm] or [yarn][yarn]:
```
npm install @humanwhocodes/module-importer
# or
yarn add @humanwhocodes/module-importer
```
Import into your Node.js project:
```js
// CommonJS
const { ModuleImporter } = require("@humanwhocodes/module-importer");
// ESM
import { ModuleImporter } from "@humanwhocodes/module-importer";
```
### Bun
Install using this command:
```
bun add @humanwhocodes/module-importer
```
Import into your Bun project:
```js
import { ModuleImporter } from "@humanwhocodes/module-importer";
```
## API
After importing, create a new instance of `ModuleImporter` to start emitting events:
```js
// cwd can be omitted to use process.cwd()
const importer = new ModuleImporter(cwd);
// you can resolve the location of any package
const location = importer.resolve("./some-file.cjs");
// you can also import directly
const module = importer.import("./some-file.cjs");
```
For both `resolve()` and `import()`, you can pass in package names and filenames.
## Developer Setup
1. Fork the repository
2. Clone your fork
3. Run `npm install` to setup dependencies
4. Run `npm test` to run tests
## License
Apache 2.0
[npm]: https://npmjs.com/
[yarn]: https://yarnpkg.com/

View file

@ -0,0 +1,22 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var module$1 = require('module');
var url = require('url');
var path = require('path');
/**
* @fileoverview Universal module importer
*/
//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------
const __filename$1 = url.fileURLToPath((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('module-importer.cjs', document.baseURI).href)));
const __dirname$1 = path.dirname(__filename$1);
const require$1 = module$1.createRequire(__dirname$1 + "/");
const { ModuleImporter } = require$1("./module-importer.cjs");
exports.ModuleImporter = ModuleImporter;

View file

@ -0,0 +1,27 @@
export class ModuleImporter {
/**
* Creates a new instance.
* @param {string} [cwd] The current working directory to resolve from.
*/
constructor(cwd?: string);
/**
* The base directory from which paths should be resolved.
* @type {string}
*/
cwd: string;
/**
* Resolves a module based on its name or location.
* @param {string} specifier Either an npm package name or
* relative file path.
* @returns {string|undefined} The location of the import.
* @throws {Error} If specifier cannot be located.
*/
resolve(specifier: string): string | undefined;
/**
* Imports a module based on its name or location.
* @param {string} specifier Either an npm package name or
* relative file path.
* @returns {Promise<object>} The module's object.
*/
import(specifier: string): Promise<object>;
}

View file

@ -0,0 +1,2 @@
export { ModuleImporter };
import { ModuleImporter } from "./module-importer.cjs";

View file

@ -0,0 +1,18 @@
import { createRequire } from 'module';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
/**
* @fileoverview Universal module importer
*/
//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const require = createRequire(__dirname + "/");
const { ModuleImporter } = require("./module-importer.cjs");
export { ModuleImporter };

View file

@ -0,0 +1,65 @@
{
"name": "@humanwhocodes/module-importer",
"version": "1.0.1",
"description": "Universal module importer for Node.js",
"main": "src/module-importer.cjs",
"module": "src/module-importer.js",
"type": "module",
"types": "dist/module-importer.d.ts",
"exports": {
"require": "./src/module-importer.cjs",
"import": "./src/module-importer.js"
},
"files": [
"dist",
"src"
],
"publishConfig": {
"access": "public"
},
"gitHooks": {
"pre-commit": "lint-staged"
},
"lint-staged": {
"*.js": [
"eslint --fix"
]
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/nzakas"
},
"scripts": {
"build": "rollup -c && tsc",
"prepare": "npm run build",
"lint": "eslint src/ tests/",
"test:unit": "c8 mocha tests/module-importer.test.js",
"test:build": "node tests/pkg.test.cjs && node tests/pkg.test.mjs",
"test": "npm run test:unit && npm run test:build"
},
"repository": {
"type": "git",
"url": "git+https://github.com/humanwhocodes/module-importer.git"
},
"keywords": [
"modules",
"esm",
"commonjs"
],
"engines": {
"node": ">=12.22"
},
"author": "Nicholas C. Zaks",
"license": "Apache-2.0",
"devDependencies": {
"@types/node": "^18.7.6",
"c8": "7.12.0",
"chai": "4.3.6",
"eslint": "8.22.0",
"lint-staged": "13.0.3",
"mocha": "9.2.2",
"rollup": "2.78.0",
"typescript": "4.7.4",
"yorkie": "2.0.0"
}
}

View file

@ -0,0 +1,81 @@
/**
* @fileoverview Universal module importer
*/
//-----------------------------------------------------------------------------
// Imports
//-----------------------------------------------------------------------------
const { createRequire } = require("module");
const { pathToFileURL } = require("url");
//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------
const SLASHES = new Set(["/", "\\"]);
/**
* Normalizes directories to have a trailing slash.
* Resolve is pretty finicky -- if the directory name doesn't have
* a trailing slash then it tries to look in the parent directory.
* i.e., if the directory is "/usr/nzakas/foo" it will start the
* search in /usr/nzakas. However, if the directory is "/user/nzakas/foo/",
* then it will start the search in /user/nzakas/foo.
* @param {string} directory The directory to check.
* @returns {string} The normalized directory.
*/
function normalizeDirectory(directory) {
if (!SLASHES.has(directory[directory.length-1])) {
return directory + "/";
}
return directory;
}
//-----------------------------------------------------------------------------
// Exports
//-----------------------------------------------------------------------------
/**
* Class for importing both CommonJS and ESM modules in Node.js.
*/
exports.ModuleImporter = class ModuleImporter {
/**
* Creates a new instance.
* @param {string} [cwd] The current working directory to resolve from.
*/
constructor(cwd = process.cwd()) {
/**
* The base directory from which paths should be resolved.
* @type {string}
*/
this.cwd = normalizeDirectory(cwd);
}
/**
* Resolves a module based on its name or location.
* @param {string} specifier Either an npm package name or
* relative file path.
* @returns {string|undefined} The location of the import.
* @throws {Error} If specifier cannot be located.
*/
resolve(specifier) {
const require = createRequire(this.cwd);
return require.resolve(specifier);
}
/**
* Imports a module based on its name or location.
* @param {string} specifier Either an npm package name or
* relative file path.
* @returns {Promise<object>} The module's object.
*/
import(specifier) {
const location = this.resolve(specifier);
return import(pathToFileURL(location).href);
}
}

View file

@ -0,0 +1,22 @@
/**
* @fileoverview Universal module importer
*/
//-----------------------------------------------------------------------------
// Imports
//-----------------------------------------------------------------------------
import { createRequire } from "module";
import { fileURLToPath } from "url";
import { dirname } from "path";
//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const require = createRequire(__dirname + "/");
const { ModuleImporter } = require("./module-importer.cjs");
export { ModuleImporter };

View file

@ -0,0 +1,27 @@
name: Node CI
on: [push, pull_request]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-latest, macOS-latest, ubuntu-latest]
node: [8.x, 10.x, 12.x, 14.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: npm install, build, and test
run: |
npm install
npm run build --if-present
npm test
env:
CI: true

View file

@ -0,0 +1,39 @@
on:
push:
branches:
- main
name: release-please
jobs:
release-please:
runs-on: ubuntu-latest
steps:
- uses: GoogleCloudPlatform/release-please-action@v2
id: release
with:
release-type: node
package-name: test-release-please
# The logic below handles the npm publication:
- uses: actions/checkout@v2
# these if statements ensure that a publication only occurs when
# a new release is created:
if: ${{ steps.release.outputs.release_created }}
- uses: actions/setup-node@v1
with:
node-version: 12
registry-url: 'https://registry.npmjs.org'
if: ${{ steps.release.outputs.release_created }}
- run: npm ci
if: ${{ steps.release.outputs.release_created }}
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
if: ${{ steps.release.outputs.release_created }}
# Tweets out release announcement
- run: 'npx @humanwhocodes/tweet "Object Schema v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }}.${{ steps.release.outputs.patch }} has been released!\n\n${{ github.event.release.html_url }}"'
if: ${{ steps.release.outputs.release_created }}
env:
TWITTER_CONSUMER_KEY: ${{ secrets.TWITTER_CONSUMER_KEY }}
TWITTER_CONSUMER_SECRET: ${{ secrets.TWITTER_CONSUMER_SECRET }}
TWITTER_ACCESS_TOKEN_KEY: ${{ secrets.TWITTER_ACCESS_TOKEN_KEY }}
TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }}

View file

@ -1,14 +0,0 @@
language: node_js
node_js:
- "8"
- "9"
- "10"
- "11"
sudo: false
branches:
only:
- master
# Run npm test always
script:
- "npm test"

View file

@ -0,0 +1,8 @@
# Changelog
### [1.2.1](https://www.github.com/humanwhocodes/object-schema/compare/v1.2.0...v1.2.1) (2021-11-02)
### Bug Fixes
* Never return original object from individual config ([5463c5c](https://www.github.com/humanwhocodes/object-schema/commit/5463c5c6d2cb35a7b7948dffc37c899a41d1775f))

View file

@ -1,6 +1,6 @@
{
"name": "@humanwhocodes/object-schema",
"version": "1.2.0",
"version": "1.2.1",
"description": "An object schema merger/validator",
"main": "src/index.js",
"directories": {
@ -30,4 +30,4 @@
"eslint": "^5.13.0",
"mocha": "^5.2.0"
}
}
}

View file

@ -104,12 +104,8 @@ class ObjectSchema {
const schema = new ObjectSchema(definitions[key].schema);
definitions[key] = {
...definitions[key],
merge(first, second) {
if (first && second) {
return schema.merge(first, second);
}
return MergeStrategy.assign(first, second);
merge(first = {}, second = {}) {
return schema.merge(first, second);
},
validate(value) {
ValidationStrategy.object(value);

View file

@ -266,6 +266,53 @@ describe("ObjectSchema", () => {
assert.strictEqual(result.name.last, "z");
});
it("should return separate objects when using subschema", () => {
schema = new ObjectSchema({
age: {
merge: "replace",
validate: "number"
},
address: {
schema: {
street: {
schema: {
number: {
merge: "replace",
validate: "number"
},
streetName: {
merge: "replace",
validate: "string"
}
}
},
state: {
merge: "replace",
validate: "string"
}
}
}
});
const baseObject = {
address: {
street: {
number: 100,
streetName: "Foo St"
},
state: "HA"
}
};
const result = schema.merge(baseObject, {
age: 29
});
assert.notStrictEqual(result.address.street, baseObject.address.street);
assert.deepStrictEqual(result.address, baseObject.address);
});
it("should not error when calling the merge strategy when there's a subschema and no matching key in second object", () => {
schema = new ObjectSchema({
@ -295,6 +342,42 @@ describe("ObjectSchema", () => {
assert.strictEqual(result.name.last, "z");
});
it("should not error when calling the merge strategy when there's multiple subschemas and no matching key in second object", () => {
schema = new ObjectSchema({
user: {
schema: {
name: {
schema: {
first: {
merge: "replace",
validate: "string"
},
last: {
merge: "replace",
validate: "string"
}
}
}
}
}
});
const result = schema.merge({
user: {
name: {
first: "n",
last: "z"
}
}
}, {
});
assert.strictEqual(result.user.name.first, "n");
assert.strictEqual(result.user.name.last, "z");
});
});