knip 6.41.0 → 6.42.1

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 (71) hide show
  1. package/README.md +1 -1
  2. package/dist/ConfigurationChief.d.ts +18 -0
  3. package/dist/WorkspaceWorker.js +1 -0
  4. package/dist/binaries/bash-parser.js +16 -39
  5. package/dist/binaries/resolvers/bun.js +1 -0
  6. package/dist/compilers/scss.js +2 -22
  7. package/dist/compilers/shared.d.ts +1 -1
  8. package/dist/compilers/shared.js +24 -1
  9. package/dist/constants.js +1 -0
  10. package/dist/graph-explorer/operations/is-referenced.js +8 -2
  11. package/dist/manifest/index.js +2 -3
  12. package/dist/plugins/_component-style-urls/component-style-urls-visitor.d.ts +2 -0
  13. package/dist/plugins/_component-style-urls/component-style-urls-visitor.js +40 -0
  14. package/dist/plugins/angular/index.js +7 -1
  15. package/dist/plugins/biome/index.js +2 -2
  16. package/dist/plugins/bun/index.js +13 -0
  17. package/dist/plugins/commitlint/index.js +2 -2
  18. package/dist/plugins/eslint/helpers.js +1 -1
  19. package/dist/plugins/filesystem-routing/index.d.ts +3 -0
  20. package/dist/plugins/filesystem-routing/index.js +57 -0
  21. package/dist/plugins/github-actions/index.js +1 -1
  22. package/dist/plugins/index.d.ts +3 -0
  23. package/dist/plugins/index.js +6 -0
  24. package/dist/plugins/jest/index.js +16 -7
  25. package/dist/plugins/jest/visitors/mock.d.ts +2 -0
  26. package/dist/plugins/jest/visitors/mock.js +91 -0
  27. package/dist/plugins/mise/scripts.js +55 -97
  28. package/dist/plugins/next/index.js +33 -1
  29. package/dist/plugins/nx/index.js +46 -8
  30. package/dist/plugins/nx/types.d.ts +8 -0
  31. package/dist/plugins/oxlint/index.js +1 -1
  32. package/dist/plugins/react-router/index.d.ts +3 -0
  33. package/dist/plugins/react-router/index.js +3 -0
  34. package/dist/plugins/rstest/index.js +1 -1
  35. package/dist/plugins/semantic-release/index.js +32 -3
  36. package/dist/plugins/semantic-release/types.d.ts +1 -0
  37. package/dist/plugins/solidjs-vite-plugin/index.d.ts +6 -0
  38. package/dist/plugins/solidjs-vite-plugin/index.js +17 -0
  39. package/dist/plugins/solidjs-vite-plugin/resolveFromAST.d.ts +3 -0
  40. package/dist/plugins/solidjs-vite-plugin/resolveFromAST.js +76 -0
  41. package/dist/plugins/sst/resolveFromAST.js +1 -1
  42. package/dist/plugins/stencil/index.js +2 -39
  43. package/dist/plugins/storybook/index.js +2 -4
  44. package/dist/plugins/sveltejs-package/helpers.js +2 -2
  45. package/dist/plugins/tailwind/compiler.js +10 -2
  46. package/dist/plugins/taskfile/index.js +3 -6
  47. package/dist/plugins/tsrs/index.d.ts +3 -0
  48. package/dist/plugins/tsrs/index.js +15 -0
  49. package/dist/plugins/typescript/index.d.ts +12 -1
  50. package/dist/plugins/typescript/index.js +5 -7
  51. package/dist/plugins/vite/helpers.d.ts +1 -0
  52. package/dist/plugins/vite/helpers.js +15 -1
  53. package/dist/plugins/vitest/index.js +4 -4
  54. package/dist/schema/configuration.d.ts +45 -0
  55. package/dist/schema/plugins.d.ts +15 -0
  56. package/dist/schema/plugins.js +3 -0
  57. package/dist/types/PluginNames.d.ts +2 -2
  58. package/dist/types/PluginNames.js +3 -0
  59. package/dist/types/config.d.ts +1 -0
  60. package/dist/typescript/visitors/imports.js +11 -0
  61. package/dist/typescript/visitors/jsdoc.js +27 -22
  62. package/dist/util/create-options.d.ts +30 -0
  63. package/dist/util/create-options.js +2 -3
  64. package/dist/util/path.d.ts +1 -0
  65. package/dist/util/path.js +1 -0
  66. package/dist/util/scripts.d.ts +3 -2
  67. package/dist/util/scripts.js +32 -72
  68. package/dist/version.d.ts +1 -1
  69. package/dist/version.js +1 -1
  70. package/package.json +5 -5
  71. package/schema.json +12 -0
@@ -0,0 +1,91 @@
1
+ import { IMPORT_FLAGS } from '../../../constants.js';
2
+ import { getPropertyKey } from '../../../typescript/ast-helpers.js';
3
+ import { getStringValue, isStringLiteral } from '../../../typescript/ast-nodes.js';
4
+ import { isShadowed } from '../../../typescript/visitors/walk.js';
5
+ const mockMethods = new Set([
6
+ 'mock',
7
+ 'doMock',
8
+ 'requireActual',
9
+ 'requireMock',
10
+ 'createMockFromModule',
11
+ 'unmock',
12
+ 'dontMock',
13
+ 'deepUnmock',
14
+ 'setMock',
15
+ 'unstable_mockModule',
16
+ 'unstable_unmockModule',
17
+ ]);
18
+ export function createJestMockVisitor(ctx) {
19
+ const jestNames = new Set();
20
+ const virtualMocks = new Set();
21
+ const virtualEsmMocks = new Set();
22
+ const mockLookups = [];
23
+ return {
24
+ Program(node) {
25
+ jestNames.clear();
26
+ virtualMocks.clear();
27
+ virtualEsmMocks.clear();
28
+ mockLookups.length = 0;
29
+ jestNames.add('jest');
30
+ for (const statement of node.body) {
31
+ if (statement.type !== 'ImportDeclaration' ||
32
+ !isStringLiteral(statement.source) ||
33
+ getStringValue(statement.source) !== '@jest/globals')
34
+ continue;
35
+ for (const specifier of statement.specifiers ?? []) {
36
+ if (specifier.type === 'ImportSpecifier' &&
37
+ specifier.imported.type === 'Identifier' &&
38
+ specifier.imported.name === 'jest') {
39
+ jestNames.add(specifier.local.name);
40
+ }
41
+ }
42
+ }
43
+ },
44
+ CallExpression(node) {
45
+ const argument = node.arguments[0];
46
+ const callee = node.callee;
47
+ if (!isStringLiteral(argument) ||
48
+ callee.type !== 'MemberExpression' ||
49
+ callee.computed ||
50
+ callee.object.type !== 'Identifier' ||
51
+ !jestNames.has(callee.object.name) ||
52
+ isShadowed(callee.object.name, callee.object.start) ||
53
+ callee.property.type !== 'Identifier' ||
54
+ !mockMethods.has(callee.property.name))
55
+ return;
56
+ const specifier = getStringValue(argument);
57
+ const method = callee.property.name;
58
+ const options = node.arguments[2];
59
+ if ((method === 'mock' || method === 'doMock' || method === 'unstable_mockModule') &&
60
+ options?.type === 'ObjectExpression') {
61
+ for (const property of options.properties) {
62
+ if (property.type === 'Property' &&
63
+ !property.computed &&
64
+ getPropertyKey(property) === 'virtual' &&
65
+ property.value.type === 'Literal' &&
66
+ property.value.value === true) {
67
+ (method === 'unstable_mockModule' ? virtualEsmMocks : virtualMocks).add(specifier);
68
+ return;
69
+ }
70
+ }
71
+ }
72
+ if (method === 'requireActual' || method === 'createMockFromModule') {
73
+ const flags = method === 'requireActual' ? IMPORT_FLAGS.OPAQUE : IMPORT_FLAGS.SIDE_EFFECTS;
74
+ ctx.addImport(specifier, argument.start, flags);
75
+ return;
76
+ }
77
+ mockLookups.push({
78
+ specifier,
79
+ pos: argument.start,
80
+ isEsm: method === 'unstable_mockModule' || method === 'unstable_unmockModule',
81
+ });
82
+ },
83
+ 'Program:exit'() {
84
+ for (const { specifier, pos, isEsm } of mockLookups) {
85
+ if ((isEsm ? virtualEsmMocks : virtualMocks).has(specifier))
86
+ continue;
87
+ ctx.addImport(specifier, pos, IMPORT_FLAGS.SIDE_EFFECTS);
88
+ }
89
+ },
90
+ };
91
+ }
@@ -1,4 +1,4 @@
1
- import { parse } from 'unbash';
1
+ import { forEachChild, parse } from 'unbash';
2
2
  import { getDependenciesFromCommand, getInputsFromNodeOptions } from '../../binaries/command.js';
3
3
  import { spawningBinaries } from '../../binaries/fallback.js';
4
4
  import { isWrapper } from '../../binaries/plugins.js';
@@ -7,121 +7,79 @@ import { toScript } from '../../binaries/util.js';
7
7
  import { SCRIPT_INTERPOLATION } from '../../constants.js';
8
8
  import { isBinary } from '../../util/input.js';
9
9
  import { extractBinary, isRelativeNodeModulesBin } from '../../util/modules.js';
10
- import { walkCommands } from '../../util/scripts.js';
10
+ import { isScriptExpansion, collectCommands } from '../../util/scripts.js';
11
11
  export const getInputsFromMiseScript = (script, options, hasLocalBinPath) => {
12
12
  const inputs = [];
13
13
  const definedFunctions = new Set();
14
- const readParts = (parts) => {
14
+ const readCommand = (command, source) => {
15
15
  let text = '';
16
- let value = '';
17
- let hasExpansion = false;
18
- for (const part of parts) {
19
- if (part.type === 'CommandExpansion' || part.type === 'ProcessSubstitution') {
20
- if (part.script)
21
- readScript(part.script);
22
- text += SCRIPT_INTERPOLATION;
23
- value += SCRIPT_INTERPOLATION;
24
- hasExpansion = true;
16
+ let cursor = command.pos;
17
+ const visit = (node) => {
18
+ if (!isScriptExpansion(node)) {
19
+ forEachChild(node, visit);
20
+ return;
25
21
  }
26
- else if (part.type === 'DoubleQuoted' || part.type === 'LocaleString') {
27
- const inner = readParts(part.parts);
28
- text += `${part.type === 'LocaleString' ? '$"' : '"'}${inner.text}"`;
29
- value += inner.value;
30
- if (inner.hasExpansion)
31
- hasExpansion = true;
22
+ if (node.script)
23
+ readScript(node.script, node.script.source ?? source);
24
+ if (node.pos >= cursor && node.end <= command.end) {
25
+ text += source.slice(cursor, node.pos) + SCRIPT_INTERPOLATION;
26
+ cursor = node.end;
32
27
  }
33
- else {
34
- text += part.text;
35
- value += 'value' in part ? part.value : part.text;
36
- }
37
- }
38
- return { text, value, hasExpansion };
39
- };
40
- const readWord = (word) => {
41
- if (!word.parts)
42
- return word;
43
- const { text, value, hasExpansion } = readParts(word.parts);
44
- return hasExpansion ? { type: 'Word', pos: word.pos, end: word.end, text, value } : word;
45
- };
46
- const readAssignment = (assignment) => {
47
- const original = assignment.value;
48
- const value = original.type === 'Word'
49
- ? readWord(original)
50
- : { type: 'ArrayValue', pos: original.pos, end: original.end, elements: original.elements.map(readWord) };
51
- if (value === original)
52
- return assignment;
53
- const text = value.type === 'Word' ? value.text : `(${value.elements.map(word => word.text).join(' ')})`;
54
- return {
55
- type: 'Assignment',
56
- pos: assignment.pos,
57
- end: assignment.end,
58
- name: assignment.name,
59
- index: assignment.index,
60
- append: assignment.append,
61
- value,
62
- text: assignment.text.slice(0, original.pos - assignment.pos) + text,
63
28
  };
29
+ forEachChild(command, visit);
30
+ return text + source.slice(cursor, command.end);
64
31
  };
65
- const readScript = (parsed) => {
32
+ const readScript = (parsed, source) => {
66
33
  for (const statement of parsed.commands) {
67
34
  if (statement.command.type === 'Function')
68
35
  definedFunctions.add(statement.command.name.value);
69
36
  }
70
- for (const statement of parsed.commands) {
71
- for (const command of walkCommands(statement.command)) {
72
- const name = command.name?.value;
73
- const word = command.name && readWord(command.name);
74
- const prefix = command.prefix
75
- .filter((item) => item.type === 'Assignment')
76
- .map(readAssignment);
77
- const words = [];
78
- for (const arg of command.args) {
79
- if (arg.type === 'Word')
80
- words.push(readWord(arg));
81
- else
82
- readAssignment(arg);
83
- }
84
- if (!name || !word || definedFunctions.has(name))
37
+ for (const command of collectCommands(parsed)) {
38
+ const text = readCommand(command, source);
39
+ const name = command.name?.value;
40
+ if (!name || definedFunctions.has(name))
41
+ continue;
42
+ const binary = extractBinary(name);
43
+ const isPackageCommand = isPackageManager(binary);
44
+ const isExplicit = isPackageCommand || name.startsWith('./') || isRelativeNodeModulesBin(name);
45
+ const hasPath = command.prefix.some(item => item.type === 'Assignment' && item.name === 'PATH');
46
+ const isLocal = hasLocalBinPath && !hasPath;
47
+ const isWrapperCommand = !isPackageCommand && isWrapper(binary);
48
+ if (!isExplicit && !isLocal && !isWrapperCommand && binary !== 'node' && binary !== 'find')
49
+ continue;
50
+ let commandInputs;
51
+ if (isWrapperCommand || binary === 'find') {
52
+ const [marked] = collectCommands(parse(text));
53
+ if (!marked)
85
54
  continue;
86
- const binary = extractBinary(name);
87
- const isPackageCommand = isPackageManager(binary);
88
- const isExplicit = isPackageCommand || name.startsWith('./') || isRelativeNodeModulesBin(name);
89
- const isLocal = hasLocalBinPath && !prefix.some(assignment => assignment.name === 'PATH');
90
- const isWrapperCommand = !isPackageCommand && isWrapper(binary);
91
- if (!isExplicit && !isLocal && !isWrapperCommand && binary !== 'node' && binary !== 'find')
55
+ const fromScript = (script) => {
56
+ inputs.push(...getInputsFromMiseScript(script, options, isLocal));
57
+ return [];
58
+ };
59
+ const fromArgs = args => fromScript(toScript(args));
60
+ commandInputs = getDependenciesFromCommand(marked, { ...options, fromArgs });
61
+ if (spawningBinaries.includes(binary))
62
+ commandInputs.push(...getInputsFromNodeOptions(marked.prefix));
63
+ }
64
+ else {
65
+ commandInputs = options.getInputsFromScripts(text, { cwd: options.cwd, manifest: options.manifest });
66
+ }
67
+ if (!isExplicit && !isLocal && binary !== 'node' && binary !== 'find')
68
+ continue;
69
+ const binaryInput = commandInputs.find(input => isBinary(input) && input.specifier === binary);
70
+ if (!isExplicit && isLocal && binaryInput)
71
+ binaryInput.optional = true;
72
+ for (const input of commandInputs) {
73
+ if (!input.specifier || input.specifier.includes(SCRIPT_INTERPOLATION))
92
74
  continue;
93
- let commandInputs;
94
- if (isWrapperCommand || binary === 'find') {
95
- const fromScript = (script) => {
96
- inputs.push(...getInputsFromMiseScript(script, options, isLocal));
97
- return [];
98
- };
99
- const fromArgs = args => fromScript(toScript(args));
100
- commandInputs = getDependenciesFromCommand({ name: word, prefix, args: words }, { ...options, fromArgs });
101
- }
102
- else {
103
- commandInputs = options.getInputsFromScripts([...prefix.map(assignment => assignment.text), word.text, ...words.map(word => word.text)].join(' '), { cwd: options.cwd, manifest: options.manifest });
104
- }
105
- if (!isExplicit && !isLocal && binary !== 'node' && binary !== 'find')
75
+ if (!isExplicit && !isLocal && input === binaryInput)
106
76
  continue;
107
- if (isWrapperCommand && spawningBinaries.includes(binary)) {
108
- commandInputs.push(...getInputsFromNodeOptions(prefix));
109
- }
110
- const binaryInput = commandInputs.find(input => isBinary(input) && input.specifier === binary);
111
- if (!isExplicit && isLocal && binaryInput)
112
- binaryInput.optional = true;
113
- for (const input of commandInputs) {
114
- if (!input.specifier || input.specifier.includes(SCRIPT_INTERPOLATION))
115
- continue;
116
- if (!isExplicit && !isLocal && input === binaryInput)
117
- continue;
118
- inputs.push(input);
119
- }
77
+ inputs.push(input);
120
78
  }
121
79
  }
122
80
  };
123
81
  try {
124
- readScript(parse(script));
82
+ readScript(parse(script), script);
125
83
  }
126
84
  catch {
127
85
  return [];
@@ -42,6 +42,28 @@ const production = getEntryFilePatterns();
42
42
  const resolveFromAST = (program, { configFileDir }) => {
43
43
  const pageExtensions = new Set();
44
44
  const loaders = new Set();
45
+ const aliasTargets = new Set();
46
+ const collectAliasTargets = (node) => {
47
+ const target = getStringValue(node);
48
+ if (target)
49
+ aliasTargets.add(target);
50
+ else if (node?.type === 'ArrayExpression') {
51
+ for (const element of node.elements)
52
+ collectAliasTargets(element);
53
+ }
54
+ else if (node?.type === 'ObjectExpression') {
55
+ collectAliasTargets(findProperty(node, 'browser'));
56
+ }
57
+ };
58
+ const collectTurbopackAliases = (node) => {
59
+ const aliases = findProperty(node, 'resolveAlias');
60
+ if (aliases?.type !== 'ObjectExpression')
61
+ return;
62
+ for (const alias of aliases.properties) {
63
+ if (alias.type === 'Property')
64
+ collectAliasTargets(alias.value);
65
+ }
66
+ };
45
67
  const collectLoaders = (node) => {
46
68
  if (node?.type === 'ArrayExpression') {
47
69
  for (const element of node.elements)
@@ -60,7 +82,15 @@ const resolveFromAST = (program, { configFileDir }) => {
60
82
  ObjectExpression(node) {
61
83
  for (const extension of getPropertyValues(node, 'pageExtensions'))
62
84
  pageExtensions.add(extension);
63
- const rules = findProperty(findProperty(node, 'turbopack'), 'rules');
85
+ const turbopack = findProperty(node, 'turbopack');
86
+ if (turbopack?.type === 'ConditionalExpression') {
87
+ collectTurbopackAliases(turbopack.consequent);
88
+ collectTurbopackAliases(turbopack.alternate);
89
+ }
90
+ else {
91
+ collectTurbopackAliases(turbopack);
92
+ }
93
+ const rules = findProperty(turbopack, 'rules');
64
94
  if (rules?.type !== 'ObjectExpression')
65
95
  return;
66
96
  for (const rule of rules.properties) {
@@ -75,6 +105,8 @@ const resolveFromAST = (program, { configFileDir }) => {
75
105
  const inputs = patterns.map(id => toProductionEntry(join(configFileDir, id)));
76
106
  for (const loader of loaders)
77
107
  inputs.push(toDeferResolve(loader));
108
+ for (const target of aliasTargets)
109
+ inputs.push({ ...toDeferResolve(target, { dir: configFileDir }), production: true });
78
110
  return inputs;
79
111
  };
80
112
  const commands = new Set(['dev', 'build', 'start']);
@@ -1,6 +1,8 @@
1
1
  import { compact } from '../../util/array.js';
2
- import { toConfig, toDependency } from '../../util/input.js';
3
- import { join, relative } from '../../util/path.js';
2
+ import { isFile, loadJSON } from '../../util/fs.js';
3
+ import { toConfig, toDeferResolveEntry, toDependency } from '../../util/input.js';
4
+ import { get } from '../../util/object.js';
5
+ import { dirname, join, relative } from '../../util/path.js';
4
6
  import { hasDependency } from '../../util/plugin.js';
5
7
  import { substringBefore } from '../../util/string.js';
6
8
  const title = 'Nx';
@@ -57,32 +59,67 @@ const resolveConfig = async (localConfig, options) => {
57
59
  const expandRelative = (command) => command
58
60
  .replaceAll('{projectRoot}', relative(cwd, options.configFileDir))
59
61
  .replaceAll('{workspaceRoot}', relative(cwd, options.rootCwd));
60
- return options.getInputsFromScripts(commands.map(expandRelative), { cwd });
62
+ const scriptInputs = options.getInputsFromScripts(commands.map(expandRelative), { cwd });
63
+ for (const input of scriptInputs)
64
+ input.dir ??= cwd;
65
+ return scriptInputs;
61
66
  });
67
+ const toTargetConfig = (pluginName, specifier) => toConfig(pluginName, expand(specifier), { dir: options.rootCwd });
62
68
  const configInputs = targets.flatMap(target => {
63
69
  const opts = target.options;
64
70
  if (!opts)
65
71
  return [];
66
72
  const configs = [];
67
73
  if ('eslintConfig' in opts && typeof opts.eslintConfig === 'string') {
68
- configs.push(toConfig('eslint', opts.eslintConfig));
74
+ configs.push(toTargetConfig('eslint', opts.eslintConfig));
69
75
  }
70
76
  if ('jestConfig' in opts && typeof opts.jestConfig === 'string') {
71
- configs.push(toConfig('jest', opts.jestConfig));
77
+ configs.push(toTargetConfig('jest', opts.jestConfig));
78
+ }
79
+ if ('karmaConfig' in opts && typeof opts.karmaConfig === 'string') {
80
+ configs.push(toTargetConfig('karma', opts.karmaConfig));
72
81
  }
73
82
  if ('tsConfig' in opts && typeof opts.tsConfig === 'string') {
74
- configs.push(toConfig('typescript', opts.tsConfig));
83
+ configs.push(toTargetConfig('typescript', opts.tsConfig));
75
84
  }
76
85
  if ('vitestConfig' in opts && typeof opts.vitestConfig === 'string') {
77
- configs.push(toConfig('vitest', opts.vitestConfig));
86
+ configs.push(toTargetConfig('vitest', opts.vitestConfig));
78
87
  }
79
88
  if ('webpackConfig' in opts && typeof opts.webpackConfig === 'string') {
80
- configs.push(toConfig('webpack', opts.webpackConfig));
89
+ configs.push(toTargetConfig('webpack', opts.webpackConfig));
81
90
  }
82
91
  return configs;
83
92
  });
84
93
  return compact([...executors, ...inputs, ...configInputs]).map(id => typeof id === 'string' ? toDependency(id) : id);
85
94
  };
95
+ const collections = [
96
+ ['generators', 'schematics'],
97
+ ['executors', 'builders'],
98
+ ];
99
+ const resolve = async (options) => {
100
+ const inputs = [];
101
+ for (const [key, alias] of collections) {
102
+ const file = get(options.manifest, key) ?? get(options.manifest, alias);
103
+ if (typeof file !== 'string')
104
+ continue;
105
+ const filePath = join(options.cwd, file);
106
+ if (!isFile(filePath))
107
+ continue;
108
+ const collection = await loadJSON(filePath);
109
+ for (const entries of [collection[key], collection[alias]]) {
110
+ for (const entry of Object.values(entries ?? {})) {
111
+ if (!entry || typeof entry !== 'object')
112
+ continue;
113
+ for (const id of [entry.implementation || entry.factory, entry.batchImplementation]) {
114
+ if (typeof id === 'string' && id.length > 0) {
115
+ inputs.push(toDeferResolveEntry(join(dirname(filePath), substringBefore(id, '#'))));
116
+ }
117
+ }
118
+ }
119
+ }
120
+ }
121
+ return inputs;
122
+ };
86
123
  const args = {
87
124
  fromArgs: (parsed) => (parsed._[0] === 'exec' ? [...parsed._.slice(1), ...(parsed['--'] ?? [])] : []),
88
125
  };
@@ -95,6 +132,7 @@ const plugin = {
95
132
  isEnabled,
96
133
  config,
97
134
  resolveConfig,
135
+ resolve,
98
136
  args,
99
137
  };
100
138
  export default plugin;
@@ -11,6 +11,7 @@ export interface NxProjectConfiguration {
11
11
  cwd?: string;
12
12
  eslintConfig?: string;
13
13
  jestConfig?: string;
14
+ karmaConfig?: string;
14
15
  tsConfig?: string;
15
16
  vitestConfig?: string;
16
17
  webpackConfig?: string;
@@ -18,6 +19,12 @@ export interface NxProjectConfiguration {
18
19
  };
19
20
  };
20
21
  }
22
+ type NxCollectionEntry = string | {
23
+ factory?: string;
24
+ implementation?: string;
25
+ batchImplementation?: string;
26
+ };
27
+ export type NxCollection = Record<string, Record<string, NxCollectionEntry> | undefined>;
21
28
  export interface NxConfigRoot {
22
29
  plugins?: Array<string | {
23
30
  plugin: string;
@@ -25,3 +32,4 @@ export interface NxConfigRoot {
25
32
  generators?: Record<string, unknown>;
26
33
  targetDefaults?: Record<string, unknown>;
27
34
  }
35
+ export {};
@@ -26,7 +26,7 @@ export const resolveExtendedConfig = (config, configFilePath) => {
26
26
  for (const entry of config.extends ?? []) {
27
27
  if (typeof entry === 'string') {
28
28
  const filePath = toAbsolute(entry, dirname(configFilePath));
29
- inputs.push(toConfig('oxlint', filePath, { containingFilePath: configFilePath }));
29
+ inputs.push(toConfig('oxlint', filePath));
30
30
  }
31
31
  else {
32
32
  for (const input of resolveExtendedConfig(entry, configFilePath))
@@ -1,3 +1,6 @@
1
1
  import type { Plugin } from '../../types/config.ts';
2
+ export declare const docs: {
3
+ note: string;
4
+ };
2
5
  declare const plugin: Plugin;
3
6
  export default plugin;
@@ -43,6 +43,9 @@ const resolveConfig = async (localConfig, options) => {
43
43
  }
44
44
  return resolved;
45
45
  };
46
+ const note = `Route modules import their types from \`./+types/<route>\`, which \`react-router typegen\` generates.
47
+ Run \`react-router typegen\` before Knip (e.g. in CI or a fresh checkout), or these imports are reported as unresolved.`;
48
+ export const docs = { note };
46
49
  const plugin = {
47
50
  title,
48
51
  enablers,
@@ -91,7 +91,7 @@ const resolveConfig = async (localConfig, options) => {
91
91
  .catch(() => undefined)
92
92
  : undefined;
93
93
  if (!project) {
94
- inputs.push(toConfig('rstest', filePath, { containingFilePath: configFilePath }));
94
+ inputs.push(toConfig('rstest', filePath));
95
95
  continue;
96
96
  }
97
97
  inputs.push(toEntry(filePath));
@@ -1,4 +1,5 @@
1
- import { toDeferResolve } from '../../util/input.js';
1
+ import { toConfig, toDeferResolve } from '../../util/input.js';
2
+ import { isInternal } from '../../util/path.js';
2
3
  import { hasDependency } from '../../util/plugin.js';
3
4
  import { toCosmiconfig } from '../../util/plugin-config.js';
4
5
  const title = 'Semantic Release';
@@ -13,9 +14,36 @@ const excludePackages = [
13
14
  '@semantic-release/npm',
14
15
  '@semantic-release/release-notes-generator',
15
16
  ];
16
- const resolveConfig = config => {
17
+ const resolveConfig = (config, options) => {
18
+ const inputs = [];
19
+ for (const id of [config?.extends ?? []].flat()) {
20
+ if (isInternal(id))
21
+ inputs.push(toConfig('semantic-release', id, { containingFilePath: options.configFilePath }));
22
+ else
23
+ inputs.push(toDeferResolve(id));
24
+ }
17
25
  const plugins = (config?.plugins ?? []).map(plugin => (Array.isArray(plugin) ? plugin[0] : plugin));
18
- return plugins.filter(plugin => !excludePackages.includes(plugin)).map(id => toDeferResolve(id));
26
+ for (const id of plugins.filter(plugin => !excludePackages.includes(plugin)))
27
+ inputs.push(toDeferResolve(id));
28
+ return inputs;
29
+ };
30
+ const args = {
31
+ alias: { extends: ['e'] },
32
+ resolveInputs: (parsed, { cwd }) => {
33
+ if (parsed.extends === 'false')
34
+ return [];
35
+ const inputs = [];
36
+ for (const value of [parsed.extends ?? []].flat()) {
37
+ for (const part of String(value).split(',')) {
38
+ const id = part.trim();
39
+ if (isInternal(id))
40
+ inputs.push(toConfig('semantic-release', id, { dir: cwd }));
41
+ else
42
+ inputs.push(toDeferResolve(id));
43
+ }
44
+ }
45
+ return inputs;
46
+ },
19
47
  };
20
48
  const plugin = {
21
49
  title,
@@ -25,5 +53,6 @@ const plugin = {
25
53
  packageJsonPath,
26
54
  config,
27
55
  resolveConfig,
56
+ args,
28
57
  };
29
58
  export default plugin;
@@ -1,3 +1,4 @@
1
1
  export type SemanticReleaseConfig = {
2
+ extends?: string | string[];
2
3
  plugins?: (string | [string, Record<string, unknown>])[];
3
4
  };
@@ -0,0 +1,6 @@
1
+ import type { Plugin } from '../../types/config.ts';
2
+ export declare const docs: {
3
+ note: string;
4
+ };
5
+ declare const plugin: Plugin;
6
+ export default plugin;
@@ -0,0 +1,17 @@
1
+ import { hasDependency } from '../../util/plugin.js';
2
+ import { config } from '../vite/index.js';
3
+ import { production, resolveFromAST } from './resolveFromAST.js';
4
+ const title = '@solidjs/vite-plugin';
5
+ const enablers = ['@solidjs/vite-plugin'];
6
+ const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
7
+ const note = `Without a Vite config, the default entry patterns are used. With a config, start entries are only added when \`start\` is enabled. Paths like \`start.app\` replace the matching default, and the \`ssr\` option decides which files Solid loads. \`serverFunctions.configure\` is added with or without \`start\`.`;
8
+ export const docs = { note };
9
+ const plugin = {
10
+ title,
11
+ enablers,
12
+ isEnabled,
13
+ config,
14
+ production,
15
+ resolveFromAST,
16
+ };
17
+ export default plugin;
@@ -0,0 +1,3 @@
1
+ import type { ResolveFromAST } from '../../types/config.ts';
2
+ export declare const production: string[];
3
+ export declare const resolveFromAST: ResolveFromAST;
@@ -0,0 +1,76 @@
1
+ import { findImportedCalls, findProperty } from '../../typescript/ast-helpers.js';
2
+ import { getStringValue } from '../../typescript/ast-nodes.js';
3
+ import { isFile } from '../../util/fs.js';
4
+ import { toProductionEntry } from '../../util/input.js';
5
+ import { join, toAbsolute } from '../../util/path.js';
6
+ import { getViteRoot } from '../vite/helpers.js';
7
+ const entryExtensions = ['tsx', 'jsx', 'ts', 'js', 'mjs', 'tsrx'];
8
+ const entryStems = {
9
+ entryServer: 'src/entry-server',
10
+ entryClient: 'src/entry-client',
11
+ };
12
+ const conventions = {
13
+ entryServer: `src/entry-server.{${entryExtensions.join(',')}}`,
14
+ entryClient: `src/entry-client.{${entryExtensions.join(',')}}`,
15
+ app: 'src/{App,app}.{tsx,jsx,ts,js,tsrx}',
16
+ document: 'src/Document.{tsx,jsx,tsrx}',
17
+ env: 'env.{ts,js}',
18
+ };
19
+ export const production = Object.values(conventions);
20
+ const startOptions = ['app', 'document', 'entryServer', 'entryClient', 'middleware', 'instrument', 'setup', 'env'];
21
+ const isBoolean = (node, value) => node?.type === 'Literal' && node.value === value;
22
+ const hasEntryFile = (root, stem) => {
23
+ for (const extension of entryExtensions)
24
+ if (isFile(root, `${stem}.${extension}`))
25
+ return true;
26
+ return false;
27
+ };
28
+ export const resolveFromAST = (program, options) => {
29
+ const root = getViteRoot(program, options.cwd);
30
+ const patterns = new Set();
31
+ const paths = new Set();
32
+ for (const call of findImportedCalls(program, '@solidjs/vite-plugin')) {
33
+ const arg = call.arguments[0];
34
+ if (arg?.type !== 'ObjectExpression')
35
+ continue;
36
+ const configure = getStringValue(findProperty(findProperty(arg, 'serverFunctions'), 'configure'));
37
+ if (configure)
38
+ paths.add(configure);
39
+ const start = findProperty(arg, 'start');
40
+ if (!start || isBoolean(start, false))
41
+ continue;
42
+ const values = {};
43
+ for (const name of startOptions) {
44
+ values[name] = start.type === 'ObjectExpression' ? findProperty(start, name) : undefined;
45
+ }
46
+ const isAuthored = (name) => Boolean(getStringValue(values[name])) || hasEntryFile(root, entryStems[name]);
47
+ const ssr = findProperty(arg, 'ssr');
48
+ const skip = new Set();
49
+ if (!ssr || isBoolean(ssr, false)) {
50
+ skip.add('entryServer');
51
+ skip.add('setup');
52
+ if (isAuthored('entryClient'))
53
+ skip.add('app');
54
+ }
55
+ else if (isBoolean(ssr, true) && isAuthored('entryServer') && isAuthored('entryClient')) {
56
+ skip.add('app');
57
+ skip.add('document');
58
+ }
59
+ for (const name of startOptions) {
60
+ if (skip.has(name))
61
+ continue;
62
+ const value = values[name];
63
+ const path = getStringValue(value);
64
+ if (path)
65
+ paths.add(path);
66
+ else if (name in conventions && !(name === 'env' && isBoolean(value, false)))
67
+ patterns.add(conventions[name]);
68
+ }
69
+ }
70
+ const inputs = [];
71
+ for (const pattern of patterns)
72
+ inputs.push(toProductionEntry(join(root, pattern)));
73
+ for (const id of paths)
74
+ inputs.push(toProductionEntry(toAbsolute(id, root)));
75
+ return inputs;
76
+ };