knip 2.25.2 → 2.27.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.
package/README.md CHANGED
@@ -244,6 +244,7 @@ This is especially useful over time when such configuration files change (and th
244
244
 
245
245
  Knip contains a growing list of plugins:
246
246
 
247
+ - [Angular][plugin-angular]
247
248
  - [Ava][plugin-ava]
248
249
  - [Babel][plugin-babel]
249
250
  - [Capacitor][plugin-capacitor]
@@ -266,6 +267,7 @@ Knip contains a growing list of plugins:
266
267
  - [Nx][plugin-nx]
267
268
  - [nyc][plugin-nyc]
268
269
  - [Playwright][plugin-playwright]
270
+ - [Playwright for components][plugin-playwright-ct]
269
271
  - [PostCSS][plugin-postcss]
270
272
  - [Prettier][plugin-prettier]
271
273
  - [Release It][plugin-release-it]
@@ -662,6 +664,7 @@ Knip takes the following JSDoc/TSDoc tags into account:
662
664
  --include-entry-exports Include entry files when reporting unused exports
663
665
  -n, --no-progress Don't show dynamic progress updates (automatically enabled in CI environments)
664
666
  --preprocessor Preprocess the results before providing it to the reporter(s), can be repeated
667
+ --preprocessor-options Pass extra options to the preprocessor (as JSON string, see --reporter-options example)
665
668
  --reporter Select reporter: symbols, compact, codeowners, json, can be repeated (default: symbols)
666
669
  --reporter-options Pass extra options to the reporter (as JSON string, see example)
667
670
  --no-config-hints Suppress configuration hints
@@ -863,6 +866,7 @@ Special thanks to the wonderful people who have contributed to this project:
863
866
  [71]: https://www.joshuakgoldberg.com/blog/speeding-up-centered-part-4-unused-code-bloat/
864
867
  [72]: https://github.com/webpro/knip/graphs/contributors
865
868
  [73]: https://contrib.rocks/image?repo=webpro/knip
869
+ [plugin-angular]: ./src/plugins/angular
866
870
  [plugin-ava]: ./src/plugins/ava
867
871
  [plugin-babel]: ./src/plugins/babel
868
872
  [plugin-capacitor]: ./src/plugins/capacitor
@@ -885,6 +889,7 @@ Special thanks to the wonderful people who have contributed to this project:
885
889
  [plugin-nx]: ./src/plugins/nx
886
890
  [plugin-nyc]: ./src/plugins/nyc
887
891
  [plugin-playwright]: ./src/plugins/playwright
892
+ [plugin-playwright-ct]: ./src/plugins/playwright-ct
888
893
  [plugin-postcss]: ./src/plugins/postcss
889
894
  [plugin-prettier]: ./src/plugins/prettier
890
895
  [plugin-release-it]: ./src/plugins/release-it
@@ -8,7 +8,7 @@ type ConfigurationManagerOptions = {
8
8
  };
9
9
  export type Workspace = {
10
10
  name: string;
11
- pkgName?: string;
11
+ pkgName: string;
12
12
  dir: string;
13
13
  ancestors: string[];
14
14
  config: WorkspaceConfiguration;
@@ -15,7 +15,7 @@ import { _dirGlob } from './util/glob.js';
15
15
  import { _load } from './util/loader.js';
16
16
  import { getKeysByValue } from './util/object.js';
17
17
  import { join, relative, toPosix } from './util/path.js';
18
- import { toCamelCase } from './util/plugin.js';
18
+ import { normalizePluginConfig, toCamelCase } from './util/plugin.js';
19
19
  import { byPathDepth } from './util/workspace.js';
20
20
  const { config: rawConfigArg, workspace: rawWorkspaceArg, include = [], exclude = [], dependencies = false, exports = false, } = parsedArgValues;
21
21
  const workspaceArg = rawWorkspaceArg ? toPosix(rawWorkspaceArg).replace(/^\.\//, '').replace(/\/$/, '') : undefined;
@@ -116,6 +116,13 @@ export class ConfigurationChief {
116
116
  const { syncCompilers, asyncCompilers } = rawLocalConfig;
117
117
  const extensions = [...Object.keys(syncCompilers ?? {}), ...Object.keys(asyncCompilers ?? {})];
118
118
  const defaultWorkspaceConfig = getDefaultWorkspaceConfig(extensions);
119
+ const rootPluginConfigs = {};
120
+ for (const [name, pluginConfig] of Object.entries(rawLocalConfig)) {
121
+ const pluginName = toCamelCase(name);
122
+ if (PLUGIN_NAMES.includes(pluginName)) {
123
+ rootPluginConfigs[pluginName] = normalizePluginConfig(pluginConfig);
124
+ }
125
+ }
119
126
  const workspaces = Object.entries(initialWorkspaces)
120
127
  .filter(([workspaceName]) => !ignoreWorkspaces.includes(workspaceName))
121
128
  .reduce((workspaces, workspace) => {
@@ -131,23 +138,15 @@ export class ConfigurationChief {
131
138
  ignoreBinaries: arrayify(workspaceConfig.ignoreBinaries),
132
139
  ignoreDependencies: arrayify(workspaceConfig.ignoreDependencies),
133
140
  };
141
+ for (const [name, pluginConfig] of Object.entries(rootPluginConfigs)) {
142
+ const pluginName = toCamelCase(name);
143
+ if (pluginConfig)
144
+ workspaces[workspaceName][pluginName] = pluginConfig;
145
+ }
134
146
  for (const [name, pluginConfig] of Object.entries(workspaceConfig)) {
135
147
  const pluginName = toCamelCase(name);
136
148
  if (PLUGIN_NAMES.includes(pluginName)) {
137
- if (pluginConfig === false) {
138
- workspaces[workspaceName][pluginName] = false;
139
- }
140
- else {
141
- const isObject = typeof pluginConfig !== 'string' && !Array.isArray(pluginConfig);
142
- const config = isObject ? arrayify(pluginConfig.config) : pluginConfig ? arrayify(pluginConfig) : null;
143
- const entry = isObject && 'entry' in pluginConfig ? arrayify(pluginConfig.entry) : null;
144
- const project = isObject && 'project' in pluginConfig ? arrayify(pluginConfig.project) : entry;
145
- workspaces[workspaceName][pluginName] = {
146
- config,
147
- entry,
148
- project,
149
- };
150
- }
149
+ workspaces[workspaceName][pluginName] = normalizePluginConfig(pluginConfig);
151
150
  }
152
151
  }
153
152
  return workspaces;
@@ -233,7 +232,7 @@ export class ConfigurationChief {
233
232
  : this.availableWorkspaceNames;
234
233
  return workspaceNames.sort(byPathDepth).map((name) => ({
235
234
  name,
236
- pkgName: this.manifestWorkspaces.get(name) ?? this.manifest?.name,
235
+ pkgName: this.manifestWorkspaces.get(name) ?? this.manifest?.name ?? `NOT_FOUND_${name}`,
237
236
  dir: join(this.cwd, name),
238
237
  config: this.getConfigForWorkspace(name),
239
238
  ancestors: this.availableWorkspaceNames.reduce(getAncestors(name), []),
@@ -1,4 +1,17 @@
1
1
  import { z } from 'zod';
2
+ export declare const pluginSchema: z.ZodUnion<[z.ZodLiteral<false>, z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>, z.ZodObject<{
3
+ config: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
4
+ entry: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
5
+ project: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
6
+ }, "strip", z.ZodTypeAny, {
7
+ config?: string | string[] | undefined;
8
+ entry?: string | string[] | undefined;
9
+ project?: string | string[] | undefined;
10
+ }, {
11
+ config?: string | string[] | undefined;
12
+ entry?: string | string[] | undefined;
13
+ project?: string | string[] | undefined;
14
+ }>]>;
2
15
  export declare const ConfigurationValidator: z.ZodObject<{
3
16
  exclude: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
4
17
  rules: z.ZodOptional<z.ZodRecord<z.ZodUnion<[z.ZodLiteral<"files">, z.ZodLiteral<"dependencies">, z.ZodLiteral<"devDependencies">, z.ZodLiteral<"unlisted">, z.ZodLiteral<"binaries">, z.ZodLiteral<"unresolved">, z.ZodLiteral<"exports">, z.ZodLiteral<"types">, z.ZodLiteral<"nsExports">, z.ZodLiteral<"nsTypes">, z.ZodLiteral<"duplicates">, z.ZodLiteral<"enumMembers">, z.ZodLiteral<"classMembers">]>, z.ZodEnum<["error", "warn", "off"]>>>;
@@ -21,6 +34,19 @@ export declare const ConfigurationValidator: z.ZodObject<{
21
34
  ignore: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
22
35
  ignoreBinaries: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
23
36
  ignoreDependencies: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
37
+ angular: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<false>, z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>, z.ZodObject<{
38
+ config: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
39
+ entry: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
40
+ project: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
41
+ }, "strip", z.ZodTypeAny, {
42
+ config?: string | string[] | undefined;
43
+ entry?: string | string[] | undefined;
44
+ project?: string | string[] | undefined;
45
+ }, {
46
+ config?: string | string[] | undefined;
47
+ entry?: string | string[] | undefined;
48
+ project?: string | string[] | undefined;
49
+ }>]>>;
24
50
  ava: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<false>, z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>, z.ZodObject<{
25
51
  config: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
26
52
  entry: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
@@ -535,6 +561,11 @@ export declare const ConfigurationValidator: z.ZodObject<{
535
561
  ignore?: string | string[] | undefined;
536
562
  ignoreBinaries?: string[] | undefined;
537
563
  ignoreDependencies?: string[] | undefined;
564
+ angular?: string | false | string[] | {
565
+ config?: string | string[] | undefined;
566
+ entry?: string | string[] | undefined;
567
+ project?: string | string[] | undefined;
568
+ } | undefined;
538
569
  ava?: string | false | string[] | {
539
570
  config?: string | string[] | undefined;
540
571
  entry?: string | string[] | undefined;
@@ -737,6 +768,11 @@ export declare const ConfigurationValidator: z.ZodObject<{
737
768
  ignore?: string | string[] | undefined;
738
769
  ignoreBinaries?: string[] | undefined;
739
770
  ignoreDependencies?: string[] | undefined;
771
+ angular?: string | false | string[] | {
772
+ config?: string | string[] | undefined;
773
+ entry?: string | string[] | undefined;
774
+ project?: string | string[] | undefined;
775
+ } | undefined;
740
776
  ava?: string | false | string[] | {
741
777
  config?: string | string[] | undefined;
742
778
  entry?: string | string[] | undefined;
@@ -933,6 +969,19 @@ export declare const ConfigurationValidator: z.ZodObject<{
933
969
  project?: string | string[] | undefined;
934
970
  } | undefined;
935
971
  }>>>;
972
+ angular: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<false>, z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>, z.ZodObject<{
973
+ config: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
974
+ entry: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
975
+ project: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
976
+ }, "strip", z.ZodTypeAny, {
977
+ config?: string | string[] | undefined;
978
+ entry?: string | string[] | undefined;
979
+ project?: string | string[] | undefined;
980
+ }, {
981
+ config?: string | string[] | undefined;
982
+ entry?: string | string[] | undefined;
983
+ project?: string | string[] | undefined;
984
+ }>]>>;
936
985
  ava: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<false>, z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>, z.ZodObject<{
937
986
  config: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
938
987
  entry: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
@@ -1462,6 +1511,11 @@ export declare const ConfigurationValidator: z.ZodObject<{
1462
1511
  ignore?: string | string[] | undefined;
1463
1512
  ignoreBinaries?: string[] | undefined;
1464
1513
  ignoreDependencies?: string[] | undefined;
1514
+ angular?: string | false | string[] | {
1515
+ config?: string | string[] | undefined;
1516
+ entry?: string | string[] | undefined;
1517
+ project?: string | string[] | undefined;
1518
+ } | undefined;
1465
1519
  ava?: string | false | string[] | {
1466
1520
  config?: string | string[] | undefined;
1467
1521
  entry?: string | string[] | undefined;
@@ -1658,6 +1712,11 @@ export declare const ConfigurationValidator: z.ZodObject<{
1658
1712
  project?: string | string[] | undefined;
1659
1713
  } | undefined;
1660
1714
  }> | undefined;
1715
+ angular?: string | false | string[] | {
1716
+ config?: string | string[] | undefined;
1717
+ entry?: string | string[] | undefined;
1718
+ project?: string | string[] | undefined;
1719
+ } | undefined;
1661
1720
  ava?: string | false | string[] | {
1662
1721
  config?: string | string[] | undefined;
1663
1722
  entry?: string | string[] | undefined;
@@ -1875,6 +1934,11 @@ export declare const ConfigurationValidator: z.ZodObject<{
1875
1934
  ignore?: string | string[] | undefined;
1876
1935
  ignoreBinaries?: string[] | undefined;
1877
1936
  ignoreDependencies?: string[] | undefined;
1937
+ angular?: string | false | string[] | {
1938
+ config?: string | string[] | undefined;
1939
+ entry?: string | string[] | undefined;
1940
+ project?: string | string[] | undefined;
1941
+ } | undefined;
1878
1942
  ava?: string | false | string[] | {
1879
1943
  config?: string | string[] | undefined;
1880
1944
  entry?: string | string[] | undefined;
@@ -2071,6 +2135,11 @@ export declare const ConfigurationValidator: z.ZodObject<{
2071
2135
  project?: string | string[] | undefined;
2072
2136
  } | undefined;
2073
2137
  }> | undefined;
2138
+ angular?: string | false | string[] | {
2139
+ config?: string | string[] | undefined;
2140
+ entry?: string | string[] | undefined;
2141
+ project?: string | string[] | undefined;
2142
+ } | undefined;
2074
2143
  ava?: string | false | string[] | {
2075
2144
  config?: string | string[] | undefined;
2076
2145
  entry?: string | string[] | undefined;
@@ -50,7 +50,7 @@ const reportConfigSchema = z.object({
50
50
  include: z.array(z.string()).optional(),
51
51
  exclude: z.array(z.string()).optional(),
52
52
  });
53
- const pluginSchema = z.union([
53
+ export const pluginSchema = z.union([
54
54
  z.literal(false),
55
55
  globSchema,
56
56
  z.object({
@@ -60,6 +60,7 @@ const pluginSchema = z.union([
60
60
  }),
61
61
  ]);
62
62
  const pluginsSchema = z.object({
63
+ angular: pluginSchema,
63
64
  ava: pluginSchema,
64
65
  babel: pluginSchema,
65
66
  capacitor: pluginSchema,
@@ -6,6 +6,7 @@ type Principal = {
6
6
  principal: ProjectPrincipal;
7
7
  cwds: Set<string>;
8
8
  pathKeys: Set<string>;
9
+ pkgNames: Set<string>;
9
10
  };
10
11
  type Principals = Set<Principal>;
11
12
  type Options = {
@@ -13,6 +14,7 @@ type Options = {
13
14
  compilerOptions: ts.CompilerOptions;
14
15
  paths: Paths;
15
16
  compilers: [SyncCompilers, AsyncCompilers];
17
+ pkgName: string;
16
18
  };
17
19
  export declare class PrincipalFactory {
18
20
  principals: Principals;
@@ -21,5 +23,6 @@ export declare class PrincipalFactory {
21
23
  private linkPrincipal;
22
24
  private addNewPrincipal;
23
25
  getPrincipals(): ProjectPrincipal[];
26
+ getPrincipalByPackageName(packageName: string): ProjectPrincipal | undefined;
24
27
  }
25
28
  export {};
@@ -12,11 +12,11 @@ const mergePaths = (cwd, compilerOptions, paths = {}) => {
12
12
  export class PrincipalFactory {
13
13
  principals = new Set();
14
14
  getPrincipal(options) {
15
- const { cwd, compilerOptions, paths } = options;
15
+ const { cwd, compilerOptions, paths, pkgName } = options;
16
16
  options.compilerOptions = mergePaths(cwd, compilerOptions, paths);
17
17
  const principal = this.findReusablePrincipal(compilerOptions);
18
18
  if (principal) {
19
- this.linkPrincipal(principal, cwd, compilerOptions);
19
+ this.linkPrincipal(principal, cwd, compilerOptions, pkgName);
20
20
  return principal.principal;
21
21
  }
22
22
  else {
@@ -35,22 +35,26 @@ export class PrincipalFactory {
35
35
  });
36
36
  return principal;
37
37
  }
38
- linkPrincipal(principal, cwd, compilerOptions) {
38
+ linkPrincipal(principal, cwd, compilerOptions, pkgName) {
39
39
  const { pathsBasePath, paths } = compilerOptions;
40
40
  if (pathsBasePath)
41
41
  principal.principal.compilerOptions.pathsBasePath = pathsBasePath;
42
42
  Object.keys(paths ?? {}).forEach(p => principal.pathKeys.add(p));
43
43
  principal.principal.compilerOptions.paths = { ...principal.principal.compilerOptions.paths, ...paths };
44
44
  principal.cwds.add(cwd);
45
+ principal.pkgNames.add(pkgName);
45
46
  }
46
47
  addNewPrincipal(options) {
47
- const { cwd, compilerOptions } = options;
48
+ const { cwd, compilerOptions, pkgName } = options;
48
49
  const pathKeys = new Set(Object.keys(compilerOptions?.paths ?? {}));
49
50
  const principal = new ProjectPrincipal(options);
50
- this.principals.add({ principal, cwds: new Set([cwd]), pathKeys });
51
+ this.principals.add({ principal, cwds: new Set([cwd]), pathKeys, pkgNames: new Set([pkgName]) });
51
52
  return principal;
52
53
  }
53
54
  getPrincipals() {
54
- return Array.from(this.principals, p => p.principal);
55
+ return Array.from(this.principals, p => p.principal).reverse();
56
+ }
57
+ getPrincipalByPackageName(packageName) {
58
+ return Array.from(this.principals).find(principal => principal.pkgNames.has(packageName))?.principal;
55
59
  }
56
60
  }
@@ -107,7 +107,7 @@ export class ProjectPrincipal {
107
107
  return Array.from(this.projectPaths).filter(filePath => !sourceFiles.has(filePath));
108
108
  }
109
109
  analyzeSourceFile(filePath, { skipTypeOnly }) {
110
- const sourceFile = this.backend.program?.getSourceFile(filePath);
110
+ const sourceFile = this.backend.fileManager.getSourceFile(filePath);
111
111
  if (!sourceFile)
112
112
  throw new Error(`Unable to find ${filePath}`);
113
113
  const skipExports = this.skipExportsAnalysis.has(filePath);
@@ -192,6 +192,11 @@ export class ProjectPrincipal {
192
192
  .map(member => member.identifier);
193
193
  }
194
194
  findReferences(filePath, pos) {
195
- return this.backend.lsFindReferences(filePath, pos) ?? [];
195
+ try {
196
+ return this.backend.lsFindReferences(filePath, pos) ?? [];
197
+ }
198
+ catch {
199
+ return [];
200
+ }
196
201
  }
197
202
  }
@@ -50,7 +50,7 @@ export declare class WorkspaceWorker {
50
50
  hostDependencies: HostDependencies;
51
51
  installedBinaries: InstalledBinaries;
52
52
  referencedDependencies: ReferencedDependencies;
53
- enabledPlugins: ("ava" | "babel" | "capacitor" | "changesets" | "commitizen" | "commitlint" | "cspell" | "cypress" | "eslint" | "gatsby" | "husky" | "jest" | "lefthook" | "markdownlint" | "mocha" | "next" | "nx" | "nyc" | "playwright" | "postcss" | "prettier" | "remark" | "remix" | "rollup" | "sentry" | "storybook" | "stryker" | "stylelint" | "tailwind" | "typedoc" | "typescript" | "vite" | "vitest" | "webpack" | "githubActions" | "lintStaged" | "npmPackageJsonLint" | "releaseIt" | "semanticRelease" | "svelte")[];
53
+ enabledPlugins: ("angular" | "ava" | "babel" | "capacitor" | "changesets" | "commitizen" | "commitlint" | "cspell" | "cypress" | "eslint" | "gatsby" | "husky" | "jest" | "lefthook" | "markdownlint" | "mocha" | "next" | "nx" | "nyc" | "playwright" | "postcss" | "prettier" | "remark" | "remix" | "rollup" | "sentry" | "storybook" | "stryker" | "stylelint" | "tailwind" | "typedoc" | "typescript" | "vite" | "vitest" | "webpack" | "githubActions" | "lintStaged" | "npmPackageJsonLint" | "playwrightCt" | "releaseIt" | "semanticRelease" | "svelte")[];
54
54
  }>;
55
55
  }
56
56
  export {};
package/dist/cli.js CHANGED
@@ -8,7 +8,7 @@ import { Performance } from './util/Performance.js';
8
8
  import { runPreprocessors, runReporters } from './util/reporter.js';
9
9
  import { version } from './version.js';
10
10
  import { main } from './index.js';
11
- const { debug: isDebug = false, help: isHelp, 'max-issues': maxIssues = '0', 'no-config-hints': noConfigHints = false, 'no-exit-code': noExitCode = false, 'no-gitignore': isNoGitIgnore = false, 'no-progress': isNoProgress = false, 'ignore-internal': isIgnoreInternal = false, 'include-entry-exports': isIncludeEntryExports = false, performance: isObservePerf = false, production: isProduction = false, 'reporter-options': reporterOptions = '', strict: isStrict = false, tsConfig, version: isVersion, } = parsedArgValues;
11
+ const { debug: isDebug = false, help: isHelp, 'max-issues': maxIssues = '0', 'no-config-hints': noConfigHints = false, 'no-exit-code': noExitCode = false, 'no-gitignore': isNoGitIgnore = false, 'no-progress': isNoProgress = false, 'ignore-internal': isIgnoreInternal = false, 'include-entry-exports': isIncludeEntryExports = false, performance: isObservePerf = false, production: isProduction = false, 'reporter-options': reporterOptions = '', 'preprocessor-options': preprocessorOptions = '', strict: isStrict = false, tsConfig, version: isVersion, } = parsedArgValues;
12
12
  if (isHelp) {
13
13
  console.log(helpText);
14
14
  process.exit(0);
@@ -40,6 +40,7 @@ const run = async () => {
40
40
  isProduction,
41
41
  isShowProgress,
42
42
  options: reporterOptions,
43
+ preprocessorOptions,
43
44
  };
44
45
  const finalData = await runPreprocessors(initialData);
45
46
  await runReporters(finalData);
package/dist/index.js CHANGED
@@ -83,7 +83,7 @@ export const main = async (unresolvedConfiguration) => {
83
83
  }
84
84
  };
85
85
  for (const workspace of workspaces) {
86
- const { name, dir, config, ancestors } = workspace;
86
+ const { name, dir, config, ancestors, pkgName } = workspace;
87
87
  const { paths, ignoreDependencies, ignoreBinaries } = config;
88
88
  const isRoot = name === ROOT_WORKSPACE_NAME;
89
89
  streamer.cast(`Analyzing workspace (${name})...`);
@@ -93,7 +93,7 @@ export const main = async (unresolvedConfiguration) => {
93
93
  throw new LoaderError(`Unable to load package.json for ${name}`);
94
94
  deputy.addWorkspace({ name, dir, manifestPath, manifest, ignoreDependencies, ignoreBinaries });
95
95
  const compilerOptions = await loadCompilerOptions(join(dir, tsConfigFile ?? 'tsconfig.json'));
96
- const principal = factory.getPrincipal({ cwd: dir, paths, compilerOptions, compilers });
96
+ const principal = factory.getPrincipal({ cwd: dir, paths, compilerOptions, compilers, pkgName });
97
97
  const worker = new WorkspaceWorker({
98
98
  name,
99
99
  dir,
@@ -176,21 +176,33 @@ export const main = async (unresolvedConfiguration) => {
176
176
  }
177
177
  const principals = factory.getPrincipals();
178
178
  debugLog(`Installed ${principals.length} principals for ${workspaces.length} workspaces`);
179
+ const analyzedFiles = new Set();
180
+ const exportedSymbols = new Map();
181
+ const importedSymbols = new Map();
179
182
  for (const principal of principals) {
180
- const exportedSymbols = new Map();
181
- const importedSymbols = new Map();
182
- const analyzeSourceFile = (filePath) => {
183
+ const analyzeSourceFile = (filePath, _principal = principal) => {
183
184
  const workspace = chief.findWorkspaceByFilePath(filePath);
184
185
  if (workspace) {
185
- const { imports, exports, scripts } = principal.analyzeSourceFile(filePath, { skipTypeOnly: isProduction });
186
+ const { imports, exports, scripts } = _principal.analyzeSourceFile(filePath, { skipTypeOnly: isProduction });
186
187
  const { internal, external, unresolved } = imports;
187
188
  const { exported, duplicate } = exports;
188
189
  if (exported.size > 0)
189
190
  exportedSymbols.set(filePath, exported);
190
191
  for (const [specifierFilePath, importItems] of internal.entries()) {
191
192
  const packageName = getPackageNameFromModuleSpecifier(importItems.specifier);
192
- if (packageName && chief.localWorkspaces.has(packageName))
193
+ if (packageName && chief.localWorkspaces.has(packageName)) {
193
194
  external.add(packageName);
195
+ if (_principal === principal) {
196
+ const workspace = chief.findWorkspaceByFilePath(specifierFilePath);
197
+ if (workspace) {
198
+ const principal = factory.getPrincipalByPackageName(workspace.pkgName);
199
+ if (principal && !principal.isGitIgnored(specifierFilePath)) {
200
+ analyzeSourceFile(specifierFilePath, principal);
201
+ analyzedFiles.add(specifierFilePath);
202
+ }
203
+ }
204
+ }
205
+ }
194
206
  if (!importedSymbols.has(specifierFilePath)) {
195
207
  importedSymbols.set(specifierFilePath, importItems);
196
208
  }
@@ -223,14 +235,13 @@ export const main = async (unresolvedConfiguration) => {
223
235
  collector.addIssue({ type: 'unresolved', filePath, symbol: moduleSpecifier });
224
236
  });
225
237
  _getDependenciesFromScripts(scripts, { cwd: dirname(filePath) }).forEach(specifier => {
226
- handleReferencedDependency({ specifier, containingFilePath: filePath, principal, workspace });
238
+ handleReferencedDependency({ specifier, containingFilePath: filePath, principal: _principal, workspace });
227
239
  });
228
240
  }
229
241
  };
230
242
  streamer.cast('Running async compilers...');
231
243
  await principal.runAsyncCompilers();
232
244
  streamer.cast('Connecting the dots...');
233
- const analyzedFiles = new Set();
234
245
  let size = principal.entryPaths.size;
235
246
  let round = 0;
236
247
  do {
@@ -243,37 +254,38 @@ export const main = async (unresolvedConfiguration) => {
243
254
  analyzedFiles.add(filePath);
244
255
  });
245
256
  } while (size !== principal.entryPaths.size);
246
- const unusedFiles = principal.getUnreferencedFiles();
247
- collector.addFilesIssues(unusedFiles);
248
- collector.addFileCounts({ processed: analyzedFiles.size, unused: unusedFiles.length });
249
- const isSymbolImported = (symbol, importingModule) => {
250
- if (!importingModule)
251
- return false;
252
- if (importingModule.symbols.has(symbol))
253
- return true;
254
- const { isReExport, isReExportedBy } = importingModule;
255
- const hasSymbol = (file) => isSymbolImported(symbol, importedSymbols.get(file));
256
- return isReExport ? Array.from(isReExportedBy).some(hasSymbol) : false;
257
- };
258
- const isExportedInEntryFile = (importedModule) => {
259
- if (!importedModule)
260
- return false;
261
- const { isReExport, isReExportedBy } = importedModule;
262
- const { entryPaths } = principal;
263
- const hasFile = (file) => entryPaths.has(file) || isExportedInEntryFile(importedSymbols.get(file));
264
- return isReExport ? Array.from(isReExportedBy).some(hasFile) : false;
265
- };
266
- const isExportedItemReferenced = (exportedItem, filePath) => {
267
- const hasReferences = principal.getHasReferences(filePath, exportedItem);
268
- return (hasReferences.external ||
269
- (hasReferences.internal &&
270
- (typeof chief.config.ignoreExportsUsedInFile === 'object'
271
- ? exportedItem.type !== 'unknown' && !!chief.config.ignoreExportsUsedInFile[exportedItem.type]
272
- : chief.config.ignoreExportsUsedInFile)));
273
- };
274
- if (isReportValues || isReportTypes) {
275
- streamer.cast('Analyzing source files...');
276
- for (const [filePath, exportItems] of exportedSymbols.entries()) {
257
+ }
258
+ const isSymbolImported = (symbol, importingModule) => {
259
+ if (!importingModule)
260
+ return false;
261
+ if (importingModule.symbols.has(symbol))
262
+ return true;
263
+ const { isReExport, isReExportedBy } = importingModule;
264
+ const hasSymbol = (file) => isSymbolImported(symbol, importedSymbols.get(file));
265
+ return isReExport ? Array.from(isReExportedBy).some(hasSymbol) : false;
266
+ };
267
+ const isExportedInEntryFile = (principal, importedModule) => {
268
+ if (!importedModule)
269
+ return false;
270
+ const { isReExport, isReExportedBy } = importedModule;
271
+ const { entryPaths } = principal;
272
+ const hasFile = (file) => entryPaths.has(file) || isExportedInEntryFile(principal, importedSymbols.get(file));
273
+ return isReExport ? Array.from(isReExportedBy).some(hasFile) : false;
274
+ };
275
+ const isExportedItemReferenced = (principal, exportedItem, filePath) => {
276
+ const hasReferences = principal.getHasReferences(filePath, exportedItem);
277
+ return (hasReferences.external ||
278
+ (hasReferences.internal &&
279
+ (typeof chief.config.ignoreExportsUsedInFile === 'object'
280
+ ? exportedItem.type !== 'unknown' && !!chief.config.ignoreExportsUsedInFile[exportedItem.type]
281
+ : chief.config.ignoreExportsUsedInFile)));
282
+ };
283
+ if (isReportValues || isReportTypes) {
284
+ streamer.cast('Analyzing source files...');
285
+ for (const [filePath, exportItems] of exportedSymbols.entries()) {
286
+ const workspace = chief.findWorkspaceByFilePath(filePath);
287
+ const principal = workspace && factory.getPrincipalByPackageName(workspace.pkgName);
288
+ if (principal) {
277
289
  if (!isIncludeEntryExports && principal.entryPaths.has(filePath))
278
290
  continue;
279
291
  const importingModule = importedSymbols.get(filePath);
@@ -283,7 +295,7 @@ export const main = async (unresolvedConfiguration) => {
283
295
  if (isIgnoreInternal && exportedItem.jsDocTags.has('@internal'))
284
296
  continue;
285
297
  if (importingModule && isSymbolImported(symbol, importingModule)) {
286
- if (importingModule.isReExport && isExportedInEntryFile(importingModule))
298
+ if (importingModule.isReExport && isExportedInEntryFile(principal, importingModule))
287
299
  continue;
288
300
  if (report.enumMembers && exportedItem.type === 'enum' && exportedItem.members) {
289
301
  if (isProduction)
@@ -300,8 +312,8 @@ export const main = async (unresolvedConfiguration) => {
300
312
  continue;
301
313
  }
302
314
  const isStar = Boolean(importingModule?.isStar);
303
- const isReExportedByEntryFile = !isIncludeEntryExports && isStar && isExportedInEntryFile(importingModule);
304
- if (!isReExportedByEntryFile && !isExportedItemReferenced(exportedItem, filePath)) {
315
+ const isReExportedByEntryFile = !isIncludeEntryExports && isStar && isExportedInEntryFile(principal, importingModule);
316
+ if (!isReExportedByEntryFile && !isExportedItemReferenced(principal, exportedItem, filePath)) {
305
317
  if (['enum', 'type', 'interface'].includes(exportedItem.type)) {
306
318
  if (isProduction)
307
319
  continue;
@@ -317,6 +329,12 @@ export const main = async (unresolvedConfiguration) => {
317
329
  }
318
330
  }
319
331
  }
332
+ const unusedFiles = factory
333
+ .getPrincipals()
334
+ .flatMap(principal => principal.getUnreferencedFiles())
335
+ .filter(filePath => !analyzedFiles.has(filePath));
336
+ collector.addFilesIssues(unusedFiles);
337
+ collector.addFileCounts({ processed: analyzedFiles.size, unused: unusedFiles.length });
320
338
  if (isReportDependencies) {
321
339
  const { dependencyIssues, devDependencyIssues, optionalPeerDependencyIssues } = deputy.settleDependencyIssues();
322
340
  const { configurationHints } = deputy.getConfigurationHints();
@@ -6,7 +6,7 @@ const findManifestDependencies = async ({ manifest, isProduction, isStrict, dir,
6
6
  const hostDependencies = new Map();
7
7
  const scripts = Object.entries(manifest.scripts ?? {}).reduce((scripts, [scriptName, script]) => {
8
8
  if (script && (scriptFilter.length === 0 || scriptFilter.includes(scriptName))) {
9
- return [...scripts, script];
9
+ scripts.push(script);
10
10
  }
11
11
  return scripts;
12
12
  }, []);
@@ -0,0 +1,6 @@
1
+ import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "Angular";
3
+ export declare const ENABLERS: string[];
4
+ export declare const isEnabled: IsPluginEnabledCallback;
5
+ export declare const CONFIG_FILE_PATTERNS: string[];
6
+ export declare const findDependencies: GenericPluginCallback;
@@ -0,0 +1,36 @@
1
+ import { join } from '../../util/path.js';
2
+ import { timerify } from '../../util/Performance.js';
3
+ import { hasDependency, load } from '../../util/plugin.js';
4
+ import { findTypeScriptDependencies } from '../typescript/index.js';
5
+ export const NAME = 'Angular';
6
+ export const ENABLERS = ['@angular/cli'];
7
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
8
+ export const CONFIG_FILE_PATTERNS = ['angular.json'];
9
+ const findPluginDependencies = async (configFilePath, opts) => {
10
+ const { cwd } = opts;
11
+ const config = await load(configFilePath);
12
+ if (!config.projects)
13
+ return [];
14
+ const dependencies = new Set();
15
+ for (const project of Object.values(config.projects)) {
16
+ if (!project.architect)
17
+ return [];
18
+ for (const target of Object.values(project.architect)) {
19
+ const { options } = target;
20
+ const [packageName] = typeof target.builder === 'string' ? target.builder.split(':') : [];
21
+ if (typeof packageName === 'string')
22
+ dependencies.add(packageName);
23
+ if (options) {
24
+ if ('main' in options && typeof options?.main === 'string') {
25
+ dependencies.add(join(cwd, options.main));
26
+ }
27
+ if ('tsConfig' in options && typeof options.tsConfig === 'string') {
28
+ const tsConfigDependencies = await findTypeScriptDependencies(join(cwd, options.tsConfig), opts);
29
+ tsConfigDependencies.forEach(dependency => dependencies.add(dependency));
30
+ }
31
+ }
32
+ }
33
+ }
34
+ return Array.from(dependencies);
35
+ };
36
+ export const findDependencies = timerify(findPluginDependencies);