knip 6.14.2 → 6.16.0

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.
Files changed (111) hide show
  1. package/dist/CacheConsultant.d.ts +1 -0
  2. package/dist/CacheConsultant.js +2 -0
  3. package/dist/ConfigurationChief.d.ts +32 -0
  4. package/dist/ConfigurationChief.js +9 -11
  5. package/dist/DependencyDeputy.d.ts +0 -4
  6. package/dist/DependencyDeputy.js +4 -16
  7. package/dist/IssueCollector.d.ts +1 -0
  8. package/dist/IssueCollector.js +10 -20
  9. package/dist/IssueFixer.js +10 -15
  10. package/dist/ProjectPrincipal.d.ts +2 -3
  11. package/dist/ProjectPrincipal.js +13 -21
  12. package/dist/WorkspaceWorker.js +6 -1
  13. package/dist/binaries/fallback.js +1 -1
  14. package/dist/binaries/plugins.js +1 -1
  15. package/dist/binaries/resolvers/bun.js +1 -1
  16. package/dist/binaries/resolvers/bunx.js +1 -1
  17. package/dist/binaries/resolvers/npm.js +1 -1
  18. package/dist/binaries/resolvers/npx.js +1 -1
  19. package/dist/binaries/resolvers/pnpm.js +1 -1
  20. package/dist/binaries/resolvers/pnpx.js +1 -1
  21. package/dist/binaries/resolvers/yarn.js +1 -1
  22. package/dist/binaries/util.d.ts +1 -2
  23. package/dist/binaries/util.js +1 -1
  24. package/dist/cli.js +3 -1
  25. package/dist/compilers/compilers.d.ts +3 -0
  26. package/dist/compilers/compilers.js +9 -13
  27. package/dist/compilers/index.d.ts +52 -0
  28. package/dist/compilers/scss.js +9 -3
  29. package/dist/graph/analyze.js +15 -8
  30. package/dist/graph/build.js +3 -5
  31. package/dist/manifest/index.js +11 -14
  32. package/dist/plugins/_custom-elements/custom-element-visitor.d.ts +7 -0
  33. package/dist/plugins/_custom-elements/custom-element-visitor.js +106 -0
  34. package/dist/plugins/bun/index.js +1 -1
  35. package/dist/plugins/catalyst/index.d.ts +3 -0
  36. package/dist/plugins/catalyst/index.js +16 -0
  37. package/dist/plugins/execa/visitors/execa.js +4 -17
  38. package/dist/plugins/fast/index.d.ts +3 -0
  39. package/dist/plugins/fast/index.js +16 -0
  40. package/dist/plugins/index.d.ts +5 -0
  41. package/dist/plugins/index.js +10 -0
  42. package/dist/plugins/lit/index.d.ts +3 -0
  43. package/dist/plugins/lit/index.js +25 -0
  44. package/dist/plugins/nano-spawn/index.d.ts +3 -0
  45. package/dist/plugins/nano-spawn/index.js +15 -0
  46. package/dist/plugins/nano-spawn/visitors/nano-spawn.d.ts +2 -0
  47. package/dist/plugins/nano-spawn/visitors/nano-spawn.js +12 -0
  48. package/dist/plugins/orval/index.d.ts +3 -0
  49. package/dist/plugins/orval/index.js +16 -0
  50. package/dist/plugins/orval/resolveFromAST.d.ts +2 -0
  51. package/dist/plugins/orval/resolveFromAST.js +11 -0
  52. package/dist/plugins/orval/types.d.ts +9 -0
  53. package/dist/plugins/orval/types.js +1 -0
  54. package/dist/plugins/relay/index.js +1 -1
  55. package/dist/plugins/stencil/index.js +17 -1
  56. package/dist/plugins/sveltejs-package/helpers.js +1 -1
  57. package/dist/plugins/vite/helpers.js +23 -6
  58. package/dist/plugins/webdriver-io/index.js +3 -3
  59. package/dist/plugins/webdriver-io/types.d.ts +5 -1
  60. package/dist/reporters/github-actions.d.ts +1 -1
  61. package/dist/reporters/github-actions.js +19 -1
  62. package/dist/reporters/index.d.ts +1 -1
  63. package/dist/reporters/symbols.js +2 -1
  64. package/dist/reporters/trace.d.ts +3 -1
  65. package/dist/reporters/trace.js +48 -16
  66. package/dist/reporters/util/configuration-hints.d.ts +1 -1
  67. package/dist/reporters/util/configuration-hints.js +3 -2
  68. package/dist/schema/configuration.d.ts +83 -1
  69. package/dist/schema/configuration.js +2 -0
  70. package/dist/schema/plugins.d.ts +25 -0
  71. package/dist/schema/plugins.js +5 -0
  72. package/dist/types/PluginNames.d.ts +2 -2
  73. package/dist/types/PluginNames.js +5 -0
  74. package/dist/types/args.d.ts +1 -1
  75. package/dist/types/config.d.ts +2 -0
  76. package/dist/types/issues.d.ts +1 -0
  77. package/dist/types/module-graph.d.ts +1 -0
  78. package/dist/types/project.d.ts +0 -1
  79. package/dist/typescript/ast-helpers.js +21 -20
  80. package/dist/typescript/ast-nodes.d.ts +1 -0
  81. package/dist/typescript/ast-nodes.js +19 -0
  82. package/dist/typescript/get-imports-and-exports.js +18 -2
  83. package/dist/typescript/resolve-module-names.d.ts +6 -2
  84. package/dist/typescript/resolve-module-names.js +20 -29
  85. package/dist/typescript/visitors/calls.d.ts +3 -2
  86. package/dist/typescript/visitors/calls.js +88 -16
  87. package/dist/typescript/visitors/exports.js +12 -0
  88. package/dist/typescript/visitors/walk.d.ts +7 -0
  89. package/dist/typescript/visitors/walk.js +43 -1
  90. package/dist/util/Performance.d.ts +13 -28
  91. package/dist/util/Performance.js +41 -72
  92. package/dist/util/cli-arguments.d.ts +3 -1
  93. package/dist/util/cli-arguments.js +4 -0
  94. package/dist/util/create-options.d.ts +53 -0
  95. package/dist/util/create-options.js +2 -1
  96. package/dist/util/disk-cache.d.ts +1 -0
  97. package/dist/util/disk-cache.js +8 -0
  98. package/dist/util/gitignore-cache.js +5 -11
  99. package/dist/util/glob-cache.js +2 -8
  100. package/dist/util/glob-core.js +4 -7
  101. package/dist/util/jiti.js +1 -0
  102. package/dist/util/load-tsconfig.js +0 -3
  103. package/dist/util/parse-args.d.ts +14 -0
  104. package/dist/util/parse-args.js +112 -0
  105. package/dist/util/trace.js +1 -1
  106. package/dist/version.d.ts +1 -1
  107. package/dist/version.js +1 -1
  108. package/package.json +3 -6
  109. package/schema.json +73 -43
  110. package/dist/util/math.d.ts +0 -6
  111. package/dist/util/math.js +0 -11
@@ -0,0 +1,15 @@
1
+ import { hasDependency } from '../../util/plugin.js';
2
+ import { createNanoSpawnVisitor } from './visitors/nano-spawn.js';
3
+ const title = 'nano-spawn';
4
+ const enablers = ['nano-spawn'];
5
+ const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
6
+ const registerVisitors = ({ ctx, registerVisitor }) => {
7
+ registerVisitor(createNanoSpawnVisitor(ctx));
8
+ };
9
+ const plugin = {
10
+ title,
11
+ enablers,
12
+ isEnabled,
13
+ registerVisitors,
14
+ };
15
+ export default plugin;
@@ -0,0 +1,2 @@
1
+ import type { PluginVisitorContext, PluginVisitorObject } from '../../../types/config.ts';
2
+ export declare function createNanoSpawnVisitor(ctx: PluginVisitorContext): PluginVisitorObject;
@@ -0,0 +1,12 @@
1
+ import { getSafeScriptFromArgs } from '../../../typescript/ast-nodes.js';
2
+ export function createNanoSpawnVisitor(ctx) {
3
+ return {
4
+ CallExpression(node) {
5
+ if (node.callee.type !== 'Identifier' || node.callee.name !== 'spawn')
6
+ return;
7
+ const script = getSafeScriptFromArgs(node.arguments[0], node.arguments[1]);
8
+ if (script)
9
+ ctx.addScript(script);
10
+ },
11
+ };
12
+ }
@@ -0,0 +1,3 @@
1
+ import type { Plugin } from '../../types/config.ts';
2
+ declare const plugin: Plugin;
3
+ export default plugin;
@@ -0,0 +1,16 @@
1
+ import { toEntry } from '../../util/input.js';
2
+ import { hasDependency } from '../../util/plugin.js';
3
+ import { getInputsFromAST } from './resolveFromAST.js';
4
+ const title = 'orval';
5
+ const enablers = ['orval'];
6
+ const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
7
+ const config = ['orval.config.{js,mjs,ts,mts}'];
8
+ const resolveFromAST = program => [...getInputsFromAST(program)].map(id => toEntry(id));
9
+ const plugin = {
10
+ title,
11
+ enablers,
12
+ isEnabled,
13
+ config,
14
+ resolveFromAST,
15
+ };
16
+ export default plugin;
@@ -0,0 +1,2 @@
1
+ import type { Program } from 'oxc-parser';
2
+ export declare const getInputsFromAST: (program: Program) => Set<string>;
@@ -0,0 +1,11 @@
1
+ import { collectPropertyValues } from '../../typescript/ast-helpers.js';
2
+ const PATH_KEY = 'path';
3
+ const TRANSFORMER_KEY = 'transformer';
4
+ export const getInputsFromAST = (program) => {
5
+ const values = new Set();
6
+ for (const v of collectPropertyValues(program, PATH_KEY))
7
+ values.add(v);
8
+ for (const v of collectPropertyValues(program, TRANSFORMER_KEY))
9
+ values.add(v);
10
+ return values;
11
+ };
@@ -0,0 +1,9 @@
1
+ export type OverrideInput = {
2
+ transformer?: InputTransformer;
3
+ };
4
+ export type MutatorObject = {
5
+ path: string;
6
+ name?: string;
7
+ };
8
+ type InputTransformer = string | ((...args: unknown[]) => unknown);
9
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -1,4 +1,4 @@
1
- import parseArgs from 'minimist';
1
+ import parseArgs from '../../util/parse-args.js';
2
2
  import { toProductionEntry } from '../../util/input.js';
3
3
  import { join } from '../../util/path.js';
4
4
  import { hasDependency } from '../../util/plugin.js';
@@ -1,22 +1,36 @@
1
- import { toConfig, toProductionEntry } from '../../util/input.js';
1
+ import { toConfig, toEntry, toProductionEntry } from '../../util/input.js';
2
2
  import { hasDependency } from '../../util/plugin.js';
3
3
  import { collectPropertyValues } from '../../typescript/ast-helpers.js';
4
+ import { createCustomElementVisitor } from '../_custom-elements/custom-element-visitor.js';
4
5
  const title = 'Stencil';
5
6
  const enablers = ['@stencil/core'];
6
7
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
7
8
  const config = ['stencil.config.{ts,js}'];
8
9
  const production = ['src/**/*.tsx'];
10
+ const entry = ['**/*.spec.{ts,tsx}', '**/*.e2e.{ts,tsx}'];
11
+ const isStencilSpecifier = (specifier) => specifier === '@stencil/core';
12
+ const registerVisitors = ({ ctx, registerVisitor }) => {
13
+ registerVisitor(createCustomElementVisitor(ctx, isStencilSpecifier, { decoratorName: 'Component' }));
14
+ };
9
15
  const resolveFromAST = program => {
10
16
  const inputs = [];
11
17
  const srcDirs = collectPropertyValues(program, 'srcDir');
12
18
  const srcDir = srcDirs.size > 0 ? [...srcDirs][0] : 'src';
13
19
  inputs.push(toProductionEntry(`${srcDir}/**/*.tsx`));
20
+ for (const pattern of entry)
21
+ inputs.push(toEntry(pattern));
14
22
  for (const script of collectPropertyValues(program, 'globalScript')) {
15
23
  inputs.push(toProductionEntry(script));
16
24
  }
17
25
  for (const tsconfig of collectPropertyValues(program, 'tsconfig')) {
18
26
  inputs.push(toConfig('typescript', tsconfig));
19
27
  }
28
+ for (const setup of collectPropertyValues(program, 'setupFilesAfterEnv')) {
29
+ inputs.push(toEntry(setup));
30
+ }
31
+ for (const setup of collectPropertyValues(program, 'setupFiles')) {
32
+ inputs.push(toEntry(setup));
33
+ }
20
34
  return inputs;
21
35
  };
22
36
  const plugin = {
@@ -24,7 +38,9 @@ const plugin = {
24
38
  enablers,
25
39
  isEnabled,
26
40
  config,
41
+ entry,
27
42
  production,
28
43
  resolveFromAST,
44
+ registerVisitors,
29
45
  };
30
46
  export default plugin;
@@ -1,4 +1,4 @@
1
- import parseArgs from 'minimist';
1
+ import parseArgs from '../../util/parse-args.js';
2
2
  import { parse } from 'unbash';
3
3
  const BIN = 'svelte-package';
4
4
  export const DEFAULT_INPUT = 'src/lib';
@@ -1,4 +1,5 @@
1
1
  import { Visitor } from 'oxc-parser';
2
+ import { blockCommentMatcher, lineCommentMatcher, scriptExtractor } from '../../compilers/compilers.js';
2
3
  import { findProperty, getImportMap, getStringValues } from '../../typescript/ast-helpers.js';
3
4
  import { isFile, loadFile } from '../../util/fs.js';
4
5
  import { toProductionEntry } from '../../util/input.js';
@@ -32,15 +33,31 @@ export const getBabelInputs = (program) => {
32
33
  visitor.visit(program);
33
34
  return inputs;
34
35
  };
35
- const moduleScriptPattern = /<script\b(?=[^>]*\btype\s*=\s*["']?module["']?)(?=[^>]*\bsrc\s*=\s*["']?([^"' >]+)["']?)[^>]*>/gi;
36
+ const moduleTypePattern = /\btype\s*=\s*["']?module["']?/i;
37
+ const srcAttrPattern = /\bsrc\s*=\s*["']([^"']+)["']/i;
38
+ const importSpecPattern = /\bimport\b(?:\s*\(\s*|(?:[\w$*,{}\s]*\bfrom\b)?\s*)(['"])([^'"]+)\1/g;
39
+ const isFilePath = (specifier) => specifier.startsWith('/') || specifier.startsWith('./') || specifier.startsWith('../');
36
40
  const normalizeModuleScriptSrc = (value) => value.trim().replace(/^\//, '');
37
41
  const getModuleScriptSources = (html) => {
38
- const matches = html.matchAll(moduleScriptPattern);
39
42
  const sources = [];
40
- for (const match of matches) {
41
- const src = normalizeModuleScriptSrc(match[1]);
42
- if (src)
43
- sources.push(src);
43
+ for (const [, attrs, body] of html.matchAll(scriptExtractor)) {
44
+ if (!moduleTypePattern.test(attrs))
45
+ continue;
46
+ const srcMatch = attrs.match(srcAttrPattern);
47
+ if (srcMatch) {
48
+ const src = normalizeModuleScriptSrc(srcMatch[1]);
49
+ if (src)
50
+ sources.push(src);
51
+ continue;
52
+ }
53
+ if (body) {
54
+ const code = body.replace(blockCommentMatcher, '').replace(lineCommentMatcher, '');
55
+ for (const importMatch of code.matchAll(importSpecPattern)) {
56
+ const specifier = importMatch[2];
57
+ if (isFilePath(specifier))
58
+ sources.push(normalizeModuleScriptSrc(specifier));
59
+ }
60
+ }
44
61
  }
45
62
  return sources;
46
63
  };
@@ -8,11 +8,11 @@ const resolveConfig = async (config) => {
8
8
  const cfg = config?.config;
9
9
  if (!cfg)
10
10
  return [];
11
- const frameworks = cfg?.framework ? [`@wdio/${cfg.framework}-framework`] : [];
12
- const runners = cfg?.runner && cfg.runner !== 'local'
11
+ const frameworks = cfg.framework ? [`@wdio/${cfg.framework}-framework`] : [];
12
+ const runners = cfg.runner && cfg.runner !== 'local'
13
13
  ? [`@wdio/${Array.isArray(cfg.runner) ? cfg.runner[0] : cfg.runner}-runner`]
14
14
  : [];
15
- const reporters = cfg?.reporters
15
+ const reporters = cfg.reporters
16
16
  ? cfg.reporters
17
17
  .flatMap(reporter => {
18
18
  if (typeof reporter === 'string')
@@ -1,3 +1,7 @@
1
1
  export type WebdriverIOConfig = {
2
- config: WebdriverIO.Config;
2
+ config: {
3
+ framework?: string;
4
+ runner?: string;
5
+ reporters?: string[];
6
+ };
3
7
  };
@@ -1,3 +1,3 @@
1
1
  import type { ReporterOptions } from '../types/issues.ts';
2
- declare const _default: ({ report, issues, cwd, configurationHints, isDisableConfigHints, isTreatConfigHintsAsErrors, configFilePath, }: ReporterOptions) => void;
2
+ declare const _default: ({ report, issues, cwd, configurationHints, tagHints, isDisableConfigHints, isDisableTagHints, isTreatConfigHintsAsErrors, isTreatTagHintsAsErrors, configFilePath, }: ReporterOptions) => void;
3
3
  export default _default;
@@ -24,7 +24,7 @@ const createGitHubActionsLogger = () => {
24
24
  notice: (message, options) => formatAnnotation('notice', message, options),
25
25
  };
26
26
  };
27
- export default ({ report, issues, cwd, configurationHints, isDisableConfigHints, isTreatConfigHintsAsErrors, configFilePath, }) => {
27
+ export default ({ report, issues, cwd, configurationHints, tagHints, isDisableConfigHints, isDisableTagHints, isTreatConfigHintsAsErrors, isTreatTagHintsAsErrors, configFilePath, }) => {
28
28
  const core = createGitHubActionsLogger();
29
29
  const reportMultipleGroups = Object.values(report).filter(Boolean).length > 1;
30
30
  for (const [reportType, isReportType] of Object.entries(report)) {
@@ -91,4 +91,22 @@ export default ({ report, issues, cwd, configurationHints, isDisableConfigHints,
91
91
  }
92
92
  }
93
93
  }
94
+ if (!isDisableTagHints && tagHints.size > 0) {
95
+ const TAG_HINTS_TITLE = 'Tag hints';
96
+ core.info(`${TAG_HINTS_TITLE} (${tagHints.size})`);
97
+ const sortedHints = [...tagHints].sort((a, b) => a.filePath.localeCompare(b.filePath));
98
+ for (const hint of sortedHints) {
99
+ const file = relative(cwd, hint.filePath);
100
+ const hintMessage = `Unused tag in ${file}: ${hint.identifier} → ${hint.tagName}`;
101
+ const log = isTreatTagHintsAsErrors ? core.error : core.notice;
102
+ log(hintMessage, {
103
+ file,
104
+ startLine: 1,
105
+ endLine: 1,
106
+ startColumn: 1,
107
+ endColumn: 1,
108
+ title: TAG_HINTS_TITLE,
109
+ });
110
+ }
111
+ }
94
112
  };
@@ -6,6 +6,6 @@ declare const _default: {
6
6
  codeclimate: ({ report, issues, cwd }: import("../types.ts").ReporterOptions) => Promise<void>;
7
7
  json: ({ report, issues, options, cwd }: import("../types.ts").ReporterOptions) => Promise<void>;
8
8
  markdown: ({ report, issues, cwd }: import("../types.ts").ReporterOptions) => void;
9
- 'github-actions': ({ report, issues, cwd, configurationHints, isDisableConfigHints, isTreatConfigHintsAsErrors, configFilePath, }: import("../types.ts").ReporterOptions) => void;
9
+ 'github-actions': ({ report, issues, cwd, configurationHints, tagHints, isDisableConfigHints, isDisableTagHints, isTreatConfigHintsAsErrors, isTreatTagHintsAsErrors, configFilePath, }: import("../types.ts").ReporterOptions) => void;
10
10
  };
11
11
  export default _default;
@@ -29,7 +29,8 @@ export default (options) => {
29
29
  }
30
30
  if (totalIssues === 0 &&
31
31
  isShowProgress &&
32
- (!options.isTreatConfigHintsAsErrors || options.configurationHints.length === 0)) {
32
+ (!options.isTreatConfigHintsAsErrors || options.configurationHints.length === 0) &&
33
+ (!options.isTreatTagHintsAsErrors || options.tagHints.size === 0)) {
33
34
  console.log('✂️ Excellent, Knip found no issues.');
34
35
  }
35
36
  };
@@ -1,4 +1,5 @@
1
1
  import type { GraphExplorer } from '../graph-explorer/explorer.ts';
2
+ import type { Issues } from '../types/issues.ts';
2
3
  import type { ModuleGraph } from '../types/module-graph.ts';
3
4
  import type { MainOptions } from '../util/create-options.ts';
4
5
  import type { WorkspaceFilePathFilter } from '../util/workspace-file-filter.ts';
@@ -7,6 +8,7 @@ interface TraceReporterOptions {
7
8
  explorer: GraphExplorer;
8
9
  options: MainOptions;
9
10
  workspaceFilePathFilter: WorkspaceFilePathFilter;
11
+ issues: Issues;
10
12
  }
11
- declare const _default: ({ graph, explorer, options, workspaceFilePathFilter }: TraceReporterOptions) => void;
13
+ declare const _default: ({ graph, explorer, options, workspaceFilePathFilter, issues }: TraceReporterOptions) => void;
12
14
  export default _default;
@@ -3,7 +3,7 @@ import { toRelative } from '../util/path.js';
3
3
  import { toRegexOrString } from '../util/regex.js';
4
4
  import { Table } from '../util/table.js';
5
5
  import { formatTrace } from '../util/trace.js';
6
- export default ({ graph, explorer, options, workspaceFilePathFilter }) => {
6
+ export default ({ graph, explorer, options, workspaceFilePathFilter, issues }) => {
7
7
  if (options.traceDependency) {
8
8
  const pattern = toRegexOrString(options.traceDependency);
9
9
  const toRel = (path) => toRelative(path, options.cwd);
@@ -23,8 +23,12 @@ export default ({ graph, explorer, options, workspaceFilePathFilter }) => {
23
23
  table.cell('package', st.cyanBright(packageName));
24
24
  }
25
25
  }
26
- for (const line of table.toRows())
27
- console.log(line);
26
+ const rows = table.toRows();
27
+ if (rows.length === 0)
28
+ console.log(`No imports found matching ${st.cyanBright(options.traceDependency)}`);
29
+ else
30
+ for (const line of rows)
31
+ console.log(line);
28
32
  }
29
33
  else {
30
34
  let nodes = explorer.buildExportsTree({ filePath: options.traceFile, identifier: options.traceExport });
@@ -32,27 +36,55 @@ export default ({ graph, explorer, options, workspaceFilePathFilter }) => {
32
36
  const nsName = options.traceExport.substring(0, options.traceExport.indexOf('.'));
33
37
  nodes = explorer.buildExportsTree({ filePath: options.traceFile, identifier: nsName });
34
38
  }
39
+ if (nodes.length === 0 && options.traceExport) {
40
+ const query = options.traceExport;
41
+ const member = query.slice(query.lastIndexOf('.') + 1);
42
+ const seen = new Set();
43
+ for (const [filePath, file] of graph) {
44
+ if (options.traceFile && filePath !== options.traceFile)
45
+ continue;
46
+ for (const [exportId, exp] of file.exports) {
47
+ const key = `${filePath}:${exportId}`;
48
+ if (seen.has(key))
49
+ continue;
50
+ if (exp.members.some(m => m.identifier === query || m.identifier === member || m.identifier.endsWith(`.${member}`))) {
51
+ seen.add(key);
52
+ nodes.push(...explorer.buildExportsTree({ filePath, identifier: exportId }));
53
+ }
54
+ }
55
+ }
56
+ }
35
57
  nodes.sort((a, b) => a.filePath.localeCompare(b.filePath) || a.identifier.localeCompare(b.identifier));
36
58
  const toRel = (path) => toRelative(path, options.cwd);
37
- const isReferenced = (node) => {
38
- if (explorer.isReferenced(node.filePath, node.identifier, { traverseEntries: false })[0])
39
- return true;
40
- if (explorer.hasStrictlyNsReferences(node.filePath, node.identifier)[0])
41
- return true;
42
- return !!graph.get(node.filePath)?.exports.get(node.identifier)?.hasRefsInFile;
43
- };
59
+ if (nodes.length === 0) {
60
+ if (options.traceFile && !graph.has(options.traceFile)) {
61
+ console.log(`File not found in module graph: ${toRel(options.traceFile)}`);
62
+ }
63
+ else {
64
+ const what = options.traceExport ? `export ${st.cyanBright(options.traceExport)}` : 'exports';
65
+ const where = options.traceFile ? ` in ${toRel(options.traceFile)}` : '';
66
+ console.log(`No ${what} found${where}`);
67
+ }
68
+ return;
69
+ }
70
+ const reportedExports = new Set();
71
+ for (const type of ['exports', 'types', 'nsExports', 'nsTypes'])
72
+ for (const byFile of Object.values(issues[type]))
73
+ for (const issue of Object.values(byFile))
74
+ reportedExports.add(`${issue.filePath}:${issue.symbol}`);
75
+ const reportedMembers = new Set();
76
+ for (const type of ['enumMembers', 'namespaceMembers'])
77
+ for (const byFile of Object.values(issues[type]))
78
+ for (const issue of Object.values(byFile))
79
+ reportedMembers.add(`${issue.filePath}:${issue.parentSymbol}.${issue.symbol}`);
80
+ const isReferenced = (node) => !reportedExports.has(`${node.filePath}:${node.identifier}`);
44
81
  for (const node of nodes) {
45
82
  const exp = graph.get(node.filePath)?.exports.get(node.identifier);
46
83
  let memberStatuses;
47
84
  if (exp && exp.members.length > 0) {
48
85
  memberStatuses = [];
49
86
  for (const m of exp.members) {
50
- const id = `${node.identifier}.${m.identifier}`;
51
- const referenced = m.hasRefsInFile ||
52
- explorer.isReferenced(node.filePath, id, {
53
- traverseEntries: true,
54
- treatStarAtEntryAsReferenced: true,
55
- })[0];
87
+ const referenced = !reportedMembers.has(`${node.filePath}:${node.identifier}.${m.identifier}`);
56
88
  memberStatuses.push({ identifier: m.identifier, referenced });
57
89
  }
58
90
  }
@@ -19,5 +19,5 @@ export declare const finalizeConfigurationHints: (results: Results, options: {
19
19
  configFilePath?: string;
20
20
  }) => ProcessedHint[];
21
21
  export declare const printConfigurationHints: ({ cwd, counters, issues, tagHints, configurationHints, enabledPlugins, isTreatConfigHintsAsErrors, includedWorkspaceDirs, selectedWorkspaces, configFilePath, }: ReporterOptions) => void;
22
- export declare const printTagHints: ({ cwd, tagHints }: ReporterOptions) => void;
22
+ export declare const printTagHints: ({ cwd, tagHints, isTreatTagHintsAsErrors }: ReporterOptions) => void;
23
23
  export {};
@@ -128,9 +128,10 @@ export const printConfigurationHints = ({ cwd, counters, issues, tagHints, confi
128
128
  console.warn(getTableForHints(rows).toString());
129
129
  }
130
130
  };
131
- export const printTagHints = ({ cwd, tagHints }) => {
131
+ export const printTagHints = ({ cwd, tagHints, isTreatTagHintsAsErrors }) => {
132
132
  if (tagHints.size > 0) {
133
- console.log(getDimmedTitle('Tag hints', tagHints.size));
133
+ const getTitle = isTreatTagHintsAsErrors ? getColoredTitle : getDimmedTitle;
134
+ console.warn(getTitle('Tag hints', tagHints.size));
134
135
  for (const hint of tagHints) {
135
136
  const { filePath, identifier, tagName } = hint;
136
137
  const message = `Unused tag in ${toRelative(filePath, cwd)}:`;