eslint-module-utils
Advanced tools
+13
-0
@@ -8,2 +8,13 @@ # Change Log | ||
| ## v2.8.2 - 2024-08-25 | ||
| ### Fixed | ||
| - `parse`: also delete `parserOptions.projectService` ([#3039], thanks [@Mysak0CZ]) | ||
| ### Changed | ||
| - [types] use shared config (thanks [@ljharb]) | ||
| - [meta] add `exports`, `main` | ||
| - [meta] add `repository.directory` field | ||
| - [refactor] avoid hoisting | ||
| ## v2.8.1 - 2024-02-26 | ||
@@ -143,2 +154,3 @@ | ||
| [#3039]: https://github.com/import-js/eslint-plugin-import/pull/3039 | ||
| [#2963]: https://github.com/import-js/eslint-plugin-import/pull/2963 | ||
@@ -190,2 +202,3 @@ [#2755]: https://github.com/import-js/eslint-plugin-import/pull/2755 | ||
| [@mgwalker]: https://github.com/mgwalker | ||
| [@Mysak0CZ]: https://github.com/Mysak0CZ | ||
| [@nicolo-ribaudo]: https://github.com/nicolo-ribaudo | ||
@@ -192,0 +205,0 @@ [@pmcelhaney]: https://github.com/pmcelhaney |
+18
-18
@@ -13,13 +13,2 @@ 'use strict'; | ||
| /** @type {(context: import('eslint').Rule.RuleContext) => Set<import('./types').Extension>} */ | ||
| function validExtensions(context) { | ||
| if (cachedSet && context.settings === lastSettings) { | ||
| return cachedSet; | ||
| } | ||
| lastSettings = context.settings; | ||
| cachedSet = makeValidExtensionSet(context.settings); | ||
| return cachedSet; | ||
| } | ||
| /** @type {import('./ignore').getFileExtensions} */ | ||
@@ -46,2 +35,20 @@ function makeValidExtensionSet(settings) { | ||
| /** @type {(context: import('eslint').Rule.RuleContext) => Set<import('./types').Extension>} */ | ||
| function validExtensions(context) { | ||
| if (cachedSet && context.settings === lastSettings) { | ||
| return cachedSet; | ||
| } | ||
| lastSettings = context.settings; | ||
| cachedSet = makeValidExtensionSet(context.settings); | ||
| return cachedSet; | ||
| } | ||
| /** @type {import('./ignore').hasValidExtension} */ | ||
| function hasValidExtension(path, context) { | ||
| // eslint-disable-next-line no-extra-parens | ||
| return validExtensions(context).has(/** @type {import('./types').Extension} */ (extname(path))); | ||
| } | ||
| exports.hasValidExtension = hasValidExtension; | ||
| /** @type {import('./ignore').default} */ | ||
@@ -65,8 +72,1 @@ exports.default = function ignore(path, context) { | ||
| }; | ||
| /** @type {import('./ignore').hasValidExtension} */ | ||
| function hasValidExtension(path, context) { | ||
| // eslint-disable-next-line no-extra-parens | ||
| return validExtensions(context).has(/** @type {import('./types').Extension} */ (extname(path))); | ||
| } | ||
| exports.hasValidExtension = hasValidExtension; |
+36
-2
| { | ||
| "name": "eslint-module-utils", | ||
| "version": "2.8.1", | ||
| "version": "2.8.2", | ||
| "description": "Core utilities to support eslint-plugin-import and other module-related plugins.", | ||
@@ -8,5 +8,36 @@ "engines": { | ||
| }, | ||
| "main": false, | ||
| "exports": { | ||
| "./ModuleCache": "./ModuleCache.js", | ||
| "./ModuleCache.js": "./ModuleCache.js", | ||
| "./declaredScope": "./declaredScope.js", | ||
| "./declaredScope.js": "./declaredScope.js", | ||
| "./hash": "./hash.js", | ||
| "./hash.js": "./hash.js", | ||
| "./ignore": "./ignore.js", | ||
| "./ignore.js": "./ignore.js", | ||
| "./module-require": "./module-require.js", | ||
| "./module-require.js": "./module-require.js", | ||
| "./moduleVisitor": "./moduleVisitor.js", | ||
| "./moduleVisitor.js": "./moduleVisitor.js", | ||
| "./parse": "./parse.js", | ||
| "./parse.js": "./parse.js", | ||
| "./pkgDir": "./pkgDir.js", | ||
| "./pkgDir.js": "./pkgDir.js", | ||
| "./pkgUp": "./pkgUp.js", | ||
| "./pkgUp.js": "./pkgUp.js", | ||
| "./readPkgUp": "./readPkgUp.js", | ||
| "./readPkgUp.js": "./readPkgUp.js", | ||
| "./resolve": "./resolve.js", | ||
| "./resolve.js": "./resolve.js", | ||
| "./unambiguous": "./unambiguous.js", | ||
| "./unambiguous.js": "./unambiguous.js", | ||
| "./visit": "./visit.js", | ||
| "./visit.js": "./visit.js", | ||
| "./package.json": "./package.json" | ||
| }, | ||
| "scripts": { | ||
| "prepublishOnly": "cp ../{LICENSE,.npmrc} ./", | ||
| "tsc": "tsc -p .", | ||
| "posttsc": "attw -P .", | ||
| "test": "echo \"Error: no test specified\" && exit 1" | ||
@@ -16,3 +47,4 @@ }, | ||
| "type": "git", | ||
| "url": "git+https://github.com/import-js/eslint-plugin-import.git" | ||
| "url": "git+https://github.com/import-js/eslint-plugin-import.git", | ||
| "directory": "utils" | ||
| }, | ||
@@ -35,2 +67,4 @@ "keywords": [ | ||
| "devDependencies": { | ||
| "@arethetypeswrong/cli": "^0.15.4", | ||
| "@ljharb/tsconfig": "^0.2.0", | ||
| "@types/debug": "^4.1.12", | ||
@@ -37,0 +71,0 @@ "@types/eslint": "^8.56.3", |
+42
-41
@@ -64,2 +64,43 @@ 'use strict'; | ||
| /** @type {(path: string, context: import('eslint').Rule.RuleContext & { settings?: ESLintSettings }) => import('eslint').Rule.RuleContext['parserPath']} */ | ||
| function getParserPath(path, context) { | ||
| const parsers = context.settings['import/parsers']; | ||
| if (parsers != null) { | ||
| // eslint-disable-next-line no-extra-parens | ||
| const extension = /** @type {Extension} */ (extname(path)); | ||
| for (const parserPath in parsers) { | ||
| if (parsers[parserPath].indexOf(extension) > -1) { | ||
| // use this alternate parser | ||
| log('using alt parser:', parserPath); | ||
| return parserPath; | ||
| } | ||
| } | ||
| } | ||
| // default to use ESLint parser | ||
| return context.parserPath; | ||
| } | ||
| /** @type {(path: string, context: import('eslint').Rule.RuleContext) => string | null | (import('eslint').Linter.ParserModule)} */ | ||
| function getParser(path, context) { | ||
| const parserPath = getParserPath(path, context); | ||
| if (parserPath) { | ||
| return parserPath; | ||
| } | ||
| if ( | ||
| !!context.languageOptions | ||
| && !!context.languageOptions.parser | ||
| && typeof context.languageOptions.parser !== 'string' | ||
| && ( | ||
| // @ts-expect-error TODO: figure out a better type | ||
| typeof context.languageOptions.parser.parse === 'function' | ||
| // @ts-expect-error TODO: figure out a better type | ||
| || typeof context.languageOptions.parser.parseForESLint === 'function' | ||
| ) | ||
| ) { | ||
| return context.languageOptions.parser; | ||
| } | ||
| return null; | ||
| } | ||
| /** @type {import('./parse').default} */ | ||
@@ -97,2 +138,3 @@ exports.default = function parse(path, content, context) { | ||
| delete parserOptions.EXPERIMENTAL_useProjectService; | ||
| delete parserOptions.projectService; | ||
| delete parserOptions.project; | ||
@@ -136,42 +178,1 @@ delete parserOptions.projects; | ||
| }; | ||
| /** @type {(path: string, context: import('eslint').Rule.RuleContext) => string | null | (import('eslint').Linter.ParserModule)} */ | ||
| function getParser(path, context) { | ||
| const parserPath = getParserPath(path, context); | ||
| if (parserPath) { | ||
| return parserPath; | ||
| } | ||
| if ( | ||
| !!context.languageOptions | ||
| && !!context.languageOptions.parser | ||
| && typeof context.languageOptions.parser !== 'string' | ||
| && ( | ||
| // @ts-expect-error TODO: figure out a better type | ||
| typeof context.languageOptions.parser.parse === 'function' | ||
| // @ts-expect-error TODO: figure out a better type | ||
| || typeof context.languageOptions.parser.parseForESLint === 'function' | ||
| ) | ||
| ) { | ||
| return context.languageOptions.parser; | ||
| } | ||
| return null; | ||
| } | ||
| /** @type {(path: string, context: import('eslint').Rule.RuleContext & { settings?: ESLintSettings }) => import('eslint').Rule.RuleContext['parserPath']} */ | ||
| function getParserPath(path, context) { | ||
| const parsers = context.settings['import/parsers']; | ||
| if (parsers != null) { | ||
| // eslint-disable-next-line no-extra-parens | ||
| const extension = /** @type {Extension} */ (extname(path)); | ||
| for (const parserPath in parsers) { | ||
| if (parsers[parserPath].indexOf(extension) > -1) { | ||
| // use this alternate parser | ||
| log('using alt parser:', parserPath); | ||
| return parserPath; | ||
| } | ||
| } | ||
| } | ||
| // default to use ESLint parser | ||
| return context.parserPath; | ||
| } |
+58
-58
@@ -37,2 +37,10 @@ 'use strict'; | ||
| /** @type {(resolver: object) => resolver is import('./resolve').Resolver} */ | ||
| function isResolverValid(resolver) { | ||
| if ('interfaceVersion' in resolver && resolver.interfaceVersion === 2) { | ||
| return 'resolve' in resolver && !!resolver.resolve && typeof resolver.resolve === 'function'; | ||
| } | ||
| return 'resolveImport' in resolver && !!resolver.resolveImport && typeof resolver.resolveImport === 'function'; | ||
| } | ||
| /** @type {<T extends string>(target: T, sourceFile?: string | null | undefined) => undefined | ReturnType<typeof require>} */ | ||
@@ -61,2 +69,52 @@ function tryRequire(target, sourceFile) { | ||
| /** @type {<T extends Map<string, unknown>>(resolvers: string[] | string | { [k: string]: string }, map: T) => T} */ | ||
| function resolverReducer(resolvers, map) { | ||
| if (Array.isArray(resolvers)) { | ||
| resolvers.forEach((r) => resolverReducer(r, map)); | ||
| return map; | ||
| } | ||
| if (typeof resolvers === 'string') { | ||
| map.set(resolvers, null); | ||
| return map; | ||
| } | ||
| if (typeof resolvers === 'object') { | ||
| for (const key in resolvers) { | ||
| map.set(key, resolvers[key]); | ||
| } | ||
| return map; | ||
| } | ||
| const err = new Error('invalid resolver config'); | ||
| err.name = ERROR_NAME; | ||
| throw err; | ||
| } | ||
| /** @type {(sourceFile: string) => string} */ | ||
| function getBaseDir(sourceFile) { | ||
| return pkgDir(sourceFile) || process.cwd(); | ||
| } | ||
| /** @type {(name: string, sourceFile: string) => import('./resolve').Resolver} */ | ||
| function requireResolver(name, sourceFile) { | ||
| // Try to resolve package with conventional name | ||
| const resolver = tryRequire(`eslint-import-resolver-${name}`, sourceFile) | ||
| || tryRequire(name, sourceFile) | ||
| || tryRequire(path.resolve(getBaseDir(sourceFile), name)); | ||
| if (!resolver) { | ||
| const err = new Error(`unable to load resolver "${name}".`); | ||
| err.name = ERROR_NAME; | ||
| throw err; | ||
| } | ||
| if (!isResolverValid(resolver)) { | ||
| const err = new Error(`${name} with invalid interface loaded as resolver`); | ||
| err.name = ERROR_NAME; | ||
| throw err; | ||
| } | ||
| return resolver; | ||
| } | ||
| // https://stackoverflow.com/a/27382838 | ||
@@ -164,60 +222,2 @@ /** @type {import('./resolve').fileExistsWithCaseSync} */ | ||
| /** @type {<T extends Map<string, unknown>>(resolvers: string[] | string | { [k: string]: string }, map: T) => T} */ | ||
| function resolverReducer(resolvers, map) { | ||
| if (Array.isArray(resolvers)) { | ||
| resolvers.forEach((r) => resolverReducer(r, map)); | ||
| return map; | ||
| } | ||
| if (typeof resolvers === 'string') { | ||
| map.set(resolvers, null); | ||
| return map; | ||
| } | ||
| if (typeof resolvers === 'object') { | ||
| for (const key in resolvers) { | ||
| map.set(key, resolvers[key]); | ||
| } | ||
| return map; | ||
| } | ||
| const err = new Error('invalid resolver config'); | ||
| err.name = ERROR_NAME; | ||
| throw err; | ||
| } | ||
| /** @type {(sourceFile: string) => string} */ | ||
| function getBaseDir(sourceFile) { | ||
| return pkgDir(sourceFile) || process.cwd(); | ||
| } | ||
| /** @type {(name: string, sourceFile: string) => import('./resolve').Resolver} */ | ||
| function requireResolver(name, sourceFile) { | ||
| // Try to resolve package with conventional name | ||
| const resolver = tryRequire(`eslint-import-resolver-${name}`, sourceFile) | ||
| || tryRequire(name, sourceFile) | ||
| || tryRequire(path.resolve(getBaseDir(sourceFile), name)); | ||
| if (!resolver) { | ||
| const err = new Error(`unable to load resolver "${name}".`); | ||
| err.name = ERROR_NAME; | ||
| throw err; | ||
| } | ||
| if (!isResolverValid(resolver)) { | ||
| const err = new Error(`${name} with invalid interface loaded as resolver`); | ||
| err.name = ERROR_NAME; | ||
| throw err; | ||
| } | ||
| return resolver; | ||
| } | ||
| /** @type {(resolver: object) => resolver is import('./resolve').Resolver} */ | ||
| function isResolverValid(resolver) { | ||
| if ('interfaceVersion' in resolver && resolver.interfaceVersion === 2) { | ||
| return 'resolve' in resolver && !!resolver.resolve && typeof resolver.resolve === 'function'; | ||
| } | ||
| return 'resolveImport' in resolver && !!resolver.resolveImport && typeof resolver.resolveImport === 'function'; | ||
| } | ||
| /** @type {Set<import('eslint').Rule.RuleContext>} */ | ||
@@ -224,0 +224,0 @@ const erroredContexts = new Set(); |
+9
-47
| { | ||
| "compilerOptions": { | ||
| /* Visit https://aka.ms/tsconfig to read more about this file */ | ||
| /* Projects */ | ||
| /* Language and Environment */ | ||
| "target": "ES2017", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ | ||
| // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ | ||
| // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ | ||
| "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ | ||
| // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ | ||
| /* Modules */ | ||
| "module": "commonjs", /* Specify what module code is generated. */ | ||
| "rootDir": "./", /* Specify the root folder within your source files. */ | ||
| "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ | ||
| // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ | ||
| // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ | ||
| // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ | ||
| // "typeRoots": ["types"], /* Specify multiple folders that act like './node_modules/@types'. */ | ||
| "resolveJsonModule": true, /* Enable importing .json files. */ | ||
| // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ | ||
| /* JavaScript Support */ | ||
| "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ | ||
| "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ | ||
| "maxNodeModuleJsDepth": 0, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ | ||
| /* Emit */ | ||
| "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ | ||
| "declarationMap": true, /* Create sourcemaps for d.ts files. */ | ||
| "noEmit": true, /* Disable emitting files from a compilation. */ | ||
| /* Interop Constraints */ | ||
| "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ | ||
| "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ | ||
| "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ | ||
| /* Type Checking */ | ||
| "strict": true, /* Enable all strict type-checking options. */ | ||
| /* Completeness */ | ||
| //"skipLibCheck": true /* Skip type checking all .d.ts files. */ | ||
| }, | ||
| "exclude": [ | ||
| "coverage" | ||
| ] | ||
| "extends": "@ljharb/tsconfig", | ||
| "compilerOptions": { | ||
| "target": "ES2017", | ||
| "moduleResolution": "node", | ||
| "maxNodeModuleJsDepth": 0, | ||
| }, | ||
| "exclude": [ | ||
| "coverage", | ||
| ], | ||
| } |
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
11
-8.33%49264
-3.59%6
50%969
-2.91%