knip 6.40.0 → 6.41.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 (49) hide show
  1. package/dist/ConfigurationChief.d.ts +12 -0
  2. package/dist/DependencyDeputy.d.ts +1 -0
  3. package/dist/DependencyDeputy.js +28 -2
  4. package/dist/IssueCollector.js +13 -15
  5. package/dist/IssueFixer.js +1 -1
  6. package/dist/WorkspaceWorker.js +14 -8
  7. package/dist/binaries/bash-parser.js +10 -4
  8. package/dist/binaries/command.d.ts +1 -1
  9. package/dist/binaries/command.js +14 -8
  10. package/dist/graph/build.js +18 -9
  11. package/dist/manifest/index.d.ts +1 -0
  12. package/dist/manifest/index.js +5 -0
  13. package/dist/plugins/expo/helpers.js +1 -1
  14. package/dist/plugins/expo/index.js +4 -24
  15. package/dist/plugins/expo-router/index.d.ts +3 -0
  16. package/dist/plugins/expo-router/index.js +32 -0
  17. package/dist/plugins/flue/index.d.ts +3 -0
  18. package/dist/plugins/flue/index.js +42 -0
  19. package/dist/plugins/index.d.ts +2 -0
  20. package/dist/plugins/index.js +4 -0
  21. package/dist/plugins/mise/scripts.js +32 -10
  22. package/dist/plugins/moonrepo/index.js +2 -1
  23. package/dist/plugins/nx/index.js +6 -2
  24. package/dist/plugins/react-native/index.js +1 -1
  25. package/dist/plugins/rsbuild/index.js +20 -6
  26. package/dist/plugins/rsbuild/types.d.ts +6 -0
  27. package/dist/plugins/rstest/types.d.ts +1 -5
  28. package/dist/plugins/sveltejs-package/helpers.js +7 -44
  29. package/dist/run.js +2 -0
  30. package/dist/schema/configuration.d.ts +30 -0
  31. package/dist/schema/plugins.d.ts +10 -0
  32. package/dist/schema/plugins.js +2 -0
  33. package/dist/types/PluginNames.d.ts +2 -2
  34. package/dist/types/PluginNames.js +2 -0
  35. package/dist/types/workspace.d.ts +1 -0
  36. package/dist/util/create-options.d.ts +20 -0
  37. package/dist/util/glob-cache.d.ts +2 -2
  38. package/dist/util/glob-core.js +70 -47
  39. package/dist/util/glob.js +15 -10
  40. package/dist/util/load-tsconfig.d.ts +1 -1
  41. package/dist/util/load-tsconfig.js +21 -11
  42. package/dist/util/module-graph.js +9 -4
  43. package/dist/util/scripts.d.ts +3 -2
  44. package/dist/util/scripts.js +9 -3
  45. package/dist/util/to-source-path.js +1 -1
  46. package/dist/version.d.ts +1 -1
  47. package/dist/version.js +1 -1
  48. package/package.json +9 -10
  49. package/schema.json +8 -0
@@ -237,6 +237,11 @@ export declare class ConfigurationChief {
237
237
  entry?: string | string[] | undefined;
238
238
  project?: string | string[] | undefined;
239
239
  } | undefined;
240
+ 'expo-router'?: string | boolean | string[] | {
241
+ config?: string | string[] | undefined;
242
+ entry?: string | string[] | undefined;
243
+ project?: string | string[] | undefined;
244
+ } | undefined;
240
245
  'expressive-code'?: string | boolean | string[] | {
241
246
  config?: string | string[] | undefined;
242
247
  entry?: string | string[] | undefined;
@@ -247,6 +252,11 @@ export declare class ConfigurationChief {
247
252
  entry?: string | string[] | undefined;
248
253
  project?: string | string[] | undefined;
249
254
  } | undefined;
255
+ flue?: string | boolean | string[] | {
256
+ config?: string | string[] | undefined;
257
+ entry?: string | string[] | undefined;
258
+ project?: string | string[] | undefined;
259
+ } | undefined;
250
260
  fumadocs?: string | boolean | string[] | {
251
261
  config?: string | string[] | undefined;
252
262
  entry?: string | string[] | undefined;
@@ -1076,8 +1086,10 @@ export declare class ConfigurationChief {
1076
1086
  eve?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1077
1087
  execa?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1078
1088
  expo?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1089
+ "expo-router"?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1079
1090
  "expressive-code"?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1080
1091
  fast?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1092
+ flue?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1081
1093
  fumadocs?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1082
1094
  gatsby?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1083
1095
  "github-action"?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
@@ -40,6 +40,7 @@ export declare class DependencyDeputy {
40
40
  peerDependencies: DependencySet;
41
41
  optionalPeerDependencies: DependencySet;
42
42
  requiredPeerDependencies: DependencyArray;
43
+ uninstalledOptionalDependencies: DependencySet;
43
44
  allDependencies: DependencySet;
44
45
  engines: Record<string, string>;
45
46
  isPrivate: boolean;
@@ -38,15 +38,25 @@ export class DependencyDeputy {
38
38
  const requiredPeerDependencies = peerDependencies.filter(dep => !optionalPeerDependencies.has(dep));
39
39
  const devDependencies = Object.keys(manifest.devDependencies ?? {});
40
40
  const allDependencies = [...dependencies, ...devDependencies, ...peerDependencies, ...optionalDependencies];
41
- const packageNames = [...dependencies, ...peerDependencies, ...(this.isProduction ? [] : devDependencies)];
41
+ const uninstalledOptionalDependencies = new Set();
42
+ const packageNames = [
43
+ ...dependencies,
44
+ ...peerDependencies,
45
+ ...optionalDependencies,
46
+ ...(this.isProduction ? [] : devDependencies),
47
+ ];
42
48
  if (this.isReportDependencies) {
43
- const { hostDependencies, installedBinaries, hasTypesIncluded } = getDependencyMetaData({
49
+ const { hostDependencies, installedBinaries, hasTypesIncluded, uninstalledDependencies } = getDependencyMetaData({
44
50
  packageNames,
45
51
  dir,
46
52
  });
47
53
  this.setHostDependencies(name, hostDependencies);
48
54
  this.installedBinaries.set(name, installedBinaries);
49
55
  this.hasTypesIncluded.set(name, hasTypesIncluded);
56
+ for (const dependency of optionalDependencies) {
57
+ if (uninstalledDependencies.has(dependency))
58
+ uninstalledOptionalDependencies.add(dependency);
59
+ }
50
60
  }
51
61
  const ignoreDependencies = id.flatMap(id => filterIsProduction(id, this.isProduction)).map(toRegexOrString);
52
62
  const ignoreBinaries = ib.flatMap(ib => filterIsProduction(ib, this.isProduction)).map(toRegexOrString);
@@ -66,6 +76,7 @@ export class DependencyDeputy {
66
76
  peerDependencies: new Set(peerDependencies),
67
77
  optionalPeerDependencies,
68
78
  requiredPeerDependencies,
79
+ uninstalledOptionalDependencies,
69
80
  allDependencies: new Set(allDependencies),
70
81
  engines: manifest.engines ?? {},
71
82
  isPrivate: Boolean(manifest.private),
@@ -171,6 +182,21 @@ export class DependencyDeputy {
171
182
  }
172
183
  }
173
184
  }
185
+ const optionalDependencies = new Set();
186
+ for (const name of workspaceNames) {
187
+ const manifest = this._manifests.get(name);
188
+ if (!manifest)
189
+ continue;
190
+ for (const dependency of manifest.uninstalledOptionalDependencies) {
191
+ const defaultBinaryName = dependency.replace(/^@[^/]+\//, '');
192
+ if (defaultBinaryName === binaryName) {
193
+ optionalDependencies.add(dependency);
194
+ this.addReferencedDependency(name, dependency);
195
+ }
196
+ }
197
+ }
198
+ if (optionalDependencies.size)
199
+ return optionalDependencies;
174
200
  return;
175
201
  }
176
202
  isInDependencies(workspaceName, packageName, isDevOnly) {
@@ -1,7 +1,6 @@
1
1
  import picomatch from 'picomatch';
2
2
  import { ROOT_WORKSPACE_NAME } from './constants.js';
3
3
  import { partition } from './util/array.js';
4
- import { prependDirToPattern } from './util/glob.js';
5
4
  import { initCounters, initIssues } from './util/issue-initializers.js';
6
5
  import { relative } from './util/path.js';
7
6
  const createMatcher = (patterns) => {
@@ -82,23 +81,22 @@ export class IssueCollector {
82
81
  return;
83
82
  const issueTypePatterns = new Map();
84
83
  for (const [pattern, issueTypes] of Object.entries(ignoreIssues)) {
85
- const id = prependDirToPattern(this.cwd, pattern);
86
84
  for (const issueType of issueTypes) {
87
85
  if (!issueTypePatterns.has(issueType)) {
88
86
  issueTypePatterns.set(issueType, []);
89
87
  }
90
- issueTypePatterns.get(issueType)?.push(id);
88
+ issueTypePatterns.get(issueType)?.push(pattern);
91
89
  }
92
90
  }
93
91
  for (const [issueType, patterns] of issueTypePatterns) {
94
92
  this.issueMatchers.set(issueType, picomatch(patterns, { dot: true }));
95
93
  }
96
94
  }
97
- shouldIgnoreIssue(filePath, issueType) {
95
+ shouldIgnoreIssue(relativePath, issueType) {
98
96
  const matcher = this.issueMatchers.get(issueType);
99
97
  if (!matcher)
100
98
  return false;
101
- return matcher(filePath);
99
+ return matcher(relativePath);
102
100
  }
103
101
  addFileCounts({ processed, unused }) {
104
102
  this.counters.processed += processed;
@@ -110,17 +108,17 @@ export class IssueCollector {
110
108
  continue;
111
109
  if (this.referencedFiles.has(filePath))
112
110
  continue;
113
- if (this.isMatch(filePath)) {
114
- this.markUsedPatterns(filePath, this.unusedIgnorePatterns);
111
+ const symbol = relative(this.cwd, filePath);
112
+ if (this.isMatch(symbol)) {
113
+ this.markUsedPatterns(symbol, this.unusedIgnorePatterns);
115
114
  continue;
116
115
  }
117
- if (this.isFileMatch(filePath)) {
118
- this.markUsedPatterns(filePath, this.unusedIgnoreFilesPatterns);
116
+ if (this.isFileMatch(symbol)) {
117
+ this.markUsedPatterns(symbol, this.unusedIgnoreFilesPatterns);
119
118
  continue;
120
119
  }
121
- if (this.shouldIgnoreIssue(filePath, 'files'))
120
+ if (this.shouldIgnoreIssue(symbol, 'files'))
122
121
  continue;
123
- const symbol = relative(this.cwd, filePath);
124
122
  this.issues.files[symbol] = {
125
123
  [symbol]: { type: 'files', filePath, symbol, workspace: '', severity: this.rules.files, fixes: [] },
126
124
  };
@@ -131,15 +129,15 @@ export class IssueCollector {
131
129
  addIssue(issue) {
132
130
  if (!this.workspaceFilter(issue.filePath))
133
131
  return;
134
- if (this.isMatch(issue.filePath)) {
135
- this.markUsedPatterns(issue.filePath, this.unusedIgnorePatterns);
132
+ const key = relative(this.cwd, issue.filePath);
133
+ if (this.isMatch(key)) {
134
+ this.markUsedPatterns(key, this.unusedIgnorePatterns);
136
135
  return;
137
136
  }
138
- if (this.shouldIgnoreIssue(issue.filePath, issue.type))
137
+ if (this.shouldIgnoreIssue(key, issue.type))
139
138
  return;
140
139
  if (this.rules[issue.type] === 'off')
141
140
  return;
142
- const key = relative(this.cwd, issue.filePath);
143
141
  issue.severity = this.rules[issue.type];
144
142
  const issues = this.issues[issue.type];
145
143
  issues[key] = issues[key] ?? {};
@@ -21,7 +21,7 @@ export const fix = async (issues, counters, options) => {
21
21
  }
22
22
  if (options.isFormat) {
23
23
  const report = await formatly(Array.from(touchedFiles));
24
- if (report.ran && report.result && (report.result.runner === 'virtual' || report.result.code === 0)) {
24
+ if (report.ran && report.result.runner !== 'dry-run' && report.result.code === 0) {
25
25
  debugLogArray('*', `Formatted files using ${report.formatter.name} (${report.formatter.runner})`, touchedFiles);
26
26
  }
27
27
  else {
@@ -14,7 +14,7 @@ import { _glob, hasNoProductionSuffix, hasProductionSuffix, negate } from './uti
14
14
  import { isCatalog, isConfig, toConfig, toDebugString, toEntry, toProductionEntry, } from './util/input.js';
15
15
  import { filterTransitiveDependencies } from './util/filter-transitive-dependencies.js';
16
16
  import { timerify } from './util/Performance.js';
17
- import { basename, dirname, join, toRelative } from './util/path.js';
17
+ import { basename, dirname, join, relative, toRelative } from './util/path.js';
18
18
  import { extractPatternExtensions } from './util/pattern-extensions.js';
19
19
  import { formatCauseMessage } from './util/errors.js';
20
20
  import { logError } from './util/log.js';
@@ -469,18 +469,24 @@ export class WorkspaceWorker {
469
469
  hints.push({ type: `${type}-empty`, identifier, workspaceName });
470
470
  return hints;
471
471
  }
472
+ const dir = this.dir;
473
+ const relativePaths = [];
474
+ const hasMatch = (isMatch) => {
475
+ for (let i = 0; i < filePaths.length; i++) {
476
+ if (isMatch((relativePaths[i] ??= relative(dir, filePaths[i]))))
477
+ return true;
478
+ }
479
+ return false;
480
+ };
472
481
  for (const pattern of patterns) {
473
482
  if (pattern.startsWith('!'))
474
483
  continue;
475
- const filePathOrPattern = join(this.dir, pattern.replace(/!$/, ''));
476
- if (includedPaths.has(filePathOrPattern)) {
484
+ const id = pattern.replace(/!$/, '');
485
+ if (includedPaths.has(join(dir, id))) {
477
486
  hints.push({ type: `${type}-redundant`, identifier: pattern, workspaceName });
478
487
  }
479
- else {
480
- const matcher = picomatch(filePathOrPattern);
481
- if (!filePaths.some(filePath => matcher(filePath))) {
482
- hints.push({ type: `${type}-empty`, identifier: pattern, workspaceName });
483
- }
488
+ else if (!hasMatch(picomatch(id))) {
489
+ hints.push({ type: `${type}-empty`, identifier: pattern, workspaceName });
484
490
  }
485
491
  }
486
492
  if (type === 'project' && compilerExtensions) {
@@ -7,6 +7,11 @@ import { walkCommands } from '../util/scripts.js';
7
7
  import { getDependenciesFromCommand } from './command.js';
8
8
  import { toScript } from './util.js';
9
9
  const collectExpansionScripts = (word, out) => {
10
+ if (word.type === 'ArrayValue') {
11
+ for (const element of word.elements)
12
+ collectExpansionScripts(element, out);
13
+ return;
14
+ }
10
15
  if (!word.parts)
11
16
  return;
12
17
  for (const part of word.parts) {
@@ -63,11 +68,12 @@ export const getDependenciesFromScript = (script, options) => {
63
68
  const processCommand = (node, pending) => {
64
69
  if (node.name)
65
70
  collectExpansionScripts(node.name, pending);
66
- for (const prefix of node.prefix)
67
- if (prefix.value)
71
+ for (const prefix of node.prefix) {
72
+ if (prefix.type === 'Assignment')
68
73
  collectExpansionScripts(prefix.value, pending);
69
- for (const suffix of node.suffix)
70
- collectExpansionScripts(suffix, pending);
74
+ }
75
+ for (const arg of node.args)
76
+ collectExpansionScripts(arg.type === 'Assignment' ? arg.value : arg, pending);
71
77
  if (definedFunctions.size && node.name && definedFunctions.has(extractBinary(node.name.value)))
72
78
  return [];
73
79
  return getDependenciesFromCommand(node, { ...options, fromArgs }, fromWords);
@@ -2,4 +2,4 @@ import type { Command, Word } from 'unbash';
2
2
  import type { BinaryResolverOptions, GetInputsFromScriptsOptions } from '../types/config.ts';
3
3
  import { type Input } from '../util/input.ts';
4
4
  export declare const getInputsFromNodeOptions: (prefix: Command['prefix']) => Input[];
5
- export declare const getDependenciesFromCommand: (node: Command, options: BinaryResolverOptions, fromWords?: (words: Word[], options: GetInputsFromScriptsOptions) => Input[]) => Input[];
5
+ export declare const getDependenciesFromCommand: (node: Pick<Command, 'name' | 'prefix' | 'args'>, options: BinaryResolverOptions, fromWords?: (words: Word[], options: GetInputsFromScriptsOptions) => Input[]) => Input[];
@@ -1,17 +1,23 @@
1
1
  import { Plugins, pluginArgsMap } from '../plugins.js';
2
2
  import { toDeferResolve } from '../util/input.js';
3
3
  import { extractBinary, isInNodeModulesBin, isRelativeNodeModulesBin } from '../util/modules.js';
4
+ import { getCommandWords } from '../util/scripts.js';
4
5
  import { resolve as fallbackResolve, spawningBinaries } from './fallback.js';
5
6
  import KnownResolvers, { isPackageManager } from './resolvers/index.js';
6
7
  import { resolve as resolverFromPlugins } from './plugins.js';
7
8
  import { parseNodeArgs, toCommandBinary } from './util.js';
8
- export const getInputsFromNodeOptions = (prefix) => prefix
9
- .filter(a => a.name === 'NODE_OPTIONS' && a.value)
10
- .map(a => a.value.value)
11
- .map(arg => parseNodeArgs(arg.split(' ')))
12
- .filter(args => args.require)
13
- .flatMap(arg => arg.require)
14
- .map(id => toDeferResolve(id));
9
+ export const getInputsFromNodeOptions = (prefix) => {
10
+ const inputs = [];
11
+ for (const item of prefix) {
12
+ if (item.type !== 'Assignment' || item.name !== 'NODE_OPTIONS' || item.value.type !== 'Word')
13
+ continue;
14
+ const args = parseNodeArgs(item.value.value.split(' '));
15
+ if (args.require)
16
+ for (const id of [args.require].flat())
17
+ inputs.push(toDeferResolve(id));
18
+ }
19
+ return inputs;
20
+ };
15
21
  export const getDependenciesFromCommand = (node, options, fromWords = options.fromArgs) => {
16
22
  const text = node.name?.value;
17
23
  if (!text)
@@ -31,7 +37,7 @@ export const getDependenciesFromCommand = (node, options, fromWords = options.fr
31
37
  };
32
38
  }
33
39
  const { fromArgs } = options;
34
- const words = node.suffix;
40
+ const words = getCommandWords(node);
35
41
  if (binary === '!' || binary === 'test')
36
42
  return fromArgs(words);
37
43
  const fromNodeOptions = getInputsFromNodeOptions(node.prefix);
@@ -51,8 +51,8 @@ export async function build({ chief, collector, counselor, deputy, principal, is
51
51
  });
52
52
  }
53
53
  deputy.setWorkspacePkgNames(chief.availableWorkspacePkgNames);
54
- collector.addIgnorePatterns(chief.config.ignore.map(id => ({ pattern: prependDir(options.cwd, id), id })));
55
- collector.addIgnoreFilesPatterns(chief.config.ignoreFiles.map(id => ({ pattern: prependDir(options.cwd, id), id })));
54
+ collector.addIgnorePatterns(chief.config.ignore.map(id => ({ pattern: id, id })));
55
+ collector.addIgnoreFilesPatterns(chief.config.ignoreFiles.map(id => ({ pattern: id, id })));
56
56
  if (options.configFilePath) {
57
57
  principal.addEntryPath(options.configFilePath, { skipExportsAnalysis: true });
58
58
  }
@@ -79,7 +79,7 @@ export async function build({ chief, collector, counselor, deputy, principal, is
79
79
  continue;
80
80
  const dependencies = deputy.getDependencies(name);
81
81
  const tsConfigFilePath = join(dir, options.tsConfigFile ?? 'tsconfig.json');
82
- const { isFile, compilerOptions, fileNames, include, exclude, sourceMapPairs, paths: tsConfigPaths, } = await loadTSConfig(tsConfigFilePath);
82
+ const { isFile, compilerOptions, fileNames, include, exclude, sourceMapPairs, paths: tsConfigPaths, } = await loadTSConfig(tsConfigFilePath, options.isUseTscFiles);
83
83
  const [definitionPaths, tscSourcePaths] = partition(fileNames, filePath => IS_DTS.test(filePath));
84
84
  const worker = new WorkspaceWorker({
85
85
  name,
@@ -122,7 +122,7 @@ export async function build({ chief, collector, counselor, deputy, principal, is
122
122
  inputs.add(toProductionEntry(tryRealpath(id), { containingFilePath: tsConfigFilePath }));
123
123
  }
124
124
  const sharedGlobOptions = { cwd: options.cwd, dir, gitignore: options.gitignore };
125
- const fn = (id) => ({ pattern: prependDir(options.cwd, prependDir(name, id)), id, workspaceName: name });
125
+ const fn = (id) => ({ pattern: prependDir(name, id), id, workspaceName: name });
126
126
  collector.addIgnorePatterns(config.ignore.map(fn));
127
127
  collector.addIgnoreFilesPatterns(config.ignoreFiles.map(fn));
128
128
  const entrySpecifiersFromManifest = getEntrySpecifiersFromManifest(manifest);
@@ -249,7 +249,10 @@ export async function build({ chief, collector, counselor, deputy, principal, is
249
249
  }
250
250
  const developmentMatchers = [];
251
251
  if (options.isProduction) {
252
- const toPattern = (pattern) => join(isAbsolute(pattern) ? '' : dir, removeProductionSuffix(pattern));
252
+ const toPattern = (pattern) => {
253
+ const id = removeProductionSuffix(pattern);
254
+ return isAbsolute(id) ? relative(options.cwd, id) : join(name, id);
255
+ };
253
256
  for (const map of [entryPatterns, entryPatternsSkipExports]) {
254
257
  for (const patterns of map.values()) {
255
258
  const [excluded, included] = partition(patterns, pattern => pattern.startsWith('!'));
@@ -260,7 +263,12 @@ export async function build({ chief, collector, counselor, deputy, principal, is
260
263
  }
261
264
  }
262
265
  }
263
- const productionPaths = (paths) => developmentMatchers.length ? paths.filter(path => !developmentMatchers.some(match => match(path))) : paths;
266
+ const productionPaths = (paths) => developmentMatchers.length
267
+ ? paths.filter(path => {
268
+ const relativePath = relative(options.cwd, path);
269
+ return !developmentMatchers.some(match => match(relativePath));
270
+ })
271
+ : paths;
264
272
  const userEntryPatterns = options.isProduction
265
273
  ? worker.getProductionEntryFilePatterns()
266
274
  : worker.getEntryFilePatterns();
@@ -313,10 +321,11 @@ export async function build({ chief, collector, counselor, deputy, principal, is
313
321
  }
314
322
  if (extensions.length > 0) {
315
323
  const extPart = extensions.length === 1 ? extensions[0] : `.{${extensions.map(ext => ext.slice(1)).join(',')}}`;
316
- const bases = include ? new Set(include.map(p => picomatch.scan(p).base || dir)) : new Set([dir]);
324
+ const tsConfigDir = relative(dir, dirname(tsConfigFilePath));
325
+ const bases = include ? new Set(include.map(p => join(tsConfigDir, picomatch.scan(p).base))) : new Set(['']);
317
326
  const patterns = [
318
- ...Array.from(bases, base => `${base}/**/*${extPart}`),
319
- ...(exclude?.map(p => `!${p}`) ?? []),
327
+ ...Array.from(bases, base => join(base, `**/*${extPart}`)),
328
+ ...(exclude?.map(p => `!${join(tsConfigDir, p)}`) ?? []),
320
329
  ];
321
330
  const compilerPaths = await _glob({ ...sharedGlobOptions, patterns, label: 'compiler extension paths' });
322
331
  for (const compilerPath of compilerPaths) {
@@ -7,6 +7,7 @@ declare const getMetaDataFromPackageJson: ({ dir, packageNames }: Options) => {
7
7
  hostDependencies: HostDependencies;
8
8
  installedBinaries: InstalledBinaries;
9
9
  hasTypesIncluded: Set<string>;
10
+ uninstalledDependencies: Set<string>;
10
11
  };
11
12
  export declare const getDependencyMetaData: typeof getMetaDataFromPackageJson;
12
13
  export {};
@@ -5,6 +5,7 @@ const getMetaDataFromPackageJson = ({ dir, packageNames }) => {
5
5
  const hostDependencies = new Map();
6
6
  const installedBinaries = new Map();
7
7
  const hasTypesIncluded = new Set();
8
+ const uninstalledDependencies = new Set();
8
9
  const addBinary = (key, value) => {
9
10
  const set = installedBinaries.get(key);
10
11
  if (set)
@@ -35,11 +36,15 @@ const getMetaDataFromPackageJson = ({ dir, packageNames }) => {
35
36
  if (!isDefinitelyTyped(packageName) && (manifest.types || manifest.typings))
36
37
  hasTypesIncluded.add(packageName);
37
38
  }
39
+ else {
40
+ uninstalledDependencies.add(packageName);
41
+ }
38
42
  }
39
43
  return {
40
44
  hostDependencies,
41
45
  installedBinaries,
42
46
  hasTypesIncluded,
47
+ uninstalledDependencies,
43
48
  };
44
49
  };
45
50
  export const getDependencyMetaData = timerify(getMetaDataFromPackageJson);
@@ -50,7 +50,7 @@ export const getDependencies = async (localConfig, options) => {
50
50
  if (platforms.includes('web')) {
51
51
  inputs.add(toProductionDependency('react-native-web'));
52
52
  inputs.add(toProductionDependency('react-dom'));
53
- if (!isExpoRouter) {
53
+ if (!isExpoRouter && !options.enabledPlugins.includes('expo-router')) {
54
54
  inputs.add(toDependency('@expo/metro-runtime'));
55
55
  }
56
56
  }
@@ -1,37 +1,17 @@
1
- import { toConfig, toIgnore, toProductionEntry } from '../../util/input.js';
2
- import { join } from '../../util/path.js';
1
+ import { toConfig, toIgnore } from '../../util/input.js';
3
2
  import { hasDependency } from '../../util/plugin.js';
4
- import { getConfig, getDependencies } from './helpers.js';
3
+ import { getDependencies } from './helpers.js';
5
4
  const title = 'Expo';
6
5
  const enablers = ['expo'];
7
6
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
8
- const config = ['app.json', 'app.config.{ts,js}'];
9
- const production = ['app/**/*.{js,jsx,ts,tsx}', 'src/app/**/*.{js,jsx,ts,tsx}'];
7
+ const config = ['app.json', 'app.config.{json,ts,js,mts,cts,mjs,cjs}'];
10
8
  const resolve = () => [toConfig('babel', 'babel.config'), toIgnore('babel-preset-expo', 'unresolved')];
11
- const resolveConfig = async (localConfig, options) => {
12
- const { manifest } = options;
13
- const config = getConfig(localConfig, options);
14
- if (manifest.main === 'expo-router/entry') {
15
- let patterns = [...production];
16
- const normalizedPlugins = config.plugins?.map(plugin => (Array.isArray(plugin) ? plugin : [plugin])) ?? [];
17
- const expoRouterPlugin = normalizedPlugins.find(([plugin]) => plugin === 'expo-router');
18
- if (expoRouterPlugin) {
19
- const [, options] = expoRouterPlugin;
20
- if (typeof options?.root === 'string') {
21
- patterns = [join(options.root, '**/*.{js,jsx,ts,tsx}')];
22
- }
23
- }
24
- return patterns.map(entry => toProductionEntry(entry)).concat(await getDependencies(localConfig, options));
25
- }
26
- return production.map(entry => toProductionEntry(entry)).concat(await getDependencies(localConfig, options));
27
- };
28
9
  const plugin = {
29
10
  title,
30
11
  enablers,
31
12
  isEnabled,
32
13
  config,
33
- production,
34
14
  resolve,
35
- resolveConfig,
15
+ resolveConfig: getDependencies,
36
16
  };
37
17
  export default plugin;
@@ -0,0 +1,3 @@
1
+ import type { Plugin } from '../../types/config.ts';
2
+ declare const plugin: Plugin;
3
+ export default plugin;
@@ -0,0 +1,32 @@
1
+ import { toProductionEntry } from '../../util/input.js';
2
+ import { join } from '../../util/path.js';
3
+ import { hasDependency } from '../../util/plugin.js';
4
+ import expo from '../expo/index.js';
5
+ import { getConfig } from '../expo/helpers.js';
6
+ const title = 'Expo Router';
7
+ const enablers = ['expo-router'];
8
+ const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
9
+ const config = expo.config;
10
+ const production = ['app/**/*.{js,jsx,ts,tsx}', 'src/app/**/*.{js,jsx,ts,tsx}'];
11
+ const resolveConfig = async (localConfig, options) => {
12
+ const config = getConfig(localConfig, options);
13
+ for (const plugin of config.plugins ?? []) {
14
+ if (!Array.isArray(plugin))
15
+ continue;
16
+ const [name, pluginOptions] = plugin;
17
+ const root = pluginOptions?.root;
18
+ if (name === 'expo-router' && typeof root === 'string') {
19
+ return [toProductionEntry(join(root, '**/*.{js,jsx,ts,tsx}'))];
20
+ }
21
+ }
22
+ return production.map(id => toProductionEntry(id));
23
+ };
24
+ const plugin = {
25
+ title,
26
+ enablers,
27
+ isEnabled,
28
+ config,
29
+ production,
30
+ resolveConfig,
31
+ };
32
+ export default plugin;
@@ -0,0 +1,3 @@
1
+ import type { Plugin } from '../../types/config.ts';
2
+ declare const plugin: Plugin;
3
+ export default plugin;
@@ -0,0 +1,42 @@
1
+ import { collectFirstPropertyValue } from '../../typescript/ast-helpers.js';
2
+ import { isDirectory } from '../../util/fs.js';
3
+ import { toProductionEntry } from '../../util/input.js';
4
+ import { join } from '../../util/path.js';
5
+ import { hasDependency } from '../../util/plugin.js';
6
+ const title = 'Flue';
7
+ const enablers = ['@flue/runtime'];
8
+ const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
9
+ const config = ['flue.config.{ts,mts,mjs,js,cjs,cts}'];
10
+ const extensions = '{ts,mts,js,mjs}';
11
+ const entryNames = ['app', 'db', 'cloudflare'];
12
+ const agentsPattern = `{agent,agents/*,agents/*/agent}.${extensions}`;
13
+ const production = [`{.flue/,src/,}{app,db,cloudflare}.${extensions}`, `{.flue/,src/,}${agentsPattern}`];
14
+ const getSourceRoot = (dir) => {
15
+ for (const name of ['.flue', 'src'])
16
+ if (isDirectory(dir, name))
17
+ return join(dir, name);
18
+ return dir;
19
+ };
20
+ const resolveFromAST = (program, { configFileDir }) => {
21
+ const sourceRoot = getSourceRoot(configFileDir);
22
+ const inputs = [];
23
+ for (const name of entryNames) {
24
+ const filePath = collectFirstPropertyValue(program, name);
25
+ if (filePath)
26
+ inputs.push(toProductionEntry(join(configFileDir, filePath)));
27
+ else
28
+ inputs.push(toProductionEntry(join(sourceRoot, `${name}.${extensions}`)));
29
+ }
30
+ const agents = collectFirstPropertyValue(program, 'agents') ?? agentsPattern;
31
+ inputs.push(toProductionEntry(join(sourceRoot, agents)));
32
+ return inputs;
33
+ };
34
+ const plugin = {
35
+ title,
36
+ enablers,
37
+ isEnabled,
38
+ config,
39
+ production,
40
+ resolveFromAST,
41
+ };
42
+ export default plugin;
@@ -35,6 +35,7 @@ export declare const Plugins: {
35
35
  eve: import("../types/config.ts").Plugin;
36
36
  execa: import("../types/config.ts").Plugin;
37
37
  expo: import("../types/config.ts").Plugin;
38
+ 'expo-router': import("../types/config.ts").Plugin;
38
39
  'expressive-code': {
39
40
  title: string;
40
41
  enablers: string[];
@@ -42,6 +43,7 @@ export declare const Plugins: {
42
43
  config: string[];
43
44
  };
44
45
  fast: import("../types/config.ts").Plugin;
46
+ flue: import("../types/config.ts").Plugin;
45
47
  fumadocs: import("../types/config.ts").Plugin;
46
48
  gatsby: import("../types/config.ts").Plugin;
47
49
  'github-action': import("../types/config.ts").Plugin;
@@ -34,8 +34,10 @@ import { default as eslint } from './eslint/index.js';
34
34
  import { default as eve } from './eve/index.js';
35
35
  import { default as execa } from './execa/index.js';
36
36
  import { default as expo } from './expo/index.js';
37
+ import { default as expoRouter } from './expo-router/index.js';
37
38
  import { default as expressiveCode } from './expressive-code/index.js';
38
39
  import { default as fast } from './fast/index.js';
40
+ import { default as flue } from './flue/index.js';
39
41
  import { default as fumadocs } from './fumadocs/index.js';
40
42
  import { default as gatsby } from './gatsby/index.js';
41
43
  import { default as githubAction } from './github-action/index.js';
@@ -225,8 +227,10 @@ export const Plugins = {
225
227
  eve,
226
228
  execa,
227
229
  expo,
230
+ 'expo-router': expoRouter,
228
231
  'expressive-code': expressiveCode,
229
232
  fast,
233
+ flue,
230
234
  fumadocs,
231
235
  gatsby,
232
236
  'github-action': githubAction,