knip 5.61.2 → 5.61.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { isBuiltin } from 'node:module';
2
- import { PackageJsonPeeker } from './PackageJsonPeeker.js';
2
+ import { PackagePeeker } from './PackagePeeker.js';
3
3
  import { DT_SCOPE, IGNORED_DEPENDENCIES, IGNORED_GLOBAL_BINARIES, IGNORED_RUNTIME_DEPENDENCIES, IGNORE_DEFINITELY_TYPED, ROOT_WORKSPACE_NAME, } from './constants.js';
4
4
  import { getDependencyMetaData } from './manifest/index.js';
5
5
  import { getDefinitelyTypedFor, getPackageFromDefinitelyTyped, getPackageNameFromModuleSpecifier, isDefinitelyTyped, } from './util/modules.js';
@@ -176,12 +176,12 @@ export class DependencyDeputy {
176
176
  for (const [workspace, { manifestPath: filePath, manifestStr }] of this._manifests.entries()) {
177
177
  const referencedDependencies = this.referencedDependencies.get(workspace);
178
178
  const hasTypesIncluded = this.getHasTypesIncluded(workspace);
179
- const peeker = new PackageJsonPeeker(manifestStr);
180
- const peerDepRecs = {};
179
+ const peeker = new PackagePeeker(manifestStr);
180
+ const peerDepCount = {};
181
181
  const isReferencedDependency = (dependency, isPeerDep) => {
182
182
  if (referencedDependencies?.has(dependency))
183
183
  return true;
184
- if (isPeerDep && peerDepRecs[dependency])
184
+ if (isPeerDep && peerDepCount[dependency])
185
185
  return false;
186
186
  const [scope, typedDependency] = dependency.split('/');
187
187
  if (scope === DT_SCOPE) {
@@ -202,10 +202,10 @@ export class DependencyDeputy {
202
202
  }
203
203
  const hostDependencies = this.getHostDependenciesFor(workspace, dependency);
204
204
  for (const { name } of hostDependencies) {
205
- if (!peerDepRecs[name])
206
- peerDepRecs[name] = 1;
205
+ if (!peerDepCount[name])
206
+ peerDepCount[name] = 1;
207
207
  else
208
- peerDepRecs[name]++;
208
+ peerDepCount[name]++;
209
209
  }
210
210
  return hostDependencies.some(hostDependency => (isPeerDep === false || !hostDependency.isPeerOptional) && isReferencedDependency(hostDependency.name, true));
211
211
  };
@@ -1,4 +1,4 @@
1
- export declare class PackageJsonPeeker {
1
+ export declare class PackagePeeker {
2
2
  private manifestStr;
3
3
  private lines;
4
4
  private sections;
@@ -1,4 +1,4 @@
1
- export class PackageJsonPeeker {
1
+ export class PackagePeeker {
2
2
  manifestStr;
3
3
  lines = [];
4
4
  sections = {};
@@ -50,7 +50,7 @@ export declare class ProjectPrincipal {
50
50
  getUsedResolvedFiles(): string[];
51
51
  private getProgramSourceFiles;
52
52
  getUnreferencedFiles(): string[];
53
- analyzeSourceFile(filePath: string, options: Omit<GetImportsAndExportsOptions, 'skipExports'>, isGitIgnored: (filePath: string) => boolean, isInternalWorkspace: (packageName: string) => boolean, getPrincipalByFilePath: (filePath: string) => undefined | ProjectPrincipal): FileNode;
53
+ analyzeSourceFile(filePath: string, options: Omit<GetImportsAndExportsOptions, 'skipExports'>): FileNode;
54
54
  invalidateFile(filePath: string): void;
55
55
  findUnusedMembers(filePath: string, members: ExportMember[]): ExportMember[];
56
56
  hasExternalReferences(filePath: string, exportedItem: Export): boolean;
@@ -1,14 +1,13 @@
1
1
  import ts from 'typescript';
2
2
  import { CacheConsultant } from './CacheConsultant.js';
3
3
  import { getCompilerExtensions } from './compilers/index.js';
4
- import { ANONYMOUS, DEFAULT_EXTENSIONS, FOREIGN_FILE_EXTENSIONS, PUBLIC_TAG } from './constants.js';
4
+ import { ANONYMOUS, DEFAULT_EXTENSIONS, PUBLIC_TAG } from './constants.js';
5
5
  import { SourceFileManager } from './typescript/SourceFileManager.js';
6
6
  import { createHosts } from './typescript/create-hosts.js';
7
7
  import { _getImportsAndExports } from './typescript/get-imports-and-exports.js';
8
8
  import { timerify } from './util/Performance.js';
9
9
  import { compact } from './util/array.js';
10
- import { getPackageNameFromModuleSpecifier, isStartsLikePackageName, sanitizeSpecifier } from './util/modules.js';
11
- import { dirname, extname, isInNodeModules, join, toAbsolute } from './util/path.js';
10
+ import { extname, isInNodeModules, toAbsolute } from './util/path.js';
12
11
  const baseCompilerOptions = {
13
12
  allowJs: true,
14
13
  allowSyntheticDefaultImports: true,
@@ -156,7 +155,7 @@ export class ProjectPrincipal {
156
155
  const sourceFiles = this.getProgramSourceFiles();
157
156
  return Array.from(this.projectPaths).filter(filePath => !sourceFiles.has(filePath));
158
157
  }
159
- analyzeSourceFile(filePath, options, isGitIgnored, isInternalWorkspace, getPrincipalByFilePath) {
158
+ analyzeSourceFile(filePath, options) {
160
159
  const fd = this.cache.getFileDescriptor(filePath);
161
160
  if (!fd.changed && fd.meta?.data)
162
161
  return fd.meta.data;
@@ -168,43 +167,7 @@ export class ProjectPrincipal {
168
167
  throw new Error(`Unable to find ${filePath}`);
169
168
  const skipExports = this.skipExportsAnalysis.has(filePath);
170
169
  const resolve = (specifier) => this.backend.resolveModuleNames([specifier], sourceFile.fileName)[0];
171
- const { imports, ...rest } = _getImportsAndExports(sourceFile, resolve, typeChecker, { ...options, skipExports });
172
- const { internal, resolved, specifiers, unresolved, external } = imports;
173
- const unresolvedImports = new Set();
174
- for (const [specifier, specifierFilePath] of specifiers) {
175
- const packageName = getPackageNameFromModuleSpecifier(specifier);
176
- if (packageName && isInternalWorkspace(packageName)) {
177
- external.add(packageName);
178
- const principal = getPrincipalByFilePath(specifierFilePath);
179
- if (principal && !isGitIgnored(specifierFilePath))
180
- principal.addNonEntryPath(specifierFilePath);
181
- }
182
- }
183
- for (const filePath of resolved) {
184
- const isIgnored = isGitIgnored(filePath);
185
- if (!isIgnored)
186
- this.addEntryPath(filePath, { skipExportsAnalysis: true });
187
- }
188
- for (const unresolvedImport of unresolved) {
189
- const { specifier } = unresolvedImport;
190
- if (specifier.startsWith('http'))
191
- continue;
192
- const sanitizedSpecifier = sanitizeSpecifier(specifier);
193
- if (isStartsLikePackageName(sanitizedSpecifier)) {
194
- external.add(sanitizedSpecifier);
195
- }
196
- else {
197
- const isIgnored = isGitIgnored(join(dirname(filePath), sanitizedSpecifier));
198
- if (!isIgnored) {
199
- const ext = extname(sanitizedSpecifier);
200
- const hasIgnoredExtension = FOREIGN_FILE_EXTENSIONS.has(ext);
201
- if (!ext || (ext !== '.json' && !hasIgnoredExtension)) {
202
- unresolvedImports.add(unresolvedImport);
203
- }
204
- }
205
- }
206
- }
207
- return { imports: { internal, unresolved: unresolvedImports, external }, ...rest };
170
+ return _getImportsAndExports(sourceFile, resolve, typeChecker, { ...options, skipExports });
208
171
  }
209
172
  invalidateFile(filePath) {
210
173
  this.backend.fileManager.snapshotCache.delete(filePath);
@@ -29,6 +29,7 @@ type WorkspaceManagerOptions = {
29
29
  type CacheItem = {
30
30
  resolveConfig?: Input[];
31
31
  resolveFromAST?: Input[];
32
+ configFile?: Input;
32
33
  };
33
34
  export declare class WorkspaceWorker {
34
35
  name: string;
@@ -262,6 +262,8 @@ export class WorkspaceWorker {
262
262
  if (data.resolveFromAST)
263
263
  for (const id of data.resolveFromAST)
264
264
  addInput(id, configFilePath);
265
+ if (data.configFile)
266
+ addInput(data.configFile);
265
267
  continue;
266
268
  }
267
269
  const resolveOpts = {
@@ -301,15 +303,17 @@ export class WorkspaceWorker {
301
303
  cache.resolveFromAST = inputs;
302
304
  }
303
305
  }
304
- if (basename(configFilePath) !== 'package.json') {
306
+ if (!isManifest) {
305
307
  addInput(toEntry(configFilePath));
306
308
  addInput(toConfig(pluginName, configFilePath));
309
+ cache.configFile = toEntry(configFilePath);
310
+ if (fd?.changed && fd.meta && !seen.get(key)?.has(configFilePath)) {
311
+ fd.meta.data = cache;
312
+ }
307
313
  if (!seen.has(key))
308
314
  seen.set(key, new Set());
309
315
  seen.get(key)?.add(configFilePath);
310
316
  }
311
- if (!isManifest && fd?.changed && fd.meta)
312
- fd.meta.data = cache;
313
317
  }
314
318
  if (plugin.resolve) {
315
319
  const dependencies = (await plugin.resolve(options)) ?? [];
@@ -1,15 +1,16 @@
1
1
  import { WorkspaceWorker } from '../WorkspaceWorker.js';
2
2
  import { _getInputsFromScripts } from '../binaries/index.js';
3
3
  import { getCompilerExtensions, getIncludedCompilers } from '../compilers/index.js';
4
- import { DEFAULT_EXTENSIONS } from '../constants.js';
4
+ import { DEFAULT_EXTENSIONS, FOREIGN_FILE_EXTENSIONS } from '../constants.js';
5
5
  import { perfObserver } from '../util/Performance.js';
6
6
  import { debugLog, debugLogArray } from '../util/debug.js';
7
7
  import { getReferencedInputsHandler } from '../util/get-referenced-inputs.js';
8
8
  import { _glob, negate } from '../util/glob.js';
9
9
  import { isAlias, isConfig, isDeferResolveEntry, isDeferResolveProductionEntry, isEntry, isIgnore, isProductionEntry, isProject, toProductionEntry, } from '../util/input.js';
10
10
  import { getOrCreateFileNode, updateImportMap } from '../util/module-graph.js';
11
+ import { getPackageNameFromModuleSpecifier, isStartsLikePackageName, sanitizeSpecifier } from '../util/modules.js';
11
12
  import { getEntryPathsFromManifest } from '../util/package-json.js';
12
- import { dirname, isAbsolute, join, relative, toRelative } from '../util/path.js';
13
+ import { dirname, extname, isAbsolute, join, relative, toRelative } from '../util/path.js';
13
14
  import { augmentWorkspace, getToSourcePathHandler, getToSourcePathsHandler } from '../util/to-source-path.js';
14
15
  import { loadTSConfig } from '../util/tsconfig-loader.js';
15
16
  export async function build({ cacheLocation, chief, collector, cwd, deputy, factory, gitignore, isCache, isFixExports, isFixTypes, isGitIgnored, isIsolateWorkspaces, isProduction, isSkipLibs, isStrict, isWatch, report, streamer, tags, tsConfigFile, workspaces, }) {
@@ -250,37 +251,68 @@ export async function build({ cacheLocation, chief, collector, cwd, deputy, fact
250
251
  analyzedFiles.add(filePath);
251
252
  const workspace = chief.findWorkspaceByFilePath(filePath);
252
253
  if (workspace) {
253
- const { imports, exports, duplicates, scripts, traceRefs } = principal.analyzeSourceFile(filePath, {
254
+ const file = principal.analyzeSourceFile(filePath, {
254
255
  skipTypeOnly: isStrict,
255
256
  isFixExports,
256
257
  isFixTypes,
257
258
  ignoreExportsUsedInFile: chief.config.ignoreExportsUsedInFile,
258
259
  isReportClassMembers,
259
260
  tags,
260
- }, isGitIgnored, isInternalWorkspace, getPrincipalByFilePath);
261
- const node = getOrCreateFileNode(graph, filePath);
262
- node.imports = imports;
263
- node.exports = exports;
264
- node.duplicates = duplicates;
265
- node.scripts = scripts;
266
- node.traceRefs = traceRefs;
267
- updateImportMap(node, imports.internal, graph);
268
- node.internalImportCache = imports.internal;
269
- graph.set(filePath, node);
270
- if (scripts && scripts.size > 0) {
261
+ });
262
+ const _unresolved = new Set();
263
+ for (const unresolvedImport of file.imports.unresolved) {
264
+ const { specifier } = unresolvedImport;
265
+ if (specifier.startsWith('http'))
266
+ continue;
267
+ const sanitizedSpecifier = sanitizeSpecifier(specifier);
268
+ if (isStartsLikePackageName(sanitizedSpecifier)) {
269
+ file.imports.external.add(sanitizedSpecifier);
270
+ }
271
+ else {
272
+ const isIgnored = isGitIgnored(join(dirname(filePath), sanitizedSpecifier));
273
+ if (!isIgnored) {
274
+ const ext = extname(sanitizedSpecifier);
275
+ const hasIgnoredExtension = FOREIGN_FILE_EXTENSIONS.has(ext);
276
+ if (!ext || (ext !== '.json' && !hasIgnoredExtension))
277
+ _unresolved.add(unresolvedImport);
278
+ }
279
+ }
280
+ }
281
+ for (const filePath of file.imports.resolved) {
282
+ const isIgnored = isGitIgnored(filePath);
283
+ if (!isIgnored)
284
+ principal.addEntryPath(filePath, { skipExportsAnalysis: true });
285
+ }
286
+ for (const [specifier, specifierFilePath] of file.imports.specifiers) {
287
+ const packageName = getPackageNameFromModuleSpecifier(specifier);
288
+ if (packageName && isInternalWorkspace(packageName)) {
289
+ file.imports.external.add(packageName);
290
+ const principal = getPrincipalByFilePath(specifierFilePath);
291
+ if (principal && !isGitIgnored(specifierFilePath)) {
292
+ principal.addNonEntryPath(specifierFilePath);
293
+ }
294
+ }
295
+ }
296
+ if (file.scripts && file.scripts.size > 0) {
271
297
  const dependencies = deputy.getDependencies(workspace.name);
272
298
  const manifestScriptNames = new Set(Object.keys(chief.getManifestForWorkspace(workspace.name)?.scripts ?? {}));
273
299
  const dir = dirname(filePath);
274
300
  const options = { cwd: dir, rootCwd: cwd, containingFilePath: filePath, dependencies, manifestScriptNames };
275
- const inputs = _getInputsFromScripts(scripts, options);
301
+ const inputs = _getInputsFromScripts(file.scripts, options);
276
302
  for (const input of inputs) {
277
303
  input.containingFilePath ??= filePath;
278
304
  input.dir ??= dir;
279
305
  const specifierFilePath = getReferencedInternalFilePath(input, workspace);
280
306
  if (specifierFilePath)
281
- analyzeSourceFile(specifierFilePath, principal);
307
+ principal.addEntryPath(specifierFilePath, { skipExportsAnalysis: true });
282
308
  }
283
309
  }
310
+ const node = getOrCreateFileNode(graph, filePath);
311
+ file.imports.unresolved = _unresolved;
312
+ Object.assign(node, file);
313
+ updateImportMap(node, file.imports.internal, graph);
314
+ node.internalImportCache = file.imports.internal;
315
+ graph.set(filePath, node);
284
316
  }
285
317
  };
286
318
  for (let i = 0; i < principals.length; ++i) {
@@ -1,5 +1,5 @@
1
1
  import { toEntry } from '../../util/input.js';
2
- import { join } from '../../util/path.js';
2
+ import { isAbsolute, join } from '../../util/path.js';
3
3
  import { hasDependency } from '../../util/plugin.js';
4
4
  import { configFiles, inputsFromFrameworks, inputsFromPlugins, loadConfig } from './helpers.js';
5
5
  const title = 'Karma';
@@ -19,12 +19,14 @@ const resolveConfig = async (localConfig, options) => {
19
19
  if (config.files) {
20
20
  for (const fileOrPatternObj of config.files) {
21
21
  const fileOrPattern = typeof fileOrPatternObj === 'string' ? fileOrPatternObj : fileOrPatternObj.pattern;
22
- inputs.add(toEntry(join(options.configFileDir, basePath, fileOrPattern)));
22
+ const absPath = isAbsolute(fileOrPattern) ? fileOrPattern : join(options.configFileDir, basePath, fileOrPattern);
23
+ inputs.add(toEntry(absPath));
23
24
  }
24
25
  }
25
26
  if (config.exclude) {
26
27
  for (const fileOrPattern of config.exclude) {
27
- inputs.add(toEntry(`!${join(options.configFileDir, basePath, fileOrPattern)}`));
28
+ const absPath = isAbsolute(fileOrPattern) ? fileOrPattern : join(options.configFileDir, basePath, fileOrPattern);
29
+ inputs.add(toEntry(`!${absPath}`));
28
30
  }
29
31
  }
30
32
  return Array.from(inputs);
@@ -55,6 +55,8 @@ export type FileNode = {
55
55
  internal: ImportMap;
56
56
  external: Set<string>;
57
57
  unresolved: Set<UnresolvedImport>;
58
+ resolved: Set<FilePath>;
59
+ specifiers: Set<[string, FilePath]>;
58
60
  };
59
61
  exports: ExportMap;
60
62
  duplicates: Iterable<Array<IssueSymbol>>;
@@ -1,18 +1,5 @@
1
1
  import ts from 'typescript';
2
2
  import type { GetImportsAndExportsOptions } from '../types/config.js';
3
- import type { IssueSymbol } from '../types/issues.js';
4
- import type { ExportMap, ImportMap, UnresolvedImport } from '../types/module-graph.js';
3
+ import type { FileNode } from '../types/module-graph.js';
5
4
  import type { BoundSourceFile } from './SourceFile.js';
6
- export declare const _getImportsAndExports: (sourceFile: BoundSourceFile, resolveModule: (specifier: string) => ts.ResolvedModuleFull | undefined, typeChecker: ts.TypeChecker, options: GetImportsAndExportsOptions) => {
7
- imports: {
8
- internal: ImportMap;
9
- external: Set<string>;
10
- resolved: Set<string>;
11
- specifiers: Set<[string, string]>;
12
- unresolved: Set<UnresolvedImport>;
13
- };
14
- exports: ExportMap;
15
- duplicates: IssueSymbol[][];
16
- scripts: Set<string>;
17
- traceRefs: Set<string>;
18
- };
5
+ export declare const _getImportsAndExports: (sourceFile: BoundSourceFile, resolveModule: (specifier: string) => ts.ResolvedModuleFull | undefined, typeChecker: ts.TypeChecker, options: GetImportsAndExportsOptions) => FileNode;
@@ -35,6 +35,8 @@ const createFileNode = () => ({
35
35
  internal: new Map(),
36
36
  external: new Set(),
37
37
  unresolved: new Set(),
38
+ resolved: new Set(),
39
+ specifiers: new Set(),
38
40
  },
39
41
  exports: new Map(),
40
42
  duplicates: new Set(),
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "5.61.2";
1
+ export declare const version = "5.61.3";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = '5.61.2';
1
+ export const version = '5.61.3';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knip",
3
- "version": "5.61.2",
3
+ "version": "5.61.3",
4
4
  "description": "Find and fix unused dependencies, exports and files in your TypeScript and JavaScript projects",
5
5
  "homepage": "https://knip.dev",
6
6
  "repository": {