knip 6.29.0 → 6.30.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 (105) hide show
  1. package/dist/CatalogCounselor.d.ts +5 -2
  2. package/dist/CatalogCounselor.js +26 -8
  3. package/dist/ConfigurationChief.d.ts +1 -1
  4. package/dist/ConfigurationChief.js +29 -36
  5. package/dist/DependencyDeputy.d.ts +8 -1
  6. package/dist/DependencyDeputy.js +5 -5
  7. package/dist/PackagePeeker.d.ts +5 -0
  8. package/dist/PackagePeeker.js +31 -3
  9. package/dist/WorkspaceWorker.d.ts +1 -1
  10. package/dist/WorkspaceWorker.js +11 -7
  11. package/dist/binaries/bash-parser.js +3 -3
  12. package/dist/binaries/create-script-parser-context.d.ts +7 -0
  13. package/dist/binaries/create-script-parser-context.js +17 -0
  14. package/dist/binaries/resolvers/pnpx.js +10 -5
  15. package/dist/compilers/index.d.ts +5 -5
  16. package/dist/compilers/scss.js +32 -5
  17. package/dist/compilers/shared.d.ts +1 -0
  18. package/dist/compilers/shared.js +1 -1
  19. package/dist/compilers/svelte.d.ts +2 -0
  20. package/dist/compilers/svelte.js +22 -0
  21. package/dist/constants.d.ts +4 -1
  22. package/dist/constants.js +4 -0
  23. package/dist/graph/analyze.js +5 -2
  24. package/dist/graph/build.d.ts +3 -1
  25. package/dist/graph/build.js +38 -19
  26. package/dist/graph-explorer/operations/build-exports-tree.js +2 -1
  27. package/dist/graph-explorer/operations/is-referenced.js +7 -4
  28. package/dist/graph-explorer/utils.js +2 -2
  29. package/dist/plugins/_template/index.js +1 -1
  30. package/dist/plugins/astro-markdoc/index.js +3 -2
  31. package/dist/plugins/eleventy/index.js +1 -1
  32. package/dist/plugins/esbuild/index.js +1 -1
  33. package/dist/plugins/eslint/helpers.js +2 -1
  34. package/dist/plugins/gatsby/index.js +2 -2
  35. package/dist/plugins/jest/helpers.js +1 -1
  36. package/dist/plugins/metro/index.js +1 -1
  37. package/dist/plugins/nest/index.js +1 -1
  38. package/dist/plugins/node/index.js +11 -2
  39. package/dist/plugins/nx/index.js +4 -3
  40. package/dist/plugins/openclaw/index.js +1 -1
  41. package/dist/plugins/oxlint/index.js +9 -2
  42. package/dist/plugins/remark/helpers.d.ts +3 -0
  43. package/dist/plugins/remark/helpers.js +42 -0
  44. package/dist/plugins/remark/index.js +4 -5
  45. package/dist/plugins/rolldown/index.js +1 -1
  46. package/dist/plugins/rollup/index.js +1 -1
  47. package/dist/plugins/rslib/index.js +1 -1
  48. package/dist/plugins/stryker/index.js +6 -1
  49. package/dist/plugins/svelte/compiler.js +7 -5
  50. package/dist/plugins/tsdown/index.js +2 -2
  51. package/dist/plugins/tsup/index.js +1 -1
  52. package/dist/plugins/vitest/index.js +1 -1
  53. package/dist/plugins/vitest/types.d.ts +1 -1
  54. package/dist/reporters/codeclimate.js +1 -5
  55. package/dist/reporters/github-actions.js +5 -3
  56. package/dist/reporters/index.d.ts +1 -0
  57. package/dist/reporters/index.js +2 -0
  58. package/dist/reporters/json.d.ts +1 -0
  59. package/dist/reporters/json.js +1 -0
  60. package/dist/reporters/sarif.d.ts +3 -0
  61. package/dist/reporters/sarif.js +79 -0
  62. package/dist/reporters/trace.js +3 -2
  63. package/dist/reporters/util/util.d.ts +2 -1
  64. package/dist/reporters/util/util.js +6 -1
  65. package/dist/run.d.ts +1 -1
  66. package/dist/run.js +30 -0
  67. package/dist/schema/configuration.d.ts +6 -6
  68. package/dist/schema/configuration.js +1 -0
  69. package/dist/session/build-maps.js +2 -1
  70. package/dist/types/issues.d.ts +1 -0
  71. package/dist/types/package-json.d.ts +10 -0
  72. package/dist/typescript/get-imports-and-exports.js +3 -2
  73. package/dist/typescript/get-published-type-dependencies.d.ts +13 -0
  74. package/dist/typescript/get-published-type-dependencies.js +155 -0
  75. package/dist/typescript/visitors/calls.js +8 -0
  76. package/dist/util/catalog.d.ts +6 -1
  77. package/dist/util/catalog.js +16 -2
  78. package/dist/util/cli-arguments.d.ts +1 -1
  79. package/dist/util/cli-arguments.js +3 -3
  80. package/dist/util/codeowners.js +1 -1
  81. package/dist/util/create-input-handler.js +8 -2
  82. package/dist/util/create-options.d.ts +6 -5
  83. package/dist/util/disk-cache.js +1 -1
  84. package/dist/util/errors.js +3 -2
  85. package/dist/util/file-entry-cache.js +5 -1
  86. package/dist/util/fs.js +2 -2
  87. package/dist/util/get-included-issue-types.js +2 -1
  88. package/dist/util/gitignore-cache.js +4 -1
  89. package/dist/util/glob-cache.js +2 -2
  90. package/dist/util/glob-core.js +3 -1
  91. package/dist/util/input.d.ts +7 -1
  92. package/dist/util/input.js +6 -0
  93. package/dist/util/package-json.d.ts +346 -0
  94. package/dist/util/package-json.js +123 -0
  95. package/dist/util/path.d.ts +8 -7
  96. package/dist/util/resolve.d.ts +6 -0
  97. package/dist/util/resolve.js +24 -0
  98. package/dist/util/string.d.ts +2 -0
  99. package/dist/util/string.js +6 -0
  100. package/dist/util/table.js +2 -2
  101. package/dist/util/to-source-path.js +1 -1
  102. package/dist/version.d.ts +1 -1
  103. package/dist/version.js +1 -1
  104. package/package.json +5 -5
  105. package/schema.json +4 -0
@@ -16,7 +16,7 @@ export declare const IGNORED_DEPENDENCIES: Set<string>;
16
16
  export declare const IGNORED_RUNTIME_DEPENDENCIES: Set<string>;
17
17
  export declare const FOREIGN_FILE_EXTENSIONS: Set<string>;
18
18
  export declare const IGNORE_DEFINITELY_TYPED: Set<string>;
19
- export declare const ISSUE_TYPES: readonly ['files', 'dependencies', 'devDependencies', 'optionalPeerDependencies', 'unlisted', 'binaries', 'unresolved', 'exports', 'nsExports', 'types', 'nsTypes', 'enumMembers', 'namespaceMembers', 'duplicates', 'catalog', 'cycles'];
19
+ export declare const ISSUE_TYPES: readonly ['files', 'dependencies', 'devDependencies', 'optionalPeerDependencies', 'unlisted', 'binaries', 'unresolved', 'exports', 'nsExports', 'types', 'nsTypes', 'enumMembers', 'namespaceMembers', 'duplicates', 'catalog', 'catalogReferences', 'cycles'];
20
20
  export declare const ISSUE_TYPE_TITLE: {
21
21
  readonly files: 'Unused files';
22
22
  readonly dependencies: 'Unused dependencies';
@@ -33,6 +33,7 @@ export declare const ISSUE_TYPE_TITLE: {
33
33
  readonly namespaceMembers: 'Unused exported namespace members';
34
34
  readonly duplicates: 'Duplicate exports';
35
35
  readonly catalog: 'Unused catalog entries';
36
+ readonly catalogReferences: 'Unresolved catalog references';
36
37
  readonly cycles: 'Circular dependencies';
37
38
  };
38
39
  export declare const SYMBOL_TYPE: {
@@ -54,6 +55,7 @@ export declare const FIX_FLAGS: {
54
55
  };
55
56
  export declare const SIDE_EFFECTS = "__side-effects";
56
57
  export declare const OPAQUE = "__opaque";
58
+ export declare const LOADER_DEFAULT = "__loader-default";
57
59
  export declare const SCRIPT_INTERPOLATION = "$__knip__";
58
60
  export declare const IMPORT_FLAGS: {
59
61
  readonly NONE: 0;
@@ -66,4 +68,5 @@ export declare const IMPORT_FLAGS: {
66
68
  readonly OPAQUE: number;
67
69
  readonly AUGMENT: number;
68
70
  readonly DYNAMIC: number;
71
+ readonly LOADER: number;
69
72
  };
package/dist/constants.js CHANGED
@@ -219,6 +219,7 @@ export const ISSUE_TYPES = [
219
219
  'namespaceMembers',
220
220
  'duplicates',
221
221
  'catalog',
222
+ 'catalogReferences',
222
223
  'cycles',
223
224
  ];
224
225
  export const ISSUE_TYPE_TITLE = {
@@ -237,6 +238,7 @@ export const ISSUE_TYPE_TITLE = {
237
238
  namespaceMembers: 'Unused exported namespace members',
238
239
  duplicates: 'Duplicate exports',
239
240
  catalog: 'Unused catalog entries',
241
+ catalogReferences: 'Unresolved catalog references',
240
242
  cycles: 'Circular dependencies',
241
243
  };
242
244
  export const SYMBOL_TYPE = {
@@ -258,6 +260,7 @@ export const FIX_FLAGS = {
258
260
  };
259
261
  export const SIDE_EFFECTS = '__side-effects';
260
262
  export const OPAQUE = '__opaque';
263
+ export const LOADER_DEFAULT = '__loader-default';
261
264
  export const SCRIPT_INTERPOLATION = '$__knip__';
262
265
  export const IMPORT_FLAGS = {
263
266
  NONE: 0,
@@ -270,4 +273,5 @@ export const IMPORT_FLAGS = {
270
273
  OPAQUE: 1 << 6,
271
274
  AUGMENT: 1 << 7,
272
275
  DYNAMIC: 1 << 8,
276
+ LOADER: 1 << 9,
273
277
  };
@@ -154,7 +154,7 @@ export const analyze = async ({ analyzedFiles, counselor, chief, collector, depu
154
154
  }
155
155
  }
156
156
  const [hasStrictlyNsRefs, namespace] = explorer.hasStrictlyNsReferences(filePath, identifier);
157
- const isType = ['enum', 'type', 'interface'].includes(exportedItem.type);
157
+ const isType = exportedItem.type === 'enum' || exportedItem.type === 'type' || exportedItem.type === 'interface';
158
158
  if (isIgnored ||
159
159
  exportedItem.hasRefsInFile ||
160
160
  exportedItem.isRegistered ||
@@ -195,7 +195,10 @@ export const analyze = async ({ analyzedFiles, counselor, chief, collector, depu
195
195
  for (const extImport of file.imports.external) {
196
196
  const packageName = getPackageNameFromModuleSpecifier(extImport.specifier);
197
197
  const isHandled = packageName &&
198
- deputy.maybeAddReferencedExternalDependency(ws, packageName, undefined, extImport.isTypeOnly, extImport.filePath !== undefined);
198
+ deputy.maybeAddReferencedExternalDependency(ws, packageName, {
199
+ isTypeOnly: extImport.isTypeOnly,
200
+ isResolved: extImport.filePath !== undefined,
201
+ });
199
202
  if (!isHandled)
200
203
  collector.addIssue({
201
204
  type: 'unlisted',
@@ -1,3 +1,4 @@
1
+ import type { ScriptParserContext } from '../binaries/create-script-parser-context.ts';
1
2
  import type { CatalogCounselor } from '../CatalogCounselor.ts';
2
3
  import type { ConfigurationChief, Workspace } from '../ConfigurationChief.ts';
3
4
  import type { ConsoleStreamer } from '../ConsoleStreamer.ts';
@@ -13,11 +14,12 @@ interface BuildOptions {
13
14
  deputy: DependencyDeputy;
14
15
  principal: ProjectPrincipal;
15
16
  isGitIgnored: (path: string) => boolean;
17
+ scriptParserContext: ScriptParserContext;
16
18
  streamer: ConsoleStreamer;
17
19
  workspaces: Workspace[];
18
20
  options: MainOptions;
19
21
  }
20
- export declare function build({ chief, collector, counselor, deputy, principal, isGitIgnored, streamer, workspaces, options, }: BuildOptions): Promise<{
22
+ export declare function build({ chief, collector, counselor, deputy, principal, isGitIgnored, scriptParserContext, streamer, workspaces, options, }: BuildOptions): Promise<{
21
23
  graph: ModuleGraph;
22
24
  entryPaths: Set<string>;
23
25
  analyzedFiles: Set<string>;
@@ -9,9 +9,10 @@ import picomatch from 'picomatch';
9
9
  import { tryRealpath } from '../util/fs.js';
10
10
  import { createManifest } from '../util/package-json.js';
11
11
  import { _glob, _syncGlob, negate, prependDirToPattern as prependDir } from '../util/glob.js';
12
- import { isAlias, isConfig, isDeferResolveEntry, isDeferResolveProductionEntry, isEntry, isIgnore, isProductionEntry, isProject, toProductionEntry, } from '../util/input.js';
12
+ import { isAlias, isCatalog, isConfig, isDeferResolveEntry, isDeferResolveProductionEntry, isEntry, isIgnore, isProductionEntry, isProject, toProductionEntry, } from '../util/input.js';
13
13
  import { isAmbientDeclarationFile } from '../typescript/ast-nodes.js';
14
14
  import { resolveImportGlobs } from '../typescript/glob-imports.js';
15
+ import { createPublishedTypeDependencyAnalyzer } from '../typescript/get-published-type-dependencies.js';
15
16
  import { loadTSConfig } from '../util/load-tsconfig.js';
16
17
  import { createFileNode, updateImportMap } from '../util/module-graph.js';
17
18
  import { getPackageNameFromModuleSpecifier, isStartsLikePackageName, sanitizeSpecifier } from '../util/modules.js';
@@ -21,7 +22,7 @@ import { dirname, extname, isAbsolute, isInNodeModules, join, relative } from '.
21
22
  import { extensionAlias } from '../util/resolve.js';
22
23
  import { augmentWorkspace, getToSourcePathsHandler, toSourceMappedSpecifiers } from '../util/to-source-path.js';
23
24
  import { WorkspaceWorker } from '../WorkspaceWorker.js';
24
- export async function build({ chief, collector, counselor, deputy, principal, isGitIgnored, streamer, workspaces, options, }) {
25
+ export async function build({ chief, collector, counselor, deputy, principal, isGitIgnored, scriptParserContext, streamer, workspaces, options, }) {
25
26
  const configFilesMap = new Map();
26
27
  const enabledPluginsStore = new Map();
27
28
  const registeredVisitorPlugins = new Set();
@@ -29,19 +30,10 @@ export async function build({ chief, collector, counselor, deputy, principal, is
29
30
  const addIssue = (issue) => collector.addIssue(issue) && options.isWatch && collector.retainIssue(issue);
30
31
  const externalRefsFromInputs = options.isSession ? new Map() : undefined;
31
32
  const handleInput = createInputHandler(deputy, chief, isGitIgnored, addIssue, externalRefsFromInputs, options);
32
- const rawRootManifest = chief.getManifestForWorkspace('.');
33
- const rootManifest = rawRootManifest ? createManifest(rawRootManifest) : undefined;
34
- const manifestsByWorkspaceName = new Map();
35
- const getManifest = (dir) => {
36
- const workspace = chief.findWorkspaceByFilePath(`${dir}/`);
37
- if (!workspace)
38
- return undefined;
39
- if (!manifestsByWorkspaceName.has(workspace.name)) {
40
- const raw = chief.getManifestForWorkspace(workspace.name);
41
- manifestsByWorkspaceName.set(workspace.name, raw ? createManifest(raw) : undefined);
42
- }
43
- return manifestsByWorkspaceName.get(workspace.name);
44
- };
33
+ const getPublishedTypeDependencies = options.isReportDependencies
34
+ ? createPublishedTypeDependencyAnalyzer()
35
+ : undefined;
36
+ const { rootManifest, getManifest } = scriptParserContext;
45
37
  for (const workspace of workspaces) {
46
38
  const { name, dir, manifestPath, manifestStr } = workspace;
47
39
  const manifest = chief.getManifestForWorkspace(name);
@@ -56,7 +48,6 @@ export async function build({ chief, collector, counselor, deputy, principal, is
56
48
  manifest,
57
49
  ...chief.getIgnores(name),
58
50
  });
59
- counselor.addWorkspace(manifest);
60
51
  }
61
52
  deputy.setWorkspacePkgNames(chief.availableWorkspacePkgNames);
62
53
  collector.addIgnorePatterns(chief.config.ignore.map(id => ({ pattern: prependDir(options.cwd, id), id })));
@@ -65,13 +56,12 @@ export async function build({ chief, collector, counselor, deputy, principal, is
65
56
  principal.addEntryPath(options.configFilePath, { skipExportsAnalysis: true });
66
57
  }
67
58
  for (const workspace of workspaces) {
68
- const { name, dir, ancestors, manifestPath: filePath } = workspace;
59
+ const { name, dir, ancestors, config: baseConfig, manifestPath: filePath } = workspace;
69
60
  streamer.cast('Analyzing workspace', name);
70
61
  const manifest = chief.getManifestForWorkspace(name);
71
62
  if (!manifest)
72
63
  continue;
73
64
  const dependencies = deputy.getDependencies(name);
74
- const baseConfig = chief.getConfigForWorkspace(name);
75
65
  const tsConfigFilePath = join(dir, options.tsConfigFile ?? 'tsconfig.json');
76
66
  const { isFile, compilerOptions, fileNames, include, exclude, sourceMapPairs, paths: tsConfigPaths, } = await loadTSConfig(tsConfigFilePath);
77
67
  const [definitionPaths, tscSourcePaths] = partition(fileNames, filePath => IS_DTS.test(filePath));
@@ -124,6 +114,28 @@ export async function build({ chief, collector, counselor, deputy, principal, is
124
114
  if (!isGitIgnored(filePath))
125
115
  inputs.add(toProductionEntry(filePath));
126
116
  }
117
+ if (getPublishedTypeDependencies && !manifest.private && !manifest.publishConfig?.directory) {
118
+ for (const dependency of getPublishedTypeDependencies(workspace, manifest)) {
119
+ const isHandled = deputy.maybeAddReferencedExternalDependency(workspace, dependency.packageName, {
120
+ isTypeOnly: true,
121
+ isResolved: dependency.isResolved,
122
+ isPublishedType: true,
123
+ });
124
+ if (!isHandled) {
125
+ addIssue({
126
+ type: 'unlisted',
127
+ filePath: dependency.containingFilePath,
128
+ workspace: name,
129
+ symbol: dependency.packageName,
130
+ specifier: dependency.specifier,
131
+ pos: dependency.pos,
132
+ line: dependency.line,
133
+ col: dependency.col,
134
+ fixes: [],
135
+ });
136
+ }
137
+ }
138
+ }
127
139
  for (const identifier of entrySpecifiersFromManifest) {
128
140
  if (identifier.startsWith('!') || isGitIgnored(join(dir, identifier)))
129
141
  continue;
@@ -175,7 +187,10 @@ export async function build({ chief, collector, counselor, deputy, principal, is
175
187
  if (input.group)
176
188
  groups.add(input.group);
177
189
  const specifier = input.specifier;
178
- if (isEntry(input)) {
190
+ if (isCatalog(input)) {
191
+ counselor.addReference({ catalogName: input.catalogName, packageName: specifier });
192
+ }
193
+ else if (isEntry(input)) {
179
194
  const targetMap = input.skipExportsAnalysis ? entryPatternsSkipExports : entryPatterns;
180
195
  addPattern(targetMap, input, toWorkspaceRelative(specifier));
181
196
  }
@@ -390,6 +405,10 @@ export async function build({ chief, collector, counselor, deputy, principal, is
390
405
  };
391
406
  const inputs = _getInputsFromScripts(file.scripts, opts);
392
407
  for (const input of inputs) {
408
+ if (isCatalog(input)) {
409
+ counselor.addReference({ catalogName: input.catalogName, packageName: input.specifier });
410
+ continue;
411
+ }
393
412
  input.containingFilePath ??= filePath;
394
413
  input.dir ??= dir;
395
414
  const specifierFilePath = handleInput(input, workspace);
@@ -1,3 +1,4 @@
1
+ import { substringBefore } from '../../util/string.js';
1
2
  import { CONTINUE } from '../constants.js';
2
3
  import { walkDown } from '../walk-down.js';
3
4
  export const buildExportsTree = (graph, entryPaths, options) => {
@@ -38,7 +39,7 @@ const buildExportTree = (graph, entryPaths, filePath, identifier) => {
38
39
  walkDown(graph, filePath, identifier, (sourceFile, sourceId, importingFile, id, isEntry, via) => {
39
40
  const importMaps = graph.get(importingFile)?.imports.internal.get(sourceFile);
40
41
  const importRefs = importMaps?.refs;
41
- const ns = id.split('.')[0];
42
+ const ns = substringBefore(id, '.');
42
43
  if (via === 'importNS' && !hasRelevantRef(importRefs, id) && !isNsReExported(importMaps, ns))
43
44
  return CONTINUE;
44
45
  const key = `${importingFile}:${id}`;
@@ -1,4 +1,4 @@
1
- import { OPAQUE } from '../../constants.js';
1
+ import { LOADER_DEFAULT, OPAQUE } from '../../constants.js';
2
2
  import { getAliasReExportMap, getNamespaceReExportSources, getPassThroughReExportSources, getStarReExportSources, } from '../visitors.js';
3
3
  const hasOnlyNsRefs = (file) => {
4
4
  if (file.importNs.size === 0)
@@ -33,8 +33,9 @@ export const isReferenced = (graph, entryPaths, filePath, id, options) => {
33
33
  isReferenced = true;
34
34
  return hasCompleteResult();
35
35
  }
36
- const file = graph.get(path)?.importedBy;
37
- if (!identifier || !file) {
36
+ const node = graph.get(path);
37
+ const file = node?.importedBy;
38
+ if (!identifier || !node || !file) {
38
39
  return false;
39
40
  }
40
41
  const follow = (sources, nextId, nextViaStar = viaStar) => {
@@ -45,7 +46,9 @@ export const isReferenced = (graph, entryPaths, filePath, id, options) => {
45
46
  return false;
46
47
  };
47
48
  if (!isReferenced) {
48
- const hasDirectReference = (file.import.get(OPAQUE) && !hasOnlyNsRefs(file)) ||
49
+ const isLoaderImport = file.import.has(LOADER_DEFAULT);
50
+ const hasDirectReference = ((file.import.get(OPAQUE) || (isLoaderImport && !node.exports.has('default'))) && !hasOnlyNsRefs(file)) ||
51
+ (isLoaderImport && identifier === 'default') ||
49
52
  ((identifier === id || (identifier !== id && file.refs.has(id))) &&
50
53
  (file.import.has(identifier) || file.importAs.has(identifier)));
51
54
  if (hasDirectReference) {
@@ -1,4 +1,4 @@
1
- import { IMPORT_FLAGS, IMPORT_STAR, OPAQUE, SIDE_EFFECTS } from '../constants.js';
1
+ import { IMPORT_FLAGS, IMPORT_STAR, LOADER_DEFAULT, OPAQUE, SIDE_EFFECTS } from '../constants.js';
2
2
  import { getCachedExportedIdentifiers, setCachedExportedIdentifiers } from './cache.js';
3
3
  import { forEachAliasReExport, forEachNamespaceReExport, forEachPassThroughReExport, getStarReExportSources, } from './visitors.js';
4
4
  const IGNORED_CYCLE_IMPORT_FLAGS = IMPORT_FLAGS.ENTRY | IMPORT_FLAGS.DYNAMIC;
@@ -79,7 +79,7 @@ const getImportKind = (importMaps, identifier, modifiers) => {
79
79
  return 'importNS';
80
80
  if (identifier && importMaps.importAs.has(identifier))
81
81
  return 'importAs';
82
- if (identifier === OPAQUE)
82
+ if (identifier === OPAQUE || identifier === LOADER_DEFAULT)
83
83
  return 'dynamicImport';
84
84
  if (identifier === SIDE_EFFECTS)
85
85
  return 'sideEffectImport';
@@ -8,7 +8,7 @@ const entry = [];
8
8
  const production = [];
9
9
  const resolveConfig = async (config) => {
10
10
  const inputs = config?.plugins ?? [];
11
- return [...inputs].map(id => toDeferResolve(id));
11
+ return Array.from(inputs, id => toDeferResolve(id));
12
12
  };
13
13
  const plugin = {
14
14
  title,
@@ -1,17 +1,18 @@
1
1
  import { toProductionEntry } from '../../util/input.js';
2
2
  import { hasDependency } from '../../util/plugin.js';
3
+ import { substringBefore } from '../../util/string.js';
3
4
  const title = 'Astro Markdoc';
4
5
  const enablers = ['@astrojs/markdoc'];
5
6
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
6
7
  const config = ['markdoc.config.{js,ts,mjs,mts}'];
7
8
  const extractSpecifiers = (renderField) => {
8
9
  if (typeof renderField === 'string') {
9
- return [renderField.split('#')[0]];
10
+ return [substringBefore(renderField, '#')];
10
11
  }
11
12
  if (renderField && typeof renderField === 'object') {
12
13
  for (const key of ['Component', 'file', 'path']) {
13
14
  if (typeof renderField[key] === 'string') {
14
- return [renderField[key].split('#')[0]];
15
+ return [substringBefore(renderField[key], '#')];
15
16
  }
16
17
  }
17
18
  }
@@ -17,7 +17,7 @@ const resolveConfig = async (localConfig, options) => {
17
17
  const inputDir = localConfig?.dir?.input || defaultEleventyConfig.dir.input;
18
18
  const dataDir = localConfig?.dir?.data || defaultEleventyConfig.dir.data;
19
19
  const templateFormats = localConfig?.templateFormats || defaultEleventyConfig.templateFormats;
20
- const exts = [...DEFAULT_EXTENSIONS].map(extname => extname.slice(1)).join(',');
20
+ const exts = Array.from(DEFAULT_EXTENSIONS, extname => extname.slice(1)).join(',');
21
21
  const copiedEntries = new Set();
22
22
  const copiedPackages = new Set();
23
23
  for (const path of Object.keys(dummyUserConfig.passthroughCopies)) {
@@ -6,7 +6,7 @@ const title = 'esbuild';
6
6
  const enablers = ['esbuild'];
7
7
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
8
8
  const config = ['esbuild.config.{js,mjs,cjs,ts,mts,cts}', 'esbuild.{js,mjs,cjs,ts,mts,cts}'];
9
- const resolveFromAST = (program, { configFileDir }) => [...collectPropertyValues(program, 'entryPoints')].map(id => toProductionEntry(join(configFileDir, id)));
9
+ const resolveFromAST = (program, { configFileDir }) => Array.from(collectPropertyValues(program, 'entryPoints'), id => toProductionEntry(join(configFileDir, id)));
10
10
  const plugin = {
11
11
  title,
12
12
  enablers,
@@ -2,6 +2,7 @@ import { compact } from '../../util/array.js';
2
2
  import { toConfig, toDeferResolve, toDependency } from '../../util/input.js';
3
3
  import { getPackageNameFromFilePath, getPackageNameFromModuleSpecifier } from '../../util/modules.js';
4
4
  import { extname, isAbsolute, isInternal } from '../../util/path.js';
5
+ import { substringBefore } from '../../util/string.js';
5
6
  import { getDependenciesFromConfig } from '../babel/index.js';
6
7
  export const isFlatConfig = (fileName) => /eslint\.config/.test(fileName);
7
8
  export const getInputs = (config, options) => {
@@ -41,7 +42,7 @@ const resolveSpecifier = (namespace, rawSpecifier) => {
41
42
  if (!specifier.startsWith('@')) {
42
43
  const id = rawSpecifier.startsWith('plugin:')
43
44
  ? getPackageNameFromModuleSpecifier(specifier)
44
- : specifier.split('/')[0];
45
+ : substringBefore(specifier, '/');
45
46
  return `${namespace}-${id}`;
46
47
  }
47
48
  const [scope, name, ...rest] = specifier.split('/');
@@ -14,12 +14,12 @@ const production = [
14
14
  ];
15
15
  const resolveConfig = async (localConfig, options) => {
16
16
  const { configFileName } = options;
17
- if (/gatsby-config/.test(configFileName)) {
17
+ if (configFileName.includes('gatsby-config')) {
18
18
  return localConfig.plugins
19
19
  .map(plugin => (typeof plugin === 'string' ? plugin : plugin.resolve))
20
20
  .map(id => toDeferResolve(id));
21
21
  }
22
- if (/gatsby-node/.test(configFileName)) {
22
+ if (configFileName.includes('gatsby-node')) {
23
23
  const plugins = new Set();
24
24
  const actions = { setBabelPlugin: plugin => plugins.add(plugin.name) };
25
25
  const _config = localConfig;
@@ -35,7 +35,7 @@ export const getReportersDependencies = (config, options) => {
35
35
  const reporters = config.reporters
36
36
  ? config.reporters
37
37
  .map(reporter => (typeof reporter === 'string' ? reporter : reporter[0]))
38
- .filter(reporter => !['default', 'github-actions', 'summary'].includes(reporter))
38
+ .filter(reporter => reporter !== 'default' && reporter !== 'github-actions' && reporter !== 'summary')
39
39
  : [];
40
40
  return [...reporters, ...jUnitReporterDeps];
41
41
  };
@@ -41,7 +41,7 @@ const resolveConfig = async (config) => {
41
41
  inputs.push(transformer.minifierPath);
42
42
  if (transformer?.babelTransformerPath)
43
43
  inputs.push(transformer.babelTransformerPath);
44
- return Array.from(i).concat([...inputs].map(id => toDeferResolve(id, {
44
+ return Array.from(i).concat(Array.from(inputs, id => toDeferResolve(id, {
45
45
  optional: id === DEFAULT_TRANSFORMER_PACKAGE || id === DEFAULT_MINIFIER_PACKAGE,
46
46
  })));
47
47
  };
@@ -6,7 +6,7 @@ const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
6
6
  const config = ['nest-cli.json', '.nestcli.json', '.nest-cli.json', 'nest.json'];
7
7
  const resolveConfig = async (config) => {
8
8
  const inputs = config?.collection ? [config.collection] : [];
9
- return [...inputs].map(id => toDependency(id));
9
+ return Array.from(inputs, id => toDependency(id));
10
10
  };
11
11
  const plugin = {
12
12
  title,
@@ -8,9 +8,18 @@ const patterns = [
8
8
  '**/test.{cjs,mjs,js,cts,mts,ts}',
9
9
  '**/test/**/*.{cjs,mjs,js,cts,mts,ts}',
10
10
  ];
11
- const hasNodeTest = (scripts) => scripts &&
12
- Object.values(scripts).some(script => typeof script === 'string' &&
11
+ const hasNodeTestCache = new WeakMap();
12
+ const hasNodeTest = (scripts) => {
13
+ if (!scripts)
14
+ return false;
15
+ const cached = hasNodeTestCache.get(scripts);
16
+ if (cached !== undefined)
17
+ return cached;
18
+ const result = Object.values(scripts).some(script => typeof script === 'string' &&
13
19
  getScriptCommands(script).some(({ binary, args }) => (binary === 'node' || binary === 'nub') && args.includes('--test')));
20
+ hasNodeTestCache.set(scripts, result);
21
+ return result;
22
+ };
14
23
  const entry = ['server.js'];
15
24
  const resolve = options => {
16
25
  const entries = entry.map(id => toProductionEntry(id));
@@ -2,6 +2,7 @@ import { compact } from '../../util/array.js';
2
2
  import { toConfig, toDependency } from '../../util/input.js';
3
3
  import { join } from '../../util/path.js';
4
4
  import { hasDependency } from '../../util/plugin.js';
5
+ import { substringBefore } from '../../util/string.js';
5
6
  const title = 'Nx';
6
7
  const enablers = ['nx', /^@nrwl\//, /^@nx\//];
7
8
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
@@ -10,7 +11,7 @@ const findNxDependenciesInNxJson = async (localConfig) => {
10
11
  const targetsDefault = localConfig.targetDefaults
11
12
  ? Object.keys(localConfig.targetDefaults)
12
13
  .filter(it => it.includes(':') && it.startsWith('@'))
13
- .map(it => it.split(':')[0])
14
+ .map(it => substringBefore(it, ':'))
14
15
  : [];
15
16
  const plugins = localConfig.plugins && Array.isArray(localConfig.plugins)
16
17
  ? localConfig.plugins
@@ -20,7 +21,7 @@ const findNxDependenciesInNxJson = async (localConfig) => {
20
21
  const generators = localConfig.generators
21
22
  ? Object.keys(localConfig.generators)
22
23
  .filter(value => value !== undefined)
23
- .map(value => value.split(':')[0])
24
+ .map(value => substringBefore(value, ':'))
24
25
  : [];
25
26
  return compact([...targetsDefault, ...plugins, ...generators]).map(id => toDependency(id));
26
27
  };
@@ -34,7 +35,7 @@ const resolveConfig = async (localConfig, options) => {
34
35
  const executors = targets
35
36
  .map(target => target?.executor)
36
37
  .filter(executor => executor && !executor.startsWith('.'))
37
- .map(executor => executor?.split(':')[0]);
38
+ .map(executor => executor && substringBefore(executor, ':'));
38
39
  const expand = (value) => value.replaceAll('{projectRoot}', options.configFileDir).replaceAll('{workspaceRoot}', options.rootCwd);
39
40
  const resolveTargetCwd = (targetCwd) => {
40
41
  if (!targetCwd)
@@ -38,7 +38,7 @@ const resolveFromAST = (_, options) => {
38
38
  return [];
39
39
  const sourceText = options.readFile(options.configFilePath).replace(/^\uFEFF/, '');
40
40
  const { program } = _parseFile(`${options.configFilePath}.ts`, `(${sourceText}\n)`);
41
- return [...collectPropertyValues(program, 'providerCatalogEntry')].map(entry => toProductionEntry(entry));
41
+ return Array.from(collectPropertyValues(program, 'providerCatalogEntry'), entry => toProductionEntry(entry));
42
42
  };
43
43
  const plugin = {
44
44
  title,
@@ -38,9 +38,16 @@ const resolveFromAST = (program, options) => {
38
38
  const visitor = new Visitor({
39
39
  ObjectExpression(node) {
40
40
  const lint = findProperty(node, 'lint');
41
- if (lint?.type === 'ObjectExpression')
42
- for (const specifier of getPropertyValues(lint, 'jsPlugins'))
41
+ if (lint?.type !== 'ObjectExpression')
42
+ return;
43
+ for (const specifier of getPropertyValues(lint, 'jsPlugins'))
44
+ jsPlugins.add(specifier);
45
+ for (const plugin of findProperty(lint, 'jsPlugins')?.elements ?? []) {
46
+ if (plugin?.type !== 'ObjectExpression')
47
+ continue;
48
+ for (const specifier of getPropertyValues(plugin, 'specifier'))
43
49
  jsPlugins.add(specifier);
50
+ }
44
51
  },
45
52
  });
46
53
  visitor.visit(program);
@@ -0,0 +1,3 @@
1
+ import { type Input } from '../../util/input.ts';
2
+ import type { Manifest } from '../../util/package-json.ts';
3
+ export declare const resolveLoadPluginStylePluginName: (prefix: string, identifier: string, manifest: Manifest) => Input;
@@ -0,0 +1,42 @@
1
+ import { toDeferResolve, toDependency } from '../../util/input.js';
2
+ import { isInternal } from '../../util/path.js';
3
+ const getCandidates = (prefix, identifier) => {
4
+ if (isInternal(identifier))
5
+ return [identifier];
6
+ if (identifier.startsWith('@')) {
7
+ const [scope, name, ...rest] = identifier.split('/');
8
+ if (rest.length > 0)
9
+ return [identifier];
10
+ if (scope) {
11
+ if (!name)
12
+ return [[scope, prefix].join('/')];
13
+ if (name.startsWith(prefix))
14
+ return [identifier];
15
+ return [[scope, prefix + name].join('/'), identifier];
16
+ }
17
+ }
18
+ const [name, ...rest] = identifier.split('/');
19
+ if (rest.length > 0)
20
+ return [identifier];
21
+ if (name.startsWith(prefix))
22
+ return [identifier];
23
+ return [prefix + name, name];
24
+ };
25
+ const getDeclaredDependencies = (manifest) => new Set([
26
+ ...Object.keys(manifest.dependencies ?? {}),
27
+ ...Object.keys(manifest.devDependencies ?? {}),
28
+ ...Object.keys(manifest.optionalDependencies ?? {}),
29
+ ...Object.keys(manifest.peerDependencies ?? {}),
30
+ ]);
31
+ const pickCandidate = (prefix, identifier, manifest) => {
32
+ const candidates = getCandidates(prefix, identifier);
33
+ if (candidates.length === 1 || isInternal(candidates[0]))
34
+ return candidates[0];
35
+ const dependencies = getDeclaredDependencies(manifest);
36
+ return candidates.find(candidate => dependencies.has(candidate)) ?? candidates[0];
37
+ };
38
+ export const resolveLoadPluginStylePluginName = (prefix, identifier, manifest) => {
39
+ prefix = prefix + (prefix.at(-1) === '-' ? '' : '-');
40
+ const candidate = pickCandidate(prefix, identifier, manifest);
41
+ return isInternal(candidate) ? toDeferResolve(candidate) : toDependency(candidate);
42
+ };
@@ -1,12 +1,11 @@
1
- import { toDeferResolve } from '../../util/input.js';
2
- import { isInternal } from '../../util/path.js';
3
1
  import { hasDependency } from '../../util/plugin.js';
2
+ import { resolveLoadPluginStylePluginName } from './helpers.js';
4
3
  const title = 'Remark';
5
4
  const enablers = ['remark-cli'];
6
5
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
7
6
  const packageJsonPath = 'remarkConfig';
8
7
  const config = ['package.json', '.remarkrc', '.remarkrc.json', '.remarkrc.{js,cjs,mjs}', '.remarkrc.{yml,yaml}'];
9
- const resolveConfig = config => {
8
+ const resolveConfig = (config, options) => {
10
9
  const plugins = config.plugins
11
10
  ?.flatMap(plugin => {
12
11
  if (typeof plugin === 'string')
@@ -15,8 +14,8 @@ const resolveConfig = config => {
15
14
  return plugin[0];
16
15
  return [];
17
16
  })
18
- .map(plugin => (isInternal(plugin) ? plugin : plugin.startsWith('remark-') ? plugin : `remark-${plugin}`)) ?? [];
19
- return plugins.map(id => toDeferResolve(id));
17
+ .map(plugin => resolveLoadPluginStylePluginName('remark-', plugin, options.manifest)) ?? [];
18
+ return plugins;
20
19
  };
21
20
  const plugin = {
22
21
  title,
@@ -5,7 +5,7 @@ const title = 'Rolldown';
5
5
  const enablers = ['rolldown'];
6
6
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
7
7
  const config = ['rolldown.config.{js,cjs,mjs,ts,cts,mts}'];
8
- const resolveFromAST = program => [...collectPropertyValues(program, 'input')].map(id => toProductionEntry(id));
8
+ const resolveFromAST = program => Array.from(collectPropertyValues(program, 'input'), id => toProductionEntry(id));
9
9
  const plugin = {
10
10
  title,
11
11
  enablers,
@@ -11,7 +11,7 @@ const args = {
11
11
  fromArgs: ['_exec'],
12
12
  resolve: ['plugin', 'configPlugin'],
13
13
  };
14
- const resolveFromAST = program => [...collectPropertyValues(program, 'input')].map(id => toProductionEntry(id));
14
+ const resolveFromAST = program => Array.from(collectPropertyValues(program, 'input'), id => toProductionEntry(id));
15
15
  const plugin = {
16
16
  title,
17
17
  enablers,
@@ -5,7 +5,7 @@ const title = 'Rslib';
5
5
  const enablers = ['@rslib/core'];
6
6
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
7
7
  const config = ['rslib*.config.{mjs,ts,js,cjs,mts,cts}'];
8
- const resolveFromAST = program => [...collectPropertyValues(program, 'entry')].map(id => toProductionEntry(id, { allowIncludeExports: true }));
8
+ const resolveFromAST = program => Array.from(collectPropertyValues(program, 'entry'), id => toProductionEntry(id, { allowIncludeExports: true }));
9
9
  const plugin = {
10
10
  title,
11
11
  enablers,
@@ -1,4 +1,4 @@
1
- import { toDeferResolve } from '../../util/input.js';
1
+ import { toConfig, toDeferResolve } from '../../util/input.js';
2
2
  import { hasDependency } from '../../util/plugin.js';
3
3
  const title = 'Stryker';
4
4
  const enablers = ['@stryker-mutator/core'];
@@ -12,11 +12,16 @@ const resolveConfig = localConfig => {
12
12
  const plugins = localConfig.plugins ?? [];
13
13
  return [...runners, ...checkers, ...plugins].map(id => toDeferResolve(id));
14
14
  };
15
+ const args = {
16
+ boolean: ['allowEmpty', 'disableBail', 'dryRunOnly', 'force', 'ignoreStatic', 'incremental', 'inPlace'],
17
+ resolveInputs: parsed => (parsed._[0] === 'run' && parsed._[1] ? [toConfig('stryker', parsed._[1])] : []),
18
+ };
15
19
  const plugin = {
16
20
  title,
17
21
  enablers,
18
22
  isEnabled,
19
23
  config,
20
24
  resolveConfig,
25
+ args,
21
26
  };
22
27
  export default plugin;
@@ -1,10 +1,12 @@
1
1
  import { importsWithinScripts } from '../../compilers/compilers.js';
2
2
  import { stylePreprocessorImports } from '../../compilers/style-preprocessors.js';
3
+ import { dynamicImportsWithinTemplate } from '../../compilers/svelte.js';
3
4
  const compiler = (text, path) => {
4
- const scripts = importsWithinScripts(text, path);
5
- const styles = stylePreprocessorImports(text, path);
6
- if (!scripts)
7
- return styles;
8
- return styles ? `${scripts};\n${styles}` : scripts;
5
+ const parts = [
6
+ importsWithinScripts(text, path),
7
+ dynamicImportsWithinTemplate(text, path),
8
+ stylePreprocessorImports(text, path),
9
+ ];
10
+ return parts.filter(Boolean).join(';\n');
9
11
  };
10
12
  export default compiler;