knip 6.38.0 → 6.39.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 (39) hide show
  1. package/dist/ConfigurationChief.d.ts +6 -0
  2. package/dist/constants.js +1 -0
  3. package/dist/graph/analyze.js +14 -5
  4. package/dist/graph-explorer/explorer.d.ts +1 -1
  5. package/dist/graph-explorer/operations/is-referenced.d.ts +1 -1
  6. package/dist/graph-explorer/operations/is-referenced.js +8 -4
  7. package/dist/plugins/_vue/auto-import.js +17 -10
  8. package/dist/plugins/angular/index.js +1 -1
  9. package/dist/plugins/cucumber/index.js +36 -4
  10. package/dist/plugins/cucumber/types.d.ts +2 -1
  11. package/dist/plugins/index.d.ts +1 -0
  12. package/dist/plugins/index.js +2 -0
  13. package/dist/plugins/playwright/index.js +3 -3
  14. package/dist/plugins/railway/index.d.ts +3 -0
  15. package/dist/plugins/railway/index.js +129 -0
  16. package/dist/plugins/rstest/index.js +116 -17
  17. package/dist/plugins/rstest/types.d.ts +29 -5
  18. package/dist/plugins/rstest/visitors/mock.d.ts +2 -0
  19. package/dist/plugins/rstest/visitors/mock.js +52 -0
  20. package/dist/plugins/vite/helpers.d.ts +1 -1
  21. package/dist/plugins/vite/helpers.js +7 -8
  22. package/dist/plugins/vitest/index.js +15 -5
  23. package/dist/plugins/vitest/types.d.ts +10 -0
  24. package/dist/schema/configuration.d.ts +15 -0
  25. package/dist/schema/plugins.d.ts +5 -0
  26. package/dist/schema/plugins.js +1 -0
  27. package/dist/types/PluginNames.d.ts +2 -2
  28. package/dist/types/PluginNames.js +1 -0
  29. package/dist/types/package-json.d.ts +5 -0
  30. package/dist/util/create-options.d.ts +10 -0
  31. package/dist/util/git.d.ts +1 -0
  32. package/dist/util/git.js +23 -1
  33. package/dist/util/package-json.d.ts +6 -0
  34. package/dist/util/tag.d.ts +1 -0
  35. package/dist/util/tag.js +1 -1
  36. package/dist/version.d.ts +1 -1
  37. package/dist/version.js +1 -1
  38. package/package.json +1 -1
  39. package/schema.json +4 -0
@@ -592,6 +592,11 @@ export declare class ConfigurationChief {
592
592
  entry?: string | string[] | undefined;
593
593
  project?: string | string[] | undefined;
594
594
  } | undefined;
595
+ railway?: string | boolean | string[] | {
596
+ config?: string | string[] | undefined;
597
+ entry?: string | string[] | undefined;
598
+ project?: string | string[] | undefined;
599
+ } | undefined;
595
600
  raycast?: string | boolean | string[] | {
596
601
  config?: string | string[] | undefined;
597
602
  entry?: string | string[] | undefined;
@@ -1132,6 +1137,7 @@ export declare class ConfigurationChief {
1132
1137
  prisma?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1133
1138
  quasar?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1134
1139
  qwik?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1140
+ railway?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1135
1141
  raycast?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1136
1142
  "react-cosmos"?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1137
1143
  "react-email"?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
package/dist/constants.js CHANGED
@@ -115,6 +115,7 @@ export const IGNORED_GLOBAL_BINARIES = new Set([
115
115
  'python',
116
116
  'python3',
117
117
  'raft',
118
+ 'railway',
118
119
  'rm',
119
120
  'rmdir',
120
121
  'rsync',
@@ -6,7 +6,7 @@ import { getPackageNameFromModuleSpecifier } from '../util/modules.js';
6
6
  import { relative } from '../util/path.js';
7
7
  import { perfObserver, timerify } from '../util/Performance.js';
8
8
  import { findMatch } from '../util/regex.js';
9
- import { getShouldIgnoreHandler, getShouldIgnoreTagHandler, isAlwaysIgnored } from '../util/tag.js';
9
+ import { getShouldIgnoreHandler, getShouldIgnoreTagHandler, hasTag, isAlwaysIgnored } from '../util/tag.js';
10
10
  import { INTERNAL_TAG } from '../constants.js';
11
11
  const toCyclePathKey = (path) => {
12
12
  const length = path.length > 1 && path[0] === path[path.length - 1] ? path.length - 1 : path.length;
@@ -123,7 +123,7 @@ export const analyze = async ({ analyzedFiles, counselor, chief, collector, depu
123
123
  const isInternalProd = options.isProduction && exportedItem.jsDocTags.has(INTERNAL_TAG);
124
124
  const isIgnored = shouldIgnoreTags(exportedItem.jsDocTags) || isInternalProd;
125
125
  if (importsForExport) {
126
- const [isReferenced, reExportingEntryFile] = explorer.isReferenced(filePath, identifier, {
126
+ const [isReferenced, reExportingEntryFile, reExportedIds] = explorer.isReferenced(filePath, identifier, {
127
127
  traverseEntries: isIncludeEntryExports,
128
128
  });
129
129
  if (isIgnored) {
@@ -148,9 +148,18 @@ export const analyze = async ({ analyzedFiles, counselor, chief, collector, depu
148
148
  if (!isIncludeEntryExports) {
149
149
  continue;
150
150
  }
151
- if (!isReferenced) {
152
- const reExportedItem = graph.get(reExportingEntryFile)?.exports.get(identifier);
153
- if (reExportedItem && shouldIgnore(reExportedItem.jsDocTags))
151
+ if (!isReferenced && reExportedIds) {
152
+ const entryExports = graph.get(reExportingEntryFile)?.exports;
153
+ let isTagged = false;
154
+ for (const id of reExportedIds) {
155
+ const reExportedItem = entryExports?.get(id);
156
+ if (reExportedItem &&
157
+ (shouldIgnore(reExportedItem.jsDocTags) || hasTag(options.tags[1], reExportedItem.jsDocTags))) {
158
+ isTagged = true;
159
+ break;
160
+ }
161
+ }
162
+ if (isTagged)
154
163
  continue;
155
164
  }
156
165
  }
@@ -3,7 +3,7 @@ export declare const createGraphExplorer: (graph: ModuleGraph, entryPaths: Set<s
3
3
  isReferenced: (filePath: string, identifier: string, options: {
4
4
  traverseEntries: boolean;
5
5
  treatStarAtEntryAsReferenced?: boolean;
6
- }) => readonly [false, string | undefined];
6
+ }) => readonly [false, string | undefined, Set<string> | undefined];
7
7
  hasStrictlyNsReferences: (filePath: string, identifier: string) => [boolean, (string | undefined)?];
8
8
  isEnumerated: (filePath: string, identifier: string) => boolean;
9
9
  buildExportsTree: (options: {
@@ -2,4 +2,4 @@ import type { Identifier, ModuleGraph } from '../../types/module-graph.ts';
2
2
  export declare const isReferenced: (graph: ModuleGraph, entryPaths: Set<string>, filePath: string, id: Identifier, options: {
3
3
  traverseEntries: boolean;
4
4
  treatStarAtEntryAsReferenced?: boolean;
5
- }) => readonly [false, string | undefined];
5
+ }) => readonly [false, string | undefined, Set<string> | undefined];
@@ -17,18 +17,22 @@ export const isReferenced = (graph, entryPaths, filePath, id, options) => {
17
17
  const seen = new Set();
18
18
  let isReferenced = false;
19
19
  let reExportingEntryFile;
20
+ let reExportedIds;
20
21
  const hasCompleteResult = () => isReferenced && (options.traverseEntries || reExportingEntryFile !== undefined);
21
22
  const walkDown = (path, id, viaStar = false) => {
22
23
  const isEntryFile = entryPaths.has(path);
23
24
  if (isEntryFile && !reExportingEntryFile)
24
25
  reExportingEntryFile = path;
26
+ if (path === reExportingEntryFile)
27
+ (reExportedIds ??= new Set()).add(id);
25
28
  if (hasCompleteResult())
26
29
  return true;
27
- if (seen.has(path))
28
- return false;
29
- seen.add(path);
30
30
  const restIds = id.split('.');
31
31
  const identifier = restIds.shift();
32
+ const key = `${path}:${identifier}`;
33
+ if (seen.has(key))
34
+ return false;
35
+ seen.add(key);
32
36
  if (options.treatStarAtEntryAsReferenced && isEntryFile && viaStar && restIds.length > 0) {
33
37
  isReferenced = true;
34
38
  return hasCompleteResult();
@@ -117,5 +121,5 @@ export const isReferenced = (graph, entryPaths, filePath, id, options) => {
117
121
  return false;
118
122
  };
119
123
  walkDown(filePath, id);
120
- return [isReferenced, reExportingEntryFile];
124
+ return [isReferenced, reExportingEntryFile, reExportedIds];
121
125
  };
@@ -3,10 +3,12 @@ import { createRequire } from 'node:module';
3
3
  import { Visitor } from 'oxc-parser';
4
4
  import { scriptBodies } from '../../compilers/compilers.js';
5
5
  import { stylePreprocessorImports } from '../../compilers/style-preprocessors.js';
6
+ import { DEFAULT_EXTENSIONS } from '../../constants.js';
6
7
  import { _parseFile } from '../../typescript/ast-nodes.js';
7
8
  import { isFile } from '../../util/fs.js';
8
9
  import { _syncGlob } from '../../util/glob.js';
9
10
  import { dirname, isInNodeModules, join } from '../../util/path.js';
11
+ import { _createSyncModuleResolver } from '../../util/resolve.js';
10
12
  const getVueSfc = (cwd) => {
11
13
  try {
12
14
  const sfc = createRequire(join(cwd, 'package.json'))('vue/compiler-sfc');
@@ -124,6 +126,7 @@ const collectVue2TemplateIdentifiers = (source) => {
124
126
  };
125
127
  const toKebabCase = (s) => s.replace(/[A-Z]/g, (m, i) => (i ? '-' : '') + m.toLowerCase());
126
128
  const isLocalSpecifier = (specifier) => specifier.startsWith('.') && !isInNodeModules(specifier);
129
+ const resolveModule = _createSyncModuleResolver([...DEFAULT_EXTENSIONS, '.vue']);
127
130
  export const collectLocalImportPaths = (filePath, result) => {
128
131
  const dir = dirname(filePath);
129
132
  const paths = new Set();
@@ -150,7 +153,7 @@ export function buildAutoImportMap(filePath, result, maps, isComponents) {
150
153
  const importType = importTypes.find(it => it.start >= start && it.end <= end);
151
154
  if (!importType || !isLocalSpecifier(importType.specifier))
152
155
  return;
153
- const absSpecifier = join(dir, importType.specifier);
156
+ const absSpecifier = resolveModule(importType.specifier, filePath) ?? join(dir, importType.specifier);
154
157
  if (isComponents) {
155
158
  const components = maps.componentMap.get(name);
156
159
  if (components) {
@@ -184,7 +187,7 @@ export function buildAutoImportMap(filePath, result, maps, isComponents) {
184
187
  const specifier = node.source.value;
185
188
  if (!isLocalSpecifier(specifier))
186
189
  return;
187
- const absSpecifier = join(dir, specifier);
190
+ const absSpecifier = resolveModule(specifier, filePath) ?? join(dir, specifier);
188
191
  for (const s of node.specifiers) {
189
192
  const name = s.exported.type === 'Identifier' ? s.exported.name : s.exported.value;
190
193
  if (name)
@@ -210,14 +213,15 @@ const getVueAutoImportMaps = (cwd) => {
210
213
  }
211
214
  return maps;
212
215
  };
213
- const getSyntheticImports = (maps, identifiers, templateTags) => {
216
+ const getSyntheticImports = (maps, identifiers, filePath, templateTags) => {
214
217
  const { importMap, componentMap } = maps;
215
218
  if (importMap.size === 0 && (!templateTags || componentMap.size === 0))
216
219
  return [];
217
220
  const syntheticImports = [];
218
221
  for (const [name, specifier] of importMap) {
219
- if (identifiers.has(name))
222
+ if (identifiers.has(name) && specifier !== filePath) {
220
223
  syntheticImports.push(`import { ${name} } from '${specifier}';`);
224
+ }
221
225
  }
222
226
  if (templateTags) {
223
227
  for (const [name, specifiers] of componentMap) {
@@ -226,9 +230,12 @@ const getSyntheticImports = (maps, identifiers, templateTags) => {
226
230
  templateTags.has(kebab) ||
227
231
  templateTags.has(`Lazy${name}`) ||
228
232
  templateTags.has(`lazy-${kebab}`)) {
229
- syntheticImports.push(`import { default as ${name} } from '${specifiers[0]}';`);
230
- for (let i = 1; i < specifiers.length; i++)
231
- syntheticImports.push(`import '${specifiers[i]}';`);
233
+ const targets = specifiers.filter(specifier => specifier !== filePath);
234
+ if (targets.length === 0)
235
+ continue;
236
+ syntheticImports.push(`import { default as ${name} } from '${targets[0]}';`);
237
+ for (let i = 1; i < targets.length; i++)
238
+ syntheticImports.push(`import '${targets[i]}';`);
232
239
  }
233
240
  }
234
241
  }
@@ -275,7 +282,7 @@ const compileVueSfc = (source, path, maps, root) => {
275
282
  for (const id of collectVue2TemplateIdentifiers(compiled.code))
276
283
  identifiers.add(id);
277
284
  }
278
- scripts.push(...getSyntheticImports(maps, identifiers, templateTags));
285
+ scripts.push(...getSyntheticImports(maps, identifiers, path, templateTags));
279
286
  scripts.push(...getImportedComponentImports(maps, importedComponents));
280
287
  const styles = stylePreprocessorImports(source, path);
281
288
  if (styles)
@@ -288,7 +295,7 @@ const compileTs = (source, path, maps) => {
288
295
  path.endsWith('.config.ts'))
289
296
  return source;
290
297
  const importedComponents = new Set();
291
- const syntheticImports = getSyntheticImports(maps, collectIdentifiers(source, path, importedComponents));
298
+ const syntheticImports = getSyntheticImports(maps, collectIdentifiers(source, path, importedComponents), path);
292
299
  syntheticImports.push(...getImportedComponentImports(maps, importedComponents));
293
300
  return syntheticImports.length === 0 ? source : `${source}\n${syntheticImports.join('\n')}`;
294
301
  };
@@ -305,7 +312,7 @@ const compileMarkdown = (source, path, maps) => {
305
312
  for (const [, tag] of code.matchAll(tagMatcher))
306
313
  tags.add(tag);
307
314
  const identifiers = scripts ? collectIdentifiers(scripts, path) : new Set();
308
- return [scripts, ...getSyntheticImports(maps, identifiers, tags)].filter(Boolean).join(';\n');
315
+ return [scripts, ...getSyntheticImports(maps, identifiers, path, tags)].filter(Boolean).join(';\n');
309
316
  };
310
317
  export const createVueCompiler = (maps, cwd) => (source, path) => compileVueSfc(source, path, maps, cwd);
311
318
  export const createTsCompiler = (maps) => (source, path) => compileTs(source, path, maps);
@@ -13,7 +13,7 @@ const resolveConfig = async (config, options) => {
13
13
  const inputs = new Set();
14
14
  for (const project of Object.values(config.projects)) {
15
15
  if (!project.architect)
16
- return [];
16
+ continue;
17
17
  for (const [targetName, target] of Object.entries(project.architect)) {
18
18
  const { options: opts, configurations: configs } = target;
19
19
  const [packageName] = typeof target.builder === 'string' ? target.builder.split(':') : [];
@@ -5,11 +5,43 @@ const enablers = ['@cucumber/cucumber'];
5
5
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
6
6
  const config = ['cucumber.{json,yaml,yml,js,cjs,mjs}'];
7
7
  const entry = ['features/**/*.@(js|cjs|mjs)'];
8
- const resolveConfig = config => {
8
+ const builtinFormatters = new Set([
9
+ 'html',
10
+ 'json',
11
+ 'junit',
12
+ 'message',
13
+ 'pretty',
14
+ 'progress',
15
+ 'progress-bar',
16
+ 'rerun',
17
+ 'snippets',
18
+ 'summary',
19
+ 'usage',
20
+ 'usage-json',
21
+ ]);
22
+ const toFormatterName = (format) => {
23
+ if (Array.isArray(format))
24
+ return format[0];
25
+ const [name, quotedName] = format.match(/^"([^"]*)"|^[^:]*/) ?? [format];
26
+ return quotedName ?? name;
27
+ };
28
+ const resolveProfile = (config) => {
9
29
  const imports = (config?.import ? config.import : entry).map(id => toEntry(id));
10
- const formatters = config?.format ? config.format : [];
11
- const requires = config?.require ? config.require : [];
12
- return imports.concat([...formatters, ...requires].map(id => toDeferResolve(id)));
30
+ const requires = (config?.require ? config.require : []).map(id => toEntry(id));
31
+ const formatters = (config?.format ? config.format : [])
32
+ .map(toFormatterName)
33
+ .filter(name => !builtinFormatters.has(name))
34
+ .map(id => toDeferResolve(id));
35
+ return [...imports, ...requires, ...formatters];
36
+ };
37
+ const resolveConfig = (config, options) => {
38
+ if (typeof config !== 'object' || config === null)
39
+ return resolveProfile();
40
+ const isProfiles = /\.(json|ya?ml)$/.test(options.configFileName) || 'default' in config;
41
+ if (!isProfiles)
42
+ return resolveProfile(config);
43
+ const profiles = 'default' in config ? Object.values(config) : [undefined, ...Object.values(config)];
44
+ return profiles.flatMap(resolveProfile);
13
45
  };
14
46
  const plugin = {
15
47
  title,
@@ -2,6 +2,7 @@ export type CucumberConfig = {
2
2
  publishQuiet?: boolean;
3
3
  import?: string[];
4
4
  require?: string[];
5
- format?: string[];
5
+ format?: Format[];
6
6
  parallel?: number;
7
7
  };
8
+ export type Format = string | [string, string?];
@@ -111,6 +111,7 @@ export declare const Plugins: {
111
111
  prisma: import("../types/config.ts").Plugin;
112
112
  quasar: import("../types/config.ts").Plugin;
113
113
  qwik: import("../types/config.ts").Plugin;
114
+ railway: import("../types/config.ts").Plugin;
114
115
  raycast: import("../types/config.ts").Plugin;
115
116
  'react-cosmos': import("../types/config.ts").Plugin;
116
117
  'react-email': import("../types/config.ts").Plugin;
@@ -105,6 +105,7 @@ import { default as prettier } from './prettier/index.js';
105
105
  import { default as prisma } from './prisma/index.js';
106
106
  import { default as quasar } from './quasar/index.js';
107
107
  import { default as qwik } from './qwik/index.js';
108
+ import { default as railway } from './railway/index.js';
108
109
  import { default as raycast } from './raycast/index.js';
109
110
  import { default as reactCosmos } from './react-cosmos/index.js';
110
111
  import { default as reactEmail } from './react-email/index.js';
@@ -293,6 +294,7 @@ export const Plugins = {
293
294
  prisma,
294
295
  quasar,
295
296
  qwik,
297
+ railway,
296
298
  raycast,
297
299
  'react-cosmos': reactCosmos,
298
300
  'react-email': reactEmail,
@@ -1,6 +1,6 @@
1
1
  import { arrayify } from '../../util/array.js';
2
2
  import { toDeferResolve, toEntry } from '../../util/input.js';
3
- import { join, relative } from '../../util/path.js';
3
+ import { join, relative, toAbsolute } from '../../util/path.js';
4
4
  import { hasDependency } from '../../util/plugin.js';
5
5
  const title = 'Playwright';
6
6
  const enablers = ['@playwright/test'];
@@ -18,9 +18,9 @@ export const resolveConfig = async (localConfig, options) => {
18
18
  const { cwd, configFileDir } = options;
19
19
  const inputs = [];
20
20
  for (const id of arrayify(localConfig.globalSetup))
21
- inputs.push(toEntry(id));
21
+ inputs.push(toEntry(toAbsolute(id, configFileDir)));
22
22
  for (const id of arrayify(localConfig.globalTeardown))
23
- inputs.push(toEntry(id));
23
+ inputs.push(toEntry(toAbsolute(id, configFileDir)));
24
24
  const projects = localConfig.projects ? [localConfig, ...localConfig.projects] : [localConfig];
25
25
  const reporters = [localConfig.reporter].flat().flatMap(reporter => {
26
26
  const name = typeof reporter === 'string' ? reporter : reporter?.[0];
@@ -0,0 +1,3 @@
1
+ import type { Plugin } from '../../types/config.ts';
2
+ declare const plugin: Plugin;
3
+ export default plugin;
@@ -0,0 +1,129 @@
1
+ import { Visitor } from 'oxc-parser';
2
+ import { findProperty, getFirstPropertyValue, getStringValues } from '../../typescript/ast-helpers.js';
3
+ import { getStringValue } from '../../typescript/ast-nodes.js';
4
+ import { getGitRemoteUrls } from '../../util/git.js';
5
+ import { isEntry } from '../../util/input.js';
6
+ import { join, toAbsolute } from '../../util/path.js';
7
+ import { hasDependency } from '../../util/plugin.js';
8
+ const title = 'Railway';
9
+ const enablers = ['railway'];
10
+ const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
11
+ const config = ['.railway/railway.ts'];
12
+ const args = {
13
+ config: ['file'],
14
+ resolve: ['runner'],
15
+ };
16
+ const getCommands = (node) => {
17
+ const command = getStringValue(node);
18
+ return command ? [command] : [...getStringValues(node)];
19
+ };
20
+ const isExternalSourceType = (type) => type === 'github' || type === 'image' || type === 'template';
21
+ const getGitHubRepository = (value) => {
22
+ const normalized = value
23
+ ?.trim()
24
+ .replace(/^git\+/, '')
25
+ .replace(/\.git\/?$/, '')
26
+ .replace(/\/$/, '');
27
+ return normalized?.match(/(?:^|github(?:\.com)?[/:])([^/:]+\/[^/]+)$/i)?.[1].toLowerCase();
28
+ };
29
+ const resolveFromAST = (program, options) => {
30
+ const serviceNames = new Set();
31
+ const sourceTypes = new Map();
32
+ const bindings = new Map();
33
+ const localRepositories = new Set();
34
+ for (const repository of [options.manifest.repository, options.rootManifest?.repository]) {
35
+ const name = getGitHubRepository(typeof repository === 'string' ? repository : repository?.url);
36
+ if (name)
37
+ localRepositories.add(name);
38
+ }
39
+ for (const url of getGitRemoteUrls(options.rootCwd)) {
40
+ const name = getGitHubRepository(url);
41
+ if (name)
42
+ localRepositories.add(name);
43
+ }
44
+ for (const node of program.body) {
45
+ if (node.type === 'ImportDeclaration' && getStringValue(node.source) === 'railway/iac') {
46
+ for (const specifier of node.specifiers) {
47
+ if (specifier.type !== 'ImportSpecifier' || specifier.imported.type !== 'Identifier')
48
+ continue;
49
+ if (specifier.imported.name === 'service')
50
+ serviceNames.add(specifier.local.name);
51
+ if (isExternalSourceType(specifier.imported.name)) {
52
+ sourceTypes.set(specifier.local.name, specifier.imported.name);
53
+ }
54
+ }
55
+ }
56
+ else if (node.type === 'VariableDeclaration') {
57
+ for (const declaration of node.declarations) {
58
+ if (declaration.id.type === 'Identifier' && declaration.init)
59
+ bindings.set(declaration.id.name, declaration.init);
60
+ }
61
+ }
62
+ }
63
+ const resolveBinding = (node) => {
64
+ const seen = new Set();
65
+ while (node?.type === 'Identifier' && bindings.has(node.name) && !seen.has(node.name)) {
66
+ seen.add(node.name);
67
+ node = bindings.get(node.name);
68
+ }
69
+ return node;
70
+ };
71
+ const inputs = [];
72
+ const visitor = new Visitor({
73
+ CallExpression(node) {
74
+ if (node.callee.type !== 'Identifier' || !serviceNames.has(node.callee.name))
75
+ return;
76
+ const serviceConfig = node.arguments[1];
77
+ if (serviceConfig?.type !== 'ObjectExpression')
78
+ return;
79
+ const source = resolveBinding(findProperty(serviceConfig, 'source'));
80
+ const repository = getFirstPropertyValue(source, 'repo');
81
+ const image = getFirstPropertyValue(source, 'image');
82
+ const template = getFirstPropertyValue(source, 'template');
83
+ const sourceType = (source?.type === 'CallExpression' && source.callee.type === 'Identifier'
84
+ ? sourceTypes.get(source.callee.name)
85
+ : undefined) ??
86
+ getFirstPropertyValue(source, 'type') ??
87
+ (repository ? 'github' : image ? 'image' : template ? 'template' : undefined);
88
+ const sourceRepository = getGitHubRepository(source?.type === 'CallExpression' ? getStringValue(source.arguments[0]) : repository);
89
+ if (sourceType === 'image' ||
90
+ sourceType === 'template' ||
91
+ (sourceType === 'github' &&
92
+ sourceRepository !== undefined &&
93
+ localRepositories.size > 0 &&
94
+ !localRepositories.has(sourceRepository))) {
95
+ return;
96
+ }
97
+ const sourceConfig = source?.type === 'CallExpression' ? source.arguments[1] : source;
98
+ const rootDirectory = getFirstPropertyValue(sourceConfig, 'rootDirectory') ??
99
+ getFirstPropertyValue(serviceConfig, 'root') ??
100
+ getFirstPropertyValue(serviceConfig, 'rootDirectory');
101
+ const cwd = rootDirectory ? join(options.cwd, rootDirectory) : options.cwd;
102
+ const manifest = options.getManifest(cwd) ?? options.manifest;
103
+ const build = findProperty(serviceConfig, 'build');
104
+ const commands = [
105
+ ...getCommands(build),
106
+ ...getCommands(findProperty(build, 'buildCommand')),
107
+ ...getCommands(findProperty(serviceConfig, 'start')),
108
+ ...getCommands(findProperty(serviceConfig, 'preDeploy')),
109
+ ...getCommands(findProperty(findProperty(serviceConfig, 'deploy'), 'preDeployCommand')),
110
+ ];
111
+ for (const input of options.getInputsFromScripts(commands, { optionalBinaries: true, cwd, manifest })) {
112
+ if (isEntry(input))
113
+ input.specifier = toAbsolute(input.specifier, cwd);
114
+ inputs.push({ ...input, dir: cwd });
115
+ }
116
+ },
117
+ });
118
+ visitor.visit(program);
119
+ return inputs;
120
+ };
121
+ const plugin = {
122
+ title,
123
+ enablers,
124
+ isEnabled,
125
+ config,
126
+ args,
127
+ resolveFromAST,
128
+ };
129
+ export default plugin;
@@ -1,31 +1,130 @@
1
- import { toDeferResolve, toEntry } from '../../util/input.js';
2
- import { hasDependency } from '../../util/plugin.js';
1
+ import { arrayify } from '../../util/array.js';
2
+ import { findFileWithExtensions } from '../../util/fs.js';
3
+ import { _dirGlob, _glob, negate } from '../../util/glob.js';
4
+ import { toAlias, toConfig, toDeferResolve, toDependency, toEntry } from '../../util/input.js';
5
+ import { dirname, join, relative, toAbsolute } from '../../util/path.js';
6
+ import { hasDependency, load } from '../../util/plugin.js';
7
+ import { createRstestMockVisitor } from './visitors/mock.js';
3
8
  const title = 'Rstest';
4
9
  const enablers = ['@rstest/core'];
5
10
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
11
+ const configExtensions = ['.mts', '.mjs', '.ts', '.js', '.cjs', '.cts'];
6
12
  const config = ['rstest.config.{js,cjs,mjs,ts,cts,mts}'];
7
13
  const mocks = ['**/__mocks__/**/*.?(c|m)[jt]s?(x)'];
8
- const entry = ['**/*.{test,spec}.?(c|m)[jt]s?(x)'];
9
- function testEnvironment(config) {
10
- const environment = typeof config.testEnvironment === 'string' ? config.testEnvironment : config.testEnvironment?.name;
11
- if (!environment || environment === 'node')
12
- return [];
13
- return [environment];
14
- }
15
- const resolveConfig = async (config) => {
16
- const entries = (config.include ?? entry)
17
- .concat(...mocks)
18
- .map(toEntry)
19
- .concat(...(config.exclude ?? []).map(id => toEntry(`!${id}`)));
20
- const environments = testEnvironment(config);
21
- const setupFiles = config.setupFiles ?? [];
22
- return [...environments, ...setupFiles, ...entries].map(id => (typeof id === 'string' ? toDeferResolve(id) : id));
14
+ const testEntry = ['**/*.{test,spec}.?(c|m)[jt]s?(x)'];
15
+ const entry = [...testEntry, ...mocks];
16
+ const getEnvironmentDependency = (name) => (name && name !== 'node' ? [toDependency(name)] : []);
17
+ const replaceRootDir = (path, root) => path.replace('<rootDir>', root);
18
+ const configParams = { env: 'test', command: 'run', envMode: 'test' };
19
+ const getConfig = async (config) => typeof config === 'function' ? await config(configParams) : config;
20
+ const resolveConfig = async (localConfig, options) => {
21
+ const { cwd, configFileDir, configFilePath, getManifest, isResolvedConfigFile } = options;
22
+ const cfg = await getConfig(localConfig);
23
+ const runnerRoot = toAbsolute(cfg.root ?? '.', isResolvedConfigFile ? configFileDir : cwd);
24
+ const manifest = getManifest(cwd);
25
+ const seen = new Set([configFilePath]);
26
+ const inputs = [];
27
+ const addProject = async (project, projectRoot) => {
28
+ const toPattern = (pattern) => relative(cwd, toAbsolute(replaceRootDir(pattern, projectRoot), projectRoot));
29
+ if (!options.config.entry) {
30
+ const include = [];
31
+ const exclude = [...(Array.isArray(project.exclude) ? project.exclude : (project.exclude?.patterns ?? []))];
32
+ for (const pattern of [...(project.include ?? testEntry), ...mocks]) {
33
+ if (pattern.startsWith('!'))
34
+ exclude.push(pattern.slice(1));
35
+ else
36
+ include.push(toPattern(pattern));
37
+ }
38
+ const entries = exclude.length === 0
39
+ ? include
40
+ : await _glob({ cwd, patterns: [...include, ...exclude.map(pattern => negate(toPattern(pattern)))] });
41
+ for (const entry of entries)
42
+ inputs.push(toEntry(entry));
43
+ }
44
+ const env = project.testEnvironment;
45
+ inputs.push(...getEnvironmentDependency(typeof env === 'string' ? env : env?.name));
46
+ for (const specifier of [project.setupFiles ?? [], project.globalSetup ?? []].flat()) {
47
+ inputs.push(toDeferResolve(replaceRootDir(specifier, projectRoot), { dir: projectRoot }));
48
+ }
49
+ if (project.browser?.enabled) {
50
+ inputs.push(toDependency('@rstest/browser'), toDependency('playwright'));
51
+ }
52
+ for (const [name, value] of Object.entries(project.resolve?.alias ?? {})) {
53
+ const prefixes = [];
54
+ for (const target of arrayify(value))
55
+ prefixes.push(target.startsWith('.') ? join(runnerRoot, target) : target);
56
+ if (name.endsWith('$')) {
57
+ inputs.push(toAlias(name.slice(0, -1), prefixes));
58
+ }
59
+ else {
60
+ inputs.push(toAlias(name, prefixes), toAlias(`${name}/*`, prefixes.map(prefix => `${prefix}/*`)));
61
+ }
62
+ }
63
+ };
64
+ const addProjects = async (projects, projectsRoot) => {
65
+ const patterns = [];
66
+ for (const project of projects) {
67
+ if (typeof project === 'string')
68
+ patterns.push(replaceRootDir(project, projectsRoot));
69
+ else
70
+ await addProject(project, toAbsolute(replaceRootDir(project.root ?? projectsRoot, projectsRoot), runnerRoot));
71
+ }
72
+ const [files, dirs] = await Promise.all([
73
+ _glob({ cwd: projectsRoot, patterns, gitignore: false }),
74
+ _dirGlob({ cwd: projectsRoot, patterns, gitignore: false }),
75
+ ]);
76
+ for (const dir of dirs) {
77
+ const projectRoot = toAbsolute(dir, projectsRoot);
78
+ const filePath = findFileWithExtensions(join(projectRoot, 'rstest.config'), configExtensions);
79
+ if (filePath)
80
+ files.push(filePath);
81
+ else
82
+ await addProject({}, projectRoot);
83
+ }
84
+ for (const filePath of files) {
85
+ if (seen.has(filePath))
86
+ continue;
87
+ seen.add(filePath);
88
+ const project = getManifest(dirname(filePath)) === manifest
89
+ ? await load(filePath)
90
+ .then(getConfig)
91
+ .catch(() => undefined)
92
+ : undefined;
93
+ if (!project) {
94
+ inputs.push(toConfig('rstest', filePath, { containingFilePath: configFilePath }));
95
+ continue;
96
+ }
97
+ inputs.push(toEntry(filePath));
98
+ if (project.projects)
99
+ await addProjects(project.projects, dirname(filePath));
100
+ else
101
+ await addProject(project, toAbsolute(project.root ?? dirname(filePath), runnerRoot));
102
+ }
103
+ };
104
+ if (cfg.projects)
105
+ await addProjects(cfg.projects, runnerRoot);
106
+ else
107
+ await addProject(cfg, runnerRoot);
108
+ if (!isResolvedConfigFile) {
109
+ inputs.push(toDependency(`@rstest/coverage-${cfg.coverage?.provider ?? 'istanbul'}`, { optional: true }));
110
+ }
111
+ return inputs;
112
+ };
113
+ const args = {
114
+ config: true,
115
+ resolveInputs: parsed => getEnvironmentDependency(parsed.testEnvironment),
116
+ };
117
+ const registerVisitors = ({ ctx, registerVisitor }) => {
118
+ registerVisitor(createRstestMockVisitor(ctx));
23
119
  };
24
120
  const plugin = {
25
121
  title,
26
122
  enablers,
27
123
  isEnabled,
28
124
  config,
125
+ entry,
29
126
  resolveConfig,
127
+ args,
128
+ registerVisitors,
30
129
  };
31
130
  export default plugin;
@@ -1,8 +1,32 @@
1
- export type RstestConfig = {
1
+ type TestEnvironment = 'node' | 'jsdom' | 'happy-dom';
2
+ export type RstestProjectConfig = {
3
+ root?: string;
2
4
  include?: string[];
3
- exclude?: string[];
4
- testEnvironment?: 'node' | 'jsdom' | 'happy-dom' | {
5
- name: 'node' | 'jsdom' | 'happy-dom';
5
+ exclude?: string[] | {
6
+ patterns: string[];
6
7
  };
7
- setupFiles?: string[];
8
+ testEnvironment?: TestEnvironment | {
9
+ name: TestEnvironment;
10
+ };
11
+ setupFiles?: string | string[];
12
+ globalSetup?: string | string[];
13
+ browser?: {
14
+ enabled?: boolean;
15
+ };
16
+ resolve?: {
17
+ alias?: Record<string, string | false | (string | false)[]>;
18
+ };
19
+ };
20
+ type RstestConfig = RstestProjectConfig & {
21
+ projects?: (string | RstestProjectConfig)[];
22
+ coverage?: {
23
+ provider?: 'istanbul' | 'v8';
24
+ };
25
+ };
26
+ type ConfigParams = {
27
+ env: string;
28
+ command: string;
29
+ envMode: string;
8
30
  };
31
+ export type RstestConfigOrFn = RstestConfig | ((params: ConfigParams) => RstestConfig | Promise<RstestConfig>);
32
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { PluginVisitorContext, PluginVisitorObject } from '../../../types/config.ts';
2
+ export declare function createRstestMockVisitor(ctx: PluginVisitorContext): PluginVisitorObject;
@@ -0,0 +1,52 @@
1
+ import { IMPORT_FLAGS } from '../../../constants.js';
2
+ import { getStringValue, isStringLiteral } from '../../../typescript/ast-nodes.js';
3
+ import { isShadowed } from '../../../typescript/visitors/walk.js';
4
+ const rstestApiNames = new Set(['rs', 'rstest']);
5
+ const mockMethods = new Set(['mock', 'doMock']);
6
+ export function createRstestMockVisitor(ctx) {
7
+ const rsNames = new Set();
8
+ return {
9
+ Program(node) {
10
+ rsNames.clear();
11
+ for (const statement of node.body) {
12
+ if (statement.type !== 'ImportDeclaration' ||
13
+ !isStringLiteral(statement.source) ||
14
+ getStringValue(statement.source) !== '@rstest/core')
15
+ continue;
16
+ for (const specifier of statement.specifiers ?? []) {
17
+ if (specifier.type === 'ImportSpecifier' &&
18
+ specifier.imported.type === 'Identifier' &&
19
+ rstestApiNames.has(specifier.imported.name)) {
20
+ rsNames.add(specifier.local.name);
21
+ }
22
+ }
23
+ }
24
+ },
25
+ CallExpression(node) {
26
+ const argument = node.arguments[0];
27
+ const factory = node.arguments[1];
28
+ const factoryBody = factory?.type === 'ArrowFunctionExpression' &&
29
+ factory.body.type === 'ParenthesizedExpression' &&
30
+ factory.body.expression.type === 'ObjectExpression'
31
+ ? factory.body.expression
32
+ : undefined;
33
+ if (argument?.type !== 'ImportExpression' ||
34
+ !isStringLiteral(argument.source) ||
35
+ factory?.type !== 'ArrowFunctionExpression' ||
36
+ !factoryBody ||
37
+ factory.async ||
38
+ factory.params.length > 0 ||
39
+ factoryBody.properties.some(property => property.type === 'SpreadElement') ||
40
+ node.callee.type !== 'MemberExpression' ||
41
+ node.callee.computed ||
42
+ node.callee.object.type !== 'Identifier' ||
43
+ !rsNames.has(node.callee.object.name) ||
44
+ isShadowed(node.callee.object.name, node.callee.object.start) ||
45
+ node.callee.property.type !== 'Identifier' ||
46
+ !mockMethods.has(node.callee.property.name))
47
+ return;
48
+ ctx.markImportExpressionHandled(argument.start);
49
+ ctx.addImport(getStringValue(argument.source), argument.source.start, IMPORT_FLAGS.SIDE_EFFECTS);
50
+ },
51
+ };
52
+ }
@@ -1,6 +1,6 @@
1
1
  import type { Program } from 'oxc-parser';
2
2
  import { type Input } from '../../util/input.ts';
3
3
  export declare const getBabelInputs: (program: Program) => Input[];
4
- export declare const getHtmlScriptEntries: (htmlPath: string, publicDir?: string) => Promise<Input[]>;
4
+ export declare const getHtmlScriptEntries: (htmlPath: string, rootDir?: string, publicDir?: string) => Promise<Input[]>;
5
5
  export declare const getIndexHtmlEntries: (rootDir: string, publicDir?: string) => Promise<Input[]>;
6
6
  export declare const getVitePluginDirs: (program: Program, specifiers: string[], key: string) => string[] | undefined;
@@ -25,9 +25,9 @@ const moduleTypePattern = /\btype\s*=\s*["']?module["']?/i;
25
25
  const srcAttrPattern = /\bsrc\s*=\s*["']([^"']+)["']/i;
26
26
  const importSpecPattern = /\bimport\b(?:\s*\(\s*|(?:[\w$*,{}\s]*\bfrom\b)?\s*)(['"])([^'"]+)\1/g;
27
27
  const isFilePath = (specifier) => specifier.startsWith('/') || specifier.startsWith('./') || specifier.startsWith('../');
28
- const normalizeModuleScriptSrc = (value) => value.trim().replace(/^\//, '');
29
- const getScriptSources = (html, publicDir) => {
28
+ const getScriptSources = (html, htmlDir, rootDir, publicDir) => {
30
29
  const sources = [];
30
+ const resolveSource = (src) => (src.startsWith('/') ? join(rootDir, src) : toAbsolute(src, htmlDir));
31
31
  for (const [, attrs, body] of html.matchAll(scriptExtractor)) {
32
32
  const srcMatch = attrs.match(srcAttrPattern);
33
33
  if (srcMatch) {
@@ -42,7 +42,7 @@ const getScriptSources = (html, publicDir) => {
42
42
  }
43
43
  }
44
44
  if (moduleTypePattern.test(attrs))
45
- sources.push(normalizeModuleScriptSrc(src));
45
+ sources.push(resolveSource(src));
46
46
  continue;
47
47
  }
48
48
  if (moduleTypePattern.test(attrs) && body) {
@@ -50,20 +50,19 @@ const getScriptSources = (html, publicDir) => {
50
50
  for (const importMatch of code.matchAll(importSpecPattern)) {
51
51
  const specifier = importMatch[2];
52
52
  if (isFilePath(specifier))
53
- sources.push(normalizeModuleScriptSrc(specifier));
53
+ sources.push(resolveSource(specifier));
54
54
  }
55
55
  }
56
56
  }
57
57
  return sources;
58
58
  };
59
- export const getHtmlScriptEntries = async (htmlPath, publicDir) => {
59
+ export const getHtmlScriptEntries = async (htmlPath, rootDir = dirname(htmlPath), publicDir) => {
60
60
  if (!isFile(htmlPath))
61
61
  return [];
62
62
  const html = await loadFile(htmlPath);
63
- const dir = dirname(htmlPath);
64
- return getScriptSources(html, publicDir).map(src => toProductionEntry(toAbsolute(src, dir)));
63
+ return getScriptSources(html, dirname(htmlPath), rootDir, publicDir).map(src => toProductionEntry(src));
65
64
  };
66
- export const getIndexHtmlEntries = (rootDir, publicDir) => getHtmlScriptEntries(join(rootDir, 'index.html'), publicDir);
65
+ export const getIndexHtmlEntries = (rootDir, publicDir) => getHtmlScriptEntries(join(rootDir, 'index.html'), rootDir, publicDir);
67
66
  export const getVitePluginDirs = (program, specifiers, key) => {
68
67
  let dirs;
69
68
  for (const call of findImportedCalls(program, specifiers)) {
@@ -1,10 +1,10 @@
1
1
  import { DEFAULT_EXTENSIONS } from '../../constants.js';
2
2
  import { _glob } from '../../util/glob.js';
3
- import { toConfig, toDeferResolve, toDependency, toEntry } from '../../util/input.js';
3
+ import { toConfig, toDeferResolve, toDependency, toEntry, toProductionEntry } from '../../util/input.js';
4
4
  import { getPackageNameFromModuleSpecifier } from '../../util/modules.js';
5
5
  import { isAbsolute, isInternal, join, toAbsolute, toPosix } from '../../util/path.js';
6
6
  import { hasDependency } from '../../util/plugin.js';
7
- import { getIndexHtmlEntries } from '../vite/helpers.js';
7
+ import { getHtmlScriptEntries, getIndexHtmlEntries } from '../vite/helpers.js';
8
8
  import { getAliasInputs, getEnvSpecifier, getExternalReporters } from './helpers.js';
9
9
  import { createVitestMockVisitor } from './visitors/mock.js';
10
10
  const title = 'Vitest';
@@ -135,11 +135,11 @@ export const resolveConfig = async (localConfig, options) => {
135
135
  const seenRoots = new Set();
136
136
  for (const cfg of configs) {
137
137
  const viteRoot = toAbsolute(cfg.root ?? '.', options.cwd);
138
+ const publicDir = cfg.publicDir === false || cfg.publicDir === ''
139
+ ? undefined
140
+ : toAbsolute(toPosix(cfg.publicDir ?? 'public'), viteRoot);
138
141
  if (!seenRoots.has(viteRoot)) {
139
142
  seenRoots.add(viteRoot);
140
- const publicDir = cfg.publicDir === false || cfg.publicDir === ''
141
- ? undefined
142
- : toAbsolute(toPosix(cfg.publicDir ?? 'public'), viteRoot);
143
143
  for (const entry of await getIndexHtmlEntries(viteRoot, publicDir))
144
144
  inputs.add(entry);
145
145
  }
@@ -189,6 +189,16 @@ export const resolveConfig = async (localConfig, options) => {
189
189
  }
190
190
  for (const dependency of findConfigDependencies(cfg, options, vitestRoot))
191
191
  inputs.add(dependency);
192
+ const _input = cfg.build?.rolldownOptions?.input ?? cfg.build?.rollupOptions?.input ?? [];
193
+ const inputSpecifiers = typeof _input === 'string' ? [_input] : Array.isArray(_input) ? _input : Object.values(_input).flat();
194
+ for (const specifier of inputSpecifiers) {
195
+ const resolved = toAbsolute(specifier, viteRoot);
196
+ inputs.add(toProductionEntry(resolved));
197
+ if (resolved.endsWith('.html')) {
198
+ for (const input of await getHtmlScriptEntries(resolved, viteRoot, publicDir))
199
+ inputs.add(input);
200
+ }
201
+ }
192
202
  const _entry = cfg.build?.lib?.entry ?? [];
193
203
  const entries = typeof _entry === 'string' ? [_entry] : Array.isArray(_entry) ? _entry : Object.values(_entry).flat();
194
204
  const deps = entries.map(specifier => join(viteRoot, specifier)).map(id => toEntry(id));
@@ -42,6 +42,16 @@ export interface ViteConfig extends VitestConfig {
42
42
  publicDir?: string | false;
43
43
  plugins?: unknown[];
44
44
  build?: {
45
+ rolldownOptions?: {
46
+ input?: string | string[] | {
47
+ [entryAlias: string]: string | string[];
48
+ };
49
+ };
50
+ rollupOptions?: {
51
+ input?: string | string[] | {
52
+ [entryAlias: string]: string | string[];
53
+ };
54
+ };
45
55
  lib?: {
46
56
  entry: string | string[] | {
47
57
  [entryAlias: string]: string | string[];
@@ -536,6 +536,11 @@ export declare const workspaceConfigurationSchema: z.ZodMiniObject<{
536
536
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
537
537
  project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
538
538
  }, z.core.$strip>]>>;
539
+ railway: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
540
+ config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
541
+ entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
542
+ project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
543
+ }, z.core.$strip>]>>;
539
544
  raycast: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
540
545
  config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
541
546
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
@@ -1488,6 +1493,11 @@ export declare const knipConfigurationSchema: z.ZodMiniObject<{
1488
1493
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1489
1494
  project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1490
1495
  }, z.core.$strip>]>>;
1496
+ railway: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
1497
+ config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1498
+ entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1499
+ project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1500
+ }, z.core.$strip>]>>;
1491
1501
  raycast: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
1492
1502
  config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1493
1503
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
@@ -2459,6 +2469,11 @@ export declare const knipConfigurationSchema: z.ZodMiniObject<{
2459
2469
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
2460
2470
  project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
2461
2471
  }, z.core.$strip>]>>;
2472
+ railway: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
2473
+ config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
2474
+ entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
2475
+ project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
2476
+ }, z.core.$strip>]>>;
2462
2477
  raycast: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
2463
2478
  config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
2464
2479
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
@@ -541,6 +541,11 @@ export declare const pluginsSchema: z.ZodMiniObject<{
541
541
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
542
542
  project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
543
543
  }, z.core.$strip>]>;
544
+ railway: z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
545
+ config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
546
+ entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
547
+ project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
548
+ }, z.core.$strip>]>;
544
549
  raycast: z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
545
550
  config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
546
551
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
@@ -117,6 +117,7 @@ export const pluginsSchema = z.object({
117
117
  prisma: pluginSchema,
118
118
  quasar: pluginSchema,
119
119
  qwik: pluginSchema,
120
+ railway: pluginSchema,
120
121
  raycast: pluginSchema,
121
122
  'react-cosmos': pluginSchema,
122
123
  'react-email': pluginSchema,
@@ -1,2 +1,2 @@
1
- export type PluginName = 'angular' | 'astro' | 'astro-db' | 'astro-markdoc' | 'astro-og-canvas' | 'ava' | 'babel' | 'biome' | 'borp' | 'bumpp' | 'bun' | 'c8' | 'capacitor' | 'catalyst' | 'changelogen' | 'changelogithub' | 'changesets' | 'commitizen' | 'commitlint' | 'convex' | 'create-typescript-app' | 'cspell' | 'cucumber' | 'cypress' | 'danger' | 'dependency-cruiser' | 'docusaurus' | 'dotenv' | 'drizzle' | 'electron-vite' | 'eleventy' | 'esbuild' | 'eslint' | 'eve' | 'execa' | 'expo' | 'expressive-code' | 'fast' | 'fumadocs' | 'gatsby' | 'github-action' | 'github-actions' | 'glob' | 'graphql-codegen' | 'hardhat' | 'husky' | 'i18next-parser' | 'jest' | 'karma' | 'knex' | 'ladle' | 'laravel-vite-plugin' | 'lefthook' | 'lint-staged' | 'linthtml' | 'lit' | 'lockfile-lint' | 'lost-pixel' | 'lunaria' | 'markdownlint' | 'marko' | 'mdx' | 'mdxlint' | 'metro' | 'mise' | 'mocha' | 'moonrepo' | 'msw' | 'nano-spawn' | 'nano-staged' | 'nest' | 'netlify' | 'next' | 'next-intl' | 'next-mdx' | 'nitro' | 'node' | 'node-modules-inspector' | 'nodemon' | 'npm-package-json-lint' | 'nuxt' | 'nuxtjs-i18n' | 'nx' | 'nyc' | 'oclif' | 'openapi-ts' | 'openclaw' | 'orval' | 'oxfmt' | 'oxlint' | 'panda-css' | 'parcel' | 'payload' | 'pino' | 'playwright' | 'playwright-ct' | 'playwright-test' | 'plop' | 'pm2' | 'pnpm' | 'postcss' | 'pre-commit' | 'preconstruct' | 'prettier' | 'prisma' | 'quasar' | 'qwik' | 'raycast' | 'react-cosmos' | 'react-email' | 'react-native' | 'react-router' | 'relay' | 'release-it' | 'remark' | 'remix' | 'rolldown' | 'rollup' | 'rsbuild' | 'rslib' | 'rspack' | 'rstest' | 'sanity' | 'semantic-release' | 'sentry' | 'serverless-framework' | 'simple-git-hooks' | 'size-limit' | 'sst' | 'starlight' | 'stencil' | 'storybook' | 'stryker' | 'stylelint' | 'svelte' | 'sveltejs-package' | 'sveltekit' | 'svgo' | 'svgr' | 'swc' | 'syncpack' | 'tailwind' | 'tanstack-router' | 'taskfile' | 'tauri' | 'temporal' | 'textlint' | 'travis' | 'ts-node' | 'tsd' | 'tsdown' | 'tsup' | 'tsx' | 'turbo' | 'typedoc' | 'typescript' | 'typescript-content-mapper' | 'unbuild' | 'unocss' | 'unplugin-auto-import' | 'unplugin-icons' | 'unplugin-vue-components' | 'unplugin-vue-i18n' | 'unplugin-vue-markdown' | 'unplugin-vue-router' | 'varlock' | 'vercel' | 'vercel-og' | 'vike' | 'vite' | 'vite-plugin-pages' | 'vite-plugin-pwa' | 'vite-plugin-vue-layouts-next' | 'vite-plus' | 'vite-pwa-assets-generator' | 'vitepress' | 'vitest' | 'vue' | 'webdriver-io' | 'webpack' | 'wireit' | 'wrangler' | 'wxt' | 'xo' | 'yarn' | 'yorkie' | 'zx';
2
- export declare const pluginNames: readonly ['angular', 'astro', 'astro-db', 'astro-markdoc', 'astro-og-canvas', 'ava', 'babel', 'biome', 'borp', 'bumpp', 'bun', 'c8', 'capacitor', 'catalyst', 'changelogen', 'changelogithub', 'changesets', 'commitizen', 'commitlint', 'convex', 'create-typescript-app', 'cspell', 'cucumber', 'cypress', 'danger', 'dependency-cruiser', 'docusaurus', 'dotenv', 'drizzle', 'electron-vite', 'eleventy', 'esbuild', 'eslint', 'eve', 'execa', 'expo', 'expressive-code', 'fast', 'fumadocs', 'gatsby', 'github-action', 'github-actions', 'glob', 'graphql-codegen', 'hardhat', 'husky', 'i18next-parser', 'jest', 'karma', 'knex', 'ladle', 'laravel-vite-plugin', 'lefthook', 'lint-staged', 'linthtml', 'lit', 'lockfile-lint', 'lost-pixel', 'lunaria', 'markdownlint', 'marko', 'mdx', 'mdxlint', 'metro', 'mise', 'mocha', 'moonrepo', 'msw', 'nano-spawn', 'nano-staged', 'nest', 'netlify', 'next', 'next-intl', 'next-mdx', 'nitro', 'node', 'node-modules-inspector', 'nodemon', 'npm-package-json-lint', 'nuxt', 'nuxtjs-i18n', 'nx', 'nyc', 'oclif', 'openapi-ts', 'openclaw', 'orval', 'oxfmt', 'oxlint', 'panda-css', 'parcel', 'payload', 'pino', 'playwright', 'playwright-ct', 'playwright-test', 'plop', 'pm2', 'pnpm', 'postcss', 'pre-commit', 'preconstruct', 'prettier', 'prisma', 'quasar', 'qwik', 'raycast', 'react-cosmos', 'react-email', 'react-native', 'react-router', 'relay', 'release-it', 'remark', 'remix', 'rolldown', 'rollup', 'rsbuild', 'rslib', 'rspack', 'rstest', 'sanity', 'semantic-release', 'sentry', 'serverless-framework', 'simple-git-hooks', 'size-limit', 'sst', 'starlight', 'stencil', 'storybook', 'stryker', 'stylelint', 'svelte', 'sveltejs-package', 'sveltekit', 'svgo', 'svgr', 'swc', 'syncpack', 'tailwind', 'tanstack-router', 'taskfile', 'tauri', 'temporal', 'textlint', 'travis', 'ts-node', 'tsd', 'tsdown', 'tsup', 'tsx', 'turbo', 'typedoc', 'typescript', 'typescript-content-mapper', 'unbuild', 'unocss', 'unplugin-auto-import', 'unplugin-icons', 'unplugin-vue-components', 'unplugin-vue-i18n', 'unplugin-vue-markdown', 'unplugin-vue-router', 'varlock', 'vercel', 'vercel-og', 'vike', 'vite', 'vite-plugin-pages', 'vite-plugin-pwa', 'vite-plugin-vue-layouts-next', 'vite-plus', 'vite-pwa-assets-generator', 'vitepress', 'vitest', 'vue', 'webdriver-io', 'webpack', 'wireit', 'wrangler', 'wxt', 'xo', 'yarn', 'yorkie', 'zx'];
1
+ export type PluginName = 'angular' | 'astro' | 'astro-db' | 'astro-markdoc' | 'astro-og-canvas' | 'ava' | 'babel' | 'biome' | 'borp' | 'bumpp' | 'bun' | 'c8' | 'capacitor' | 'catalyst' | 'changelogen' | 'changelogithub' | 'changesets' | 'commitizen' | 'commitlint' | 'convex' | 'create-typescript-app' | 'cspell' | 'cucumber' | 'cypress' | 'danger' | 'dependency-cruiser' | 'docusaurus' | 'dotenv' | 'drizzle' | 'electron-vite' | 'eleventy' | 'esbuild' | 'eslint' | 'eve' | 'execa' | 'expo' | 'expressive-code' | 'fast' | 'fumadocs' | 'gatsby' | 'github-action' | 'github-actions' | 'glob' | 'graphql-codegen' | 'hardhat' | 'husky' | 'i18next-parser' | 'jest' | 'karma' | 'knex' | 'ladle' | 'laravel-vite-plugin' | 'lefthook' | 'lint-staged' | 'linthtml' | 'lit' | 'lockfile-lint' | 'lost-pixel' | 'lunaria' | 'markdownlint' | 'marko' | 'mdx' | 'mdxlint' | 'metro' | 'mise' | 'mocha' | 'moonrepo' | 'msw' | 'nano-spawn' | 'nano-staged' | 'nest' | 'netlify' | 'next' | 'next-intl' | 'next-mdx' | 'nitro' | 'node' | 'node-modules-inspector' | 'nodemon' | 'npm-package-json-lint' | 'nuxt' | 'nuxtjs-i18n' | 'nx' | 'nyc' | 'oclif' | 'openapi-ts' | 'openclaw' | 'orval' | 'oxfmt' | 'oxlint' | 'panda-css' | 'parcel' | 'payload' | 'pino' | 'playwright' | 'playwright-ct' | 'playwright-test' | 'plop' | 'pm2' | 'pnpm' | 'postcss' | 'pre-commit' | 'preconstruct' | 'prettier' | 'prisma' | 'quasar' | 'qwik' | 'railway' | 'raycast' | 'react-cosmos' | 'react-email' | 'react-native' | 'react-router' | 'relay' | 'release-it' | 'remark' | 'remix' | 'rolldown' | 'rollup' | 'rsbuild' | 'rslib' | 'rspack' | 'rstest' | 'sanity' | 'semantic-release' | 'sentry' | 'serverless-framework' | 'simple-git-hooks' | 'size-limit' | 'sst' | 'starlight' | 'stencil' | 'storybook' | 'stryker' | 'stylelint' | 'svelte' | 'sveltejs-package' | 'sveltekit' | 'svgo' | 'svgr' | 'swc' | 'syncpack' | 'tailwind' | 'tanstack-router' | 'taskfile' | 'tauri' | 'temporal' | 'textlint' | 'travis' | 'ts-node' | 'tsd' | 'tsdown' | 'tsup' | 'tsx' | 'turbo' | 'typedoc' | 'typescript' | 'typescript-content-mapper' | 'unbuild' | 'unocss' | 'unplugin-auto-import' | 'unplugin-icons' | 'unplugin-vue-components' | 'unplugin-vue-i18n' | 'unplugin-vue-markdown' | 'unplugin-vue-router' | 'varlock' | 'vercel' | 'vercel-og' | 'vike' | 'vite' | 'vite-plugin-pages' | 'vite-plugin-pwa' | 'vite-plugin-vue-layouts-next' | 'vite-plus' | 'vite-pwa-assets-generator' | 'vitepress' | 'vitest' | 'vue' | 'webdriver-io' | 'webpack' | 'wireit' | 'wrangler' | 'wxt' | 'xo' | 'yarn' | 'yorkie' | 'zx';
2
+ export declare const pluginNames: readonly ['angular', 'astro', 'astro-db', 'astro-markdoc', 'astro-og-canvas', 'ava', 'babel', 'biome', 'borp', 'bumpp', 'bun', 'c8', 'capacitor', 'catalyst', 'changelogen', 'changelogithub', 'changesets', 'commitizen', 'commitlint', 'convex', 'create-typescript-app', 'cspell', 'cucumber', 'cypress', 'danger', 'dependency-cruiser', 'docusaurus', 'dotenv', 'drizzle', 'electron-vite', 'eleventy', 'esbuild', 'eslint', 'eve', 'execa', 'expo', 'expressive-code', 'fast', 'fumadocs', 'gatsby', 'github-action', 'github-actions', 'glob', 'graphql-codegen', 'hardhat', 'husky', 'i18next-parser', 'jest', 'karma', 'knex', 'ladle', 'laravel-vite-plugin', 'lefthook', 'lint-staged', 'linthtml', 'lit', 'lockfile-lint', 'lost-pixel', 'lunaria', 'markdownlint', 'marko', 'mdx', 'mdxlint', 'metro', 'mise', 'mocha', 'moonrepo', 'msw', 'nano-spawn', 'nano-staged', 'nest', 'netlify', 'next', 'next-intl', 'next-mdx', 'nitro', 'node', 'node-modules-inspector', 'nodemon', 'npm-package-json-lint', 'nuxt', 'nuxtjs-i18n', 'nx', 'nyc', 'oclif', 'openapi-ts', 'openclaw', 'orval', 'oxfmt', 'oxlint', 'panda-css', 'parcel', 'payload', 'pino', 'playwright', 'playwright-ct', 'playwright-test', 'plop', 'pm2', 'pnpm', 'postcss', 'pre-commit', 'preconstruct', 'prettier', 'prisma', 'quasar', 'qwik', 'railway', 'raycast', 'react-cosmos', 'react-email', 'react-native', 'react-router', 'relay', 'release-it', 'remark', 'remix', 'rolldown', 'rollup', 'rsbuild', 'rslib', 'rspack', 'rstest', 'sanity', 'semantic-release', 'sentry', 'serverless-framework', 'simple-git-hooks', 'size-limit', 'sst', 'starlight', 'stencil', 'storybook', 'stryker', 'stylelint', 'svelte', 'sveltejs-package', 'sveltekit', 'svgo', 'svgr', 'swc', 'syncpack', 'tailwind', 'tanstack-router', 'taskfile', 'tauri', 'temporal', 'textlint', 'travis', 'ts-node', 'tsd', 'tsdown', 'tsup', 'tsx', 'turbo', 'typedoc', 'typescript', 'typescript-content-mapper', 'unbuild', 'unocss', 'unplugin-auto-import', 'unplugin-icons', 'unplugin-vue-components', 'unplugin-vue-i18n', 'unplugin-vue-markdown', 'unplugin-vue-router', 'varlock', 'vercel', 'vercel-og', 'vike', 'vite', 'vite-plugin-pages', 'vite-plugin-pwa', 'vite-plugin-vue-layouts-next', 'vite-plus', 'vite-pwa-assets-generator', 'vitepress', 'vitest', 'vue', 'webdriver-io', 'webpack', 'wireit', 'wrangler', 'wxt', 'xo', 'yarn', 'yorkie', 'zx'];
@@ -106,6 +106,7 @@ export const pluginNames = [
106
106
  'prisma',
107
107
  'quasar',
108
108
  'qwik',
109
+ 'railway',
109
110
  'raycast',
110
111
  'react-cosmos',
111
112
  'react-email',
@@ -36,6 +36,11 @@ export type PackageJson = {
36
36
  name?: string;
37
37
  main?: string;
38
38
  bin?: string | Record<string, string>;
39
+ repository?: string | {
40
+ type?: string;
41
+ url?: string;
42
+ directory?: string;
43
+ };
39
44
  version?: string;
40
45
  private?: boolean;
41
46
  workspaces?: string[] | {
@@ -581,6 +581,11 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
581
581
  entry?: string | string[] | undefined;
582
582
  project?: string | string[] | undefined;
583
583
  } | undefined;
584
+ railway?: string | boolean | string[] | {
585
+ config?: string | string[] | undefined;
586
+ entry?: string | string[] | undefined;
587
+ project?: string | string[] | undefined;
588
+ } | undefined;
584
589
  raycast?: string | boolean | string[] | {
585
590
  config?: string | string[] | undefined;
586
591
  entry?: string | string[] | undefined;
@@ -1548,6 +1553,11 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
1548
1553
  entry?: string | string[] | undefined;
1549
1554
  project?: string | string[] | undefined;
1550
1555
  } | undefined;
1556
+ railway?: string | boolean | string[] | {
1557
+ config?: string | string[] | undefined;
1558
+ entry?: string | string[] | undefined;
1559
+ project?: string | string[] | undefined;
1560
+ } | undefined;
1551
1561
  raycast?: string | boolean | string[] | {
1552
1562
  config?: string | string[] | undefined;
1553
1563
  entry?: string | string[] | undefined;
@@ -1 +1,2 @@
1
+ export declare const getGitRemoteUrls: (cwd: string) => string[];
1
2
  export declare const getGitHookPaths: (defaultPath?: string, followGitConfig?: boolean, cwd?: string) => string[];
package/dist/util/git.js CHANGED
@@ -1,4 +1,4 @@
1
- import { execSync } from 'node:child_process';
1
+ import { execFileSync, execSync } from 'node:child_process';
2
2
  import { join } from './path.js';
3
3
  const hookFileNames = [
4
4
  'prepare-commit-msg',
@@ -18,6 +18,28 @@ const getGitHooksPath = (defaultPath = '.git/hooks', cwd) => {
18
18
  return defaultPath;
19
19
  }
20
20
  };
21
+ const remoteUrlCache = new Map();
22
+ export const getGitRemoteUrls = (cwd) => {
23
+ const cached = remoteUrlCache.get(cwd);
24
+ if (cached)
25
+ return cached;
26
+ const urls = [];
27
+ try {
28
+ const output = execFileSync('git', ['config', '--local', '--get-regexp', String.raw `^remote\..*\.url$`], {
29
+ encoding: 'utf8',
30
+ stdio: ['pipe', 'pipe', 'ignore'],
31
+ cwd,
32
+ });
33
+ for (const line of output.trim().split('\n')) {
34
+ const separator = line.indexOf(' ');
35
+ if (separator !== -1)
36
+ urls.push(line.slice(separator + 1));
37
+ }
38
+ }
39
+ catch (_error) { }
40
+ remoteUrlCache.set(cwd, urls);
41
+ return urls;
42
+ };
21
43
  export const getGitHookPaths = (defaultPath = '.git/hooks', followGitConfig = true, cwd) => {
22
44
  const gitHooksPath = followGitConfig ? getGitHooksPath(defaultPath, cwd) : defaultPath;
23
45
  return hookFileNames.map(fileName => join(gitHooksPath, fileName));
@@ -10,6 +10,11 @@ export declare const getPublishedTypeManifest: (manifest: PackageJson) => {
10
10
  name?: string;
11
11
  main?: string;
12
12
  bin?: string | Record<string, string>;
13
+ repository?: string | {
14
+ type?: string;
15
+ url?: string;
16
+ directory?: string;
17
+ };
13
18
  version?: string;
14
19
  private?: boolean;
15
20
  workspaces?: string[] | {
@@ -273,6 +278,7 @@ export declare const getPublishedTypeManifest: (manifest: PackageJson) => {
273
278
  prisma?: unknown;
274
279
  quasar?: unknown;
275
280
  qwik?: unknown;
281
+ railway?: unknown;
276
282
  raycast?: unknown;
277
283
  "react-cosmos"?: unknown;
278
284
  "react-email"?: unknown;
@@ -1,5 +1,6 @@
1
1
  import type { Tags } from '../types/options.ts';
2
2
  export declare const splitTags: (rawTags: string[]) => Tags;
3
+ export declare const hasTag: (tags: string[], jsDocTags: Set<string>) => boolean;
3
4
  export declare const shouldIgnore: (jsDocTags: Set<string>, tags: Tags) => boolean;
4
5
  export declare const isAlwaysIgnored: (jsDocTags: Set<string>) => boolean;
5
6
  export declare const getShouldIgnoreHandler: (isProduction: boolean) => (jsDocTags: Set<string>) => boolean;
package/dist/util/tag.js CHANGED
@@ -8,7 +8,7 @@ export const splitTags = (rawTags) => {
8
8
  return [incl, excl];
9
9
  }, [[], []]);
10
10
  };
11
- const hasTag = (tags, jsDocTags) => tags.some(tag => jsDocTags.has(tag));
11
+ export const hasTag = (tags, jsDocTags) => tags.some(tag => jsDocTags.has(tag));
12
12
  export const shouldIgnore = (jsDocTags, tags) => {
13
13
  const [includeJSDocTags, excludeJSDocTags] = tags;
14
14
  if (includeJSDocTags.length > 0 && !hasTag(includeJSDocTags, jsDocTags))
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "6.38.0";
1
+ export declare const version = "6.39.0";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = '6.38.0';
1
+ export const version = '6.39.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knip",
3
- "version": "6.38.0",
3
+ "version": "6.39.0",
4
4
  "description": "Find and fix unused dependencies, exports and files in your TypeScript and JavaScript projects",
5
5
  "keywords": [
6
6
  "analysis",
package/schema.json CHANGED
@@ -838,6 +838,10 @@
838
838
  "title": "qwik plugin configuration (https://knip.dev/reference/plugins/qwik)",
839
839
  "$ref": "#/definitions/plugin"
840
840
  },
841
+ "railway": {
842
+ "title": "railway plugin configuration (https://knip.dev/reference/plugins/railway)",
843
+ "$ref": "#/definitions/plugin"
844
+ },
841
845
  "react-cosmos": {
842
846
  "title": "react-cosmos plugin configuration (https://knip.dev/reference/plugins/react-cosmos)",
843
847
  "$ref": "#/definitions/plugin"