knip 6.32.3 → 6.34.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 (59) hide show
  1. package/dist/DependencyDeputy.d.ts +1 -2
  2. package/dist/DependencyDeputy.js +1 -2
  3. package/dist/ProjectPrincipal.d.ts +6 -3
  4. package/dist/ProjectPrincipal.js +29 -6
  5. package/dist/cli.js +2 -2
  6. package/dist/config.d.ts +2 -0
  7. package/dist/config.js +1 -0
  8. package/dist/graph/analyze.js +4 -4
  9. package/dist/graph/build.js +1 -2
  10. package/dist/graph-explorer/explorer.d.ts +1 -0
  11. package/dist/graph-explorer/explorer.js +2 -0
  12. package/dist/graph-explorer/operations/is-enumerated.d.ts +2 -0
  13. package/dist/graph-explorer/operations/is-enumerated.js +33 -0
  14. package/dist/manifest/helpers.d.ts +2 -3
  15. package/dist/manifest/helpers.js +6 -42
  16. package/dist/manifest/index.d.ts +1 -2
  17. package/dist/manifest/index.js +2 -2
  18. package/dist/plugins/dotenv/index.js +1 -8
  19. package/dist/plugins/eslint/helpers.d.ts +2 -1
  20. package/dist/plugins/eslint/helpers.js +1 -0
  21. package/dist/plugins/eslint/resolveFromAST.d.ts +1 -0
  22. package/dist/plugins/eslint/resolveFromAST.js +5 -2
  23. package/dist/plugins/eslint/types.d.ts +1 -1
  24. package/dist/plugins/moonrepo/index.js +3 -3
  25. package/dist/plugins/node/index.js +5 -0
  26. package/dist/plugins/node/visitors/fsPromisesGlob.d.ts +2 -0
  27. package/dist/plugins/node/visitors/fsPromisesGlob.js +89 -0
  28. package/dist/plugins/nuxt/index.js +38 -13
  29. package/dist/plugins/nuxt/types.d.ts +5 -1
  30. package/dist/plugins/oxlint/index.js +6 -2
  31. package/dist/plugins/oxlint/types.d.ts +2 -0
  32. package/dist/plugins/typescript/index.js +22 -5
  33. package/dist/plugins/vitest/index.js +18 -11
  34. package/dist/plugins/vitest/types.d.ts +1 -1
  35. package/dist/plugins/vitest/visitors/mock.d.ts +2 -0
  36. package/dist/plugins/vitest/visitors/mock.js +50 -0
  37. package/dist/plugins/webpack/index.js +15 -14
  38. package/dist/run.js +1 -1
  39. package/dist/types/config.d.ts +2 -0
  40. package/dist/types/module-graph.d.ts +2 -0
  41. package/dist/types/tsconfig-json.d.ts +6 -0
  42. package/dist/typescript/get-imports-and-exports.js +7 -1
  43. package/dist/typescript/glob-imports.js +8 -3
  44. package/dist/typescript/visitors/calls.js +2 -2
  45. package/dist/typescript/visitors/members.js +56 -8
  46. package/dist/typescript/visitors/walk.d.ts +4 -1
  47. package/dist/typescript/visitors/walk.js +78 -14
  48. package/dist/util/cli-arguments.d.ts +1 -0
  49. package/dist/util/cli-arguments.js +9 -0
  50. package/dist/util/create-options.d.ts +2 -1
  51. package/dist/util/create-options.js +3 -1
  52. package/dist/util/load-config.js +6 -1
  53. package/dist/util/resolve.d.ts +1 -0
  54. package/dist/util/resolve.js +11 -0
  55. package/dist/util/scripts.d.ts +1 -0
  56. package/dist/util/scripts.js +1 -0
  57. package/dist/version.d.ts +1 -1
  58. package/dist/version.js +1 -1
  59. package/package.json +16 -12
@@ -49,6 +49,26 @@ const resolveAlias = (specifier, srcDir, rootDir) => {
49
49
  return join(srcDir, specifier.slice(2));
50
50
  return specifier;
51
51
  };
52
+ const remoteSourcePrefixes = ['gh:', 'github:', 'gitlab:', 'bitbucket:', 'https://', 'http://'];
53
+ const toLayerSource = (layer) => {
54
+ if (typeof layer === 'string')
55
+ return layer;
56
+ if (Array.isArray(layer))
57
+ return layer[0];
58
+ if (layer && typeof layer === 'object' && 'source' in layer)
59
+ return layer.source;
60
+ };
61
+ const toLayerSources = (extend) => {
62
+ const sources = [];
63
+ if (!extend)
64
+ return sources;
65
+ for (const layer of Array.isArray(extend) ? extend : [extend]) {
66
+ const source = toLayerSource(layer);
67
+ if (typeof source === 'string')
68
+ sources.push(source);
69
+ }
70
+ return sources;
71
+ };
52
72
  const addAppEntries = (inputs, srcDir, serverDir, config, dir) => {
53
73
  for (const id of entry)
54
74
  inputs.push(toEntry(join(srcDir, id)));
@@ -67,18 +87,18 @@ const addAppEntries = (inputs, srcDir, serverDir, config, dir) => {
67
87
  inputs.push(toDeferResolveProductionEntry(resolveAlias(id, srcDir, dir)));
68
88
  };
69
89
  const findLayerConfigs = (cwd) => _syncGlob({ cwd, patterns: [`layers/*/${config.at(0)}`] });
90
+ const definitionFiles = [
91
+ '.nuxt/imports.d.ts',
92
+ '.nuxt/components.d.ts',
93
+ '.nuxt/types/nitro-routes.d.ts',
94
+ '.nuxt/types/nitro-imports.d.ts',
95
+ ];
70
96
  const registerCompilers = async ({ cwd, hasDependency, registerCompiler }) => {
71
- if (hasDependency('nuxt') || hasDependency('nuxt-nightly')) {
97
+ if (hasDependency('nuxt') || hasDependency('nuxt-nightly') || isDirectory(cwd, '.nuxt')) {
98
+ const paths = definitionFiles.map(file => join(cwd, file));
72
99
  const maps = createAutoImportMaps();
73
- const definitionFiles = [
74
- '.nuxt/imports.d.ts',
75
- '.nuxt/components.d.ts',
76
- '.nuxt/types/nitro-routes.d.ts',
77
- '.nuxt/types/nitro-imports.d.ts',
78
- ];
79
- for (const file of definitionFiles) {
80
- const path = join(cwd, file);
81
- buildAutoImportMap(path, readAndParseFile(path), maps, file.endsWith('components.d.ts'));
100
+ for (const path of paths) {
101
+ buildAutoImportMap(path, readAndParseFile(path), maps, path.endsWith('components.d.ts'));
82
102
  }
83
103
  registerCompiler({ extension: '.vue', compiler: createVueCompiler(maps, cwd) });
84
104
  registerCompiler({ extension: '.ts', compiler: createTsCompiler(maps) });
@@ -101,6 +121,9 @@ const resolveConfig = async (localConfig, options) => {
101
121
  addModule(id);
102
122
  }
103
123
  addAppEntries(inputs, srcDir, serverDir, localConfig, cwd);
124
+ const sharedDir = toAbsolute(localConfig.dir?.shared ?? 'shared', cwd);
125
+ inputs.push(toAlias('#shared', sharedDir));
126
+ inputs.push(toAlias('#shared/*', join(sharedDir, '*'), { dir: cwd }));
104
127
  const aliases = localConfig.alias;
105
128
  if (aliases) {
106
129
  for (const key in aliases) {
@@ -111,15 +134,17 @@ const resolveConfig = async (localConfig, options) => {
111
134
  }
112
135
  }
113
136
  }
114
- for (const ext of localConfig.extends ?? []) {
115
- const target = resolveAlias(ext, srcDir, cwd);
137
+ for (const source of toLayerSources(localConfig.extends)) {
138
+ if (remoteSourcePrefixes.some(prefix => source.startsWith(prefix)))
139
+ continue;
140
+ const target = resolveAlias(source, srcDir, cwd);
116
141
  const resolved = isInternal(target) ? toAbsolute(target, cwd) : target;
117
142
  const configs = _syncGlob({ cwd: resolved, patterns: config });
118
143
  if (configs.length > 0)
119
144
  for (const cfg of configs)
120
145
  inputs.push(toConfig('nuxt', cfg));
121
146
  else
122
- inputs.push(toDependency(ext));
147
+ inputs.push(toDependency(source));
123
148
  }
124
149
  for (const layerConfig of findLayerConfigs(cwd)) {
125
150
  inputs.push(toConfig('nuxt', layerConfig));
@@ -1,3 +1,6 @@
1
+ type NuxtLayer = string | [string, unknown?] | {
2
+ source: string;
3
+ };
1
4
  export interface NuxtConfig {
2
5
  srcDir?: string;
3
6
  buildDir?: string;
@@ -14,7 +17,7 @@ export interface NuxtConfig {
14
17
  autoImport?: boolean;
15
18
  dirs?: string[];
16
19
  };
17
- extends?: string[];
20
+ extends?: NuxtLayer | NuxtLayer[];
18
21
  components?: Array<string | {
19
22
  path: string;
20
23
  }> | {
@@ -25,3 +28,4 @@ export interface NuxtConfig {
25
28
  css?: string[];
26
29
  alias?: Record<string, string>;
27
30
  }
31
+ export {};
@@ -3,10 +3,12 @@ import { findProperty, getPropertyValues } from '../../typescript/ast-helpers.js
3
3
  import { toDependency, toEntry } from '../../util/input.js';
4
4
  import { isInternal } from '../../util/path.js';
5
5
  import { hasDependency } from '../../util/plugin.js';
6
+ import { getInputsFromSettings } from '../eslint/helpers.js';
7
+ import { getInputsFromSettingsAST } from '../eslint/resolveFromAST.js';
6
8
  const title = 'Oxlint';
7
9
  const enablers = ['oxlint', 'vite-plus'];
8
10
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
9
- const config = ['.oxlintrc.json', 'oxlint.config.{ts,mts}', 'vite.config.{js,mjs,ts,cjs,mts,cts}'];
11
+ const config = ['.oxlintrc.{json,jsonc}', 'oxlint.config.{ts,mts}', 'vite.config.{js,mjs,ts,cjs,mts,cts}'];
10
12
  const isViteConfig = (configFileName) => configFileName.startsWith('vite.config.');
11
13
  const args = {
12
14
  config: true,
@@ -29,6 +31,8 @@ const resolveConfig = config => {
29
31
  for (const input of resolveJsPlugins(override.jsPlugins))
30
32
  inputs.push(input);
31
33
  }
34
+ for (const input of getInputsFromSettings(config.settings))
35
+ inputs.push(input);
32
36
  return inputs;
33
37
  };
34
38
  const resolveFromAST = (program, options) => {
@@ -51,7 +55,7 @@ const resolveFromAST = (program, options) => {
51
55
  },
52
56
  });
53
57
  visitor.visit(program);
54
- return resolveJsPlugins([...jsPlugins]);
58
+ return [...resolveJsPlugins([...jsPlugins]), ...getInputsFromSettingsAST(program)];
55
59
  };
56
60
  const plugin = {
57
61
  title,
@@ -1,3 +1,4 @@
1
+ import type { Settings } from '../eslint/types.ts';
1
2
  type JsPlugin = string | {
2
3
  name: string;
3
4
  specifier: string;
@@ -8,5 +9,6 @@ type Override = {
8
9
  export type OxlintConfig = {
9
10
  jsPlugins?: JsPlugin[];
10
11
  overrides?: Override[];
12
+ settings?: Settings;
11
13
  };
12
14
  export {};
@@ -1,12 +1,21 @@
1
1
  import { compact } from '../../util/array.js';
2
- import { toConfig, toDeferResolve, toProductionDependency } from '../../util/input.js';
2
+ import { toConfig, toDeferResolve, toDependency, toProductionDependency } from '../../util/input.js';
3
3
  import { join } from '../../util/path.js';
4
4
  import { hasDependency } from '../../util/plugin.js';
5
+ import { toShellCommand } from '../../util/scripts.js';
5
6
  const title = 'TypeScript';
6
7
  const enablers = ['typescript', '@typescript/native', '@typescript/native-preview'];
7
8
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
8
- const config = ['tsconfig.json'];
9
- const resolveConfig = async (localConfig, options) => {
9
+ const config = ['tsconfig.json', 'package.json'];
10
+ const packageJsonPath = 'typescript.contentMapper';
11
+ const resolveContentMapper = ({ exec }, options) => {
12
+ if (!Array.isArray(exec) || exec.some(arg => typeof arg !== 'string'))
13
+ return [];
14
+ return options
15
+ .getInputsFromScripts(toShellCommand(exec))
16
+ .map(input => input.type === 'entry' || input.type === 'deferResolveEntry' ? { ...input, production: true } : input);
17
+ };
18
+ const resolveTsConfig = (localConfig, options) => {
10
19
  const { compilerOptions } = localConfig;
11
20
  const extend = localConfig.extends
12
21
  ? [localConfig.extends]
@@ -16,8 +25,9 @@ const resolveConfig = async (localConfig, options) => {
16
25
  const references = localConfig.references
17
26
  ?.filter(reference => reference.path.endsWith('.json'))
18
27
  .map(reference => toConfig('typescript', reference.path, { containingFilePath: options.configFilePath })) ?? [];
28
+ const contentMappers = localConfig.contentMappers?.map(contentMapper => toDependency(contentMapper.package)) ?? [];
19
29
  if (!(compilerOptions && localConfig))
20
- return compact([...extend, ...references]);
30
+ return compact([...contentMappers, ...extend, ...references]);
21
31
  const jsx = (compilerOptions?.jsxImportSource ? [compilerOptions.jsxImportSource] : []).map(toProductionDependency);
22
32
  const types = compilerOptions.types ?? [];
23
33
  const plugins = Array.isArray(compilerOptions?.plugins)
@@ -25,6 +35,7 @@ const resolveConfig = async (localConfig, options) => {
25
35
  : [];
26
36
  const importHelpers = compilerOptions?.importHelpers ? ['tslib'] : [];
27
37
  return compact([
38
+ ...contentMappers,
28
39
  ...extend,
29
40
  ...references,
30
41
  ...types.map(id => toDeferResolve(id, { isTypeOnly: true, dir: options.cwd })),
@@ -32,19 +43,25 @@ const resolveConfig = async (localConfig, options) => {
32
43
  ...jsx,
33
44
  ]);
34
45
  };
46
+ const resolveConfig = (localConfig, options) => options.configFileName === 'package.json'
47
+ ? resolveContentMapper(localConfig, options)
48
+ : resolveTsConfig(localConfig, options);
35
49
  const args = {
36
50
  binaries: ['tsc', 'tsgo'],
37
51
  string: ['project'],
38
52
  alias: { project: ['p'] },
39
53
  config: [['project', (p) => (p.endsWith('.json') ? p : join(p, 'tsconfig.json'))]],
40
54
  };
41
- const note = "[What's up with that configurable tsconfig.json location?](/reference/faq#whats-up-with-that-configurable-tsconfigjson-location)";
55
+ const note = `[What's up with that configurable tsconfig.json location?](/reference/faq#whats-up-with-that-configurable-tsconfigjson-location)
56
+
57
+ In a content mapper package, the command in \`package.json#typescript.contentMapper.exec\` is resolved to a production entry.`;
42
58
  export const docs = { note };
43
59
  const plugin = {
44
60
  title,
45
61
  enablers,
46
62
  isEnabled,
47
63
  config,
64
+ packageJsonPath,
48
65
  resolveConfig,
49
66
  args,
50
67
  };
@@ -6,6 +6,7 @@ import { isAbsolute, isInternal, join, toAbsolute } from '../../util/path.js';
6
6
  import { hasDependency } from '../../util/plugin.js';
7
7
  import { getIndexHtmlEntries } from '../vite/helpers.js';
8
8
  import { getAliasInputs, getEnvSpecifier, getExternalReporters } from './helpers.js';
9
+ import { createVitestMockVisitor } from './visitors/mock.js';
9
10
  const title = 'Vitest';
10
11
  const enablers = ['vitest', 'vite-plus'];
11
12
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
@@ -15,7 +16,6 @@ const testEntry = ['**/*.{bench,test,test-d,spec,spec-d}.?(c|m)[jt]s?(x)'];
15
16
  const entry = [...testEntry, ...mocks];
16
17
  const benchmark = ['**/*.bench.?(c|m)[jt]s?(x)'];
17
18
  const findConfigDependencies = (localConfig, options, vitestRoot) => {
18
- const { configFileDir: dir } = options;
19
19
  const testConfig = localConfig.test;
20
20
  if (!testConfig)
21
21
  return [];
@@ -37,7 +37,9 @@ const findConfigDependencies = (localConfig, options, vitestRoot) => {
37
37
  ...toDeferResolve(specifier),
38
38
  dir: vitestRoot,
39
39
  }));
40
- const globalSetup = [testConfig.globalSetup ?? []].flat().map(specifier => ({ ...toDeferResolve(specifier), dir }));
40
+ const globalSetup = [testConfig.globalSetup ?? []]
41
+ .flat()
42
+ .map(specifier => ({ ...toDeferResolve(specifier), dir: vitestRoot }));
41
43
  const workspaceDependencies = [];
42
44
  if (testConfig.workspace !== undefined) {
43
45
  for (const workspaceConfig of testConfig.workspace) {
@@ -75,12 +77,14 @@ const getConfigs = async (localConfig) => {
75
77
  if (typeof config === 'function') {
76
78
  for (const command of ['serve', 'build']) {
77
79
  for (const mode of ['development', 'production']) {
78
- const cfg = await config({ command, mode, ssrBuild: undefined });
79
- configs.push(cfg);
80
- if (cfg.test?.projects) {
81
- for (const project of cfg.test.projects) {
82
- if (typeof project !== 'string') {
83
- configs.push(project);
80
+ for (const ssrBuild of command === 'build' ? [undefined, false, true] : [undefined]) {
81
+ const cfg = await config({ command, mode, ssrBuild });
82
+ configs.push(cfg);
83
+ if (cfg.test?.projects) {
84
+ for (const project of cfg.test.projects) {
85
+ if (typeof project !== 'string') {
86
+ configs.push(project);
87
+ }
84
88
  }
85
89
  }
86
90
  }
@@ -181,9 +185,8 @@ export const resolveConfig = async (localConfig, options) => {
181
185
  for (const dependency of findConfigDependencies(cfg, options, vitestRoot))
182
186
  inputs.add(dependency);
183
187
  const _entry = cfg.build?.lib?.entry ?? [];
184
- const deps = (typeof _entry === 'string' ? [_entry] : Object.values(_entry))
185
- .map(specifier => join(vitestRoot, specifier))
186
- .map(id => toEntry(id));
188
+ const entries = typeof _entry === 'string' ? [_entry] : Array.isArray(_entry) ? _entry : Object.values(_entry).flat();
189
+ const deps = entries.map(specifier => join(vitestRoot, specifier)).map(id => toEntry(id));
187
190
  for (const dependency of deps)
188
191
  inputs.add(dependency);
189
192
  }
@@ -215,6 +218,9 @@ const args = {
215
218
  return inputs;
216
219
  },
217
220
  };
221
+ const registerVisitors = ({ ctx, registerVisitor }) => {
222
+ registerVisitor(createVitestMockVisitor(ctx));
223
+ };
218
224
  const plugin = {
219
225
  title,
220
226
  enablers,
@@ -223,5 +229,6 @@ const plugin = {
223
229
  entry,
224
230
  resolveConfig,
225
231
  args,
232
+ registerVisitors,
226
233
  };
227
234
  export default plugin;
@@ -43,7 +43,7 @@ export interface ViteConfig extends VitestConfig {
43
43
  build?: {
44
44
  lib?: {
45
45
  entry: string | string[] | {
46
- [entryAlias: string]: string;
46
+ [entryAlias: string]: string | string[];
47
47
  };
48
48
  };
49
49
  };
@@ -0,0 +1,2 @@
1
+ import type { PluginVisitorContext, PluginVisitorObject } from '../../../types/config.ts';
2
+ export declare function createVitestMockVisitor(ctx: PluginVisitorContext): PluginVisitorObject;
@@ -0,0 +1,50 @@
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
+ export function createVitestMockVisitor(ctx) {
5
+ const viNames = new Set();
6
+ return {
7
+ Program(node) {
8
+ viNames.clear();
9
+ for (const statement of node.body) {
10
+ if (statement.type !== 'ImportDeclaration' ||
11
+ !isStringLiteral(statement.source) ||
12
+ getStringValue(statement.source) !== 'vitest')
13
+ continue;
14
+ for (const specifier of statement.specifiers ?? []) {
15
+ if (specifier.type === 'ImportSpecifier' &&
16
+ specifier.imported.type === 'Identifier' &&
17
+ specifier.imported.name === 'vi') {
18
+ viNames.add(specifier.local.name);
19
+ }
20
+ }
21
+ }
22
+ },
23
+ CallExpression(node) {
24
+ const argument = node.arguments[0];
25
+ const factory = node.arguments[1];
26
+ const factoryBody = factory?.type === 'ArrowFunctionExpression' &&
27
+ factory.body.type === 'ParenthesizedExpression' &&
28
+ factory.body.expression.type === 'ObjectExpression'
29
+ ? factory.body.expression
30
+ : undefined;
31
+ if (argument?.type !== 'ImportExpression' ||
32
+ !isStringLiteral(argument.source) ||
33
+ factory?.type !== 'ArrowFunctionExpression' ||
34
+ !factoryBody ||
35
+ factory.async ||
36
+ factory.params.length > 0 ||
37
+ factoryBody.properties.some(property => property.type === 'SpreadElement') ||
38
+ node.callee.type !== 'MemberExpression' ||
39
+ node.callee.computed ||
40
+ node.callee.object.type !== 'Identifier' ||
41
+ !viNames.has(node.callee.object.name) ||
42
+ isShadowed(node.callee.object.name, node.callee.object.start) ||
43
+ node.callee.property.type !== 'Identifier' ||
44
+ node.callee.property.name !== 'mock')
45
+ return;
46
+ ctx.markImportExpressionHandled(argument.start);
47
+ ctx.addImport(getStringValue(argument.source), argument.source.start, IMPORT_FLAGS.SIDE_EFFECTS);
48
+ },
49
+ };
50
+ }
@@ -105,20 +105,21 @@ export const findWebpackDependenciesFromConfig = async (config, options) => {
105
105
  }
106
106
  }
107
107
  }
108
- if (typeof opts.entry === 'string')
109
- entries.push(opts.entry);
110
- else if (Array.isArray(opts.entry))
111
- entries.push(...opts.entry);
112
- else if (typeof opts.entry === 'object') {
113
- for (const entry of Object.values(opts.entry)) {
114
- if (typeof entry === 'string')
115
- entries.push(entry);
116
- else if (Array.isArray(entry))
117
- entries.push(...entry);
118
- else if (typeof entry === 'function')
119
- entries.push(entry());
120
- else if (entry && typeof entry === 'object' && 'filename' in entry)
121
- entries.push(entry['filename']);
108
+ const entry = typeof opts.entry === 'function' ? await opts.entry() : opts.entry;
109
+ if (typeof entry === 'string')
110
+ entries.push(entry);
111
+ else if (Array.isArray(entry))
112
+ entries.push(...entry);
113
+ else if (typeof entry === 'object') {
114
+ for (const item of Object.values(entry)) {
115
+ if (typeof item === 'string')
116
+ entries.push(item);
117
+ else if (Array.isArray(item))
118
+ entries.push(...item);
119
+ else if (typeof item === 'function')
120
+ entries.push(item());
121
+ else if (item && typeof item === 'object' && 'import' in item)
122
+ entries.push(...[item.import].flat());
122
123
  }
123
124
  }
124
125
  if (entries.length === 0 && opts.context)
package/dist/run.js CHANGED
@@ -60,7 +60,7 @@ export const run = async (options) => {
60
60
  const isGitIgnored = await getGitIgnoredHandler(options, new Set(workspaces.map(w => w.dir)));
61
61
  const toSourceFilePath = getModuleSourcePathHandler(chief);
62
62
  const findWorkspacePackageTarget = getWorkspacePackageTargetHandler(chief);
63
- const principal = new ProjectPrincipal(options, toSourceFilePath, findWorkspacePackageTarget);
63
+ const principal = new ProjectPrincipal(options, toSourceFilePath, findWorkspacePackageTarget, filePath => chief.findWorkspaceByFilePath(filePath)?.name);
64
64
  collector.setWorkspaceFilter(chief.workspaceFilePathFilter);
65
65
  collector.setSelectedWorkspaces(chief.selectedWorkspaces);
66
66
  collector.setIgnoreIssues(chief.getIgnoreIssues());
@@ -138,8 +138,10 @@ export type PluginVisitorContext = {
138
138
  sourceText: string;
139
139
  addScript: (script: string) => void;
140
140
  addImport: (specifier: string, pos: number, modifiers: number) => void;
141
+ markImportExpressionHandled: (pos: number) => void;
141
142
  addImportGlob: (patterns: string[], options?: {
142
143
  base?: string;
144
+ cwd?: string;
143
145
  filter?: RegExp;
144
146
  }) => void;
145
147
  markExportRegistered: (name: string) => void;
@@ -30,6 +30,7 @@ export interface Import extends Position {
30
30
  readonly identifier: string | undefined;
31
31
  readonly isTypeOnly: boolean;
32
32
  readonly modifiers: number;
33
+ readonly jsDocTags: Tags | undefined;
33
34
  }
34
35
  export interface ExternalRef {
35
36
  readonly specifier: string;
@@ -76,6 +77,7 @@ export type FileNode = {
76
77
  export interface ImportGlob {
77
78
  patterns: string[];
78
79
  base?: string;
80
+ cwd?: string;
79
81
  filter?: RegExp;
80
82
  }
81
83
  export type ModuleGraph = Map<FilePath, FileNode>;
@@ -8,7 +8,13 @@ export interface TsConfigJson {
8
8
  }>;
9
9
  [key: string]: unknown;
10
10
  };
11
+ contentMappers?: {
12
+ package: string;
13
+ }[];
11
14
  references?: Array<{
12
15
  path: string;
13
16
  }>;
14
17
  }
18
+ export interface ContentMapperManifest {
19
+ exec?: string[];
20
+ }
@@ -25,6 +25,7 @@ const getImportsAndExports = (filePath, sourceText, resolveModule, options, igno
25
25
  const specifierExportNames = new Set();
26
26
  const scripts = new Set();
27
27
  const importGlobs = [];
28
+ const handledImportExpressions = new Set();
28
29
  const importAliases = new Map();
29
30
  const addImportAlias = (aliasName, id, importFilePath) => {
30
31
  const aliases = importAliases.get(aliasName);
@@ -61,6 +62,7 @@ const getImportsAndExports = (filePath, sourceText, resolveModule, options, igno
61
62
  col: opts.col,
62
63
  isTypeOnly: isDts || !!(modifiers & IMPORT_FLAGS.TYPE_ONLY),
63
64
  modifiers,
65
+ jsDocTags: undefined,
64
66
  });
65
67
  const file = internal.get(importFilePath);
66
68
  const importMaps = file ?? createImports();
@@ -145,6 +147,7 @@ const getImportsAndExports = (filePath, sourceText, resolveModule, options, igno
145
147
  col,
146
148
  isTypeOnly: isDts || !!(modifiers & IMPORT_FLAGS.TYPE_ONLY),
147
149
  modifiers,
150
+ jsDocTags,
148
151
  });
149
152
  }
150
153
  }
@@ -170,6 +173,7 @@ const getImportsAndExports = (filePath, sourceText, resolveModule, options, igno
170
173
  col,
171
174
  isTypeOnly: isDts || !!(modifiers & IMPORT_FLAGS.TYPE_ONLY),
172
175
  modifiers,
176
+ jsDocTags: undefined,
173
177
  });
174
178
  }
175
179
  }
@@ -278,7 +282,8 @@ const getImportsAndExports = (filePath, sourceText, resolveModule, options, igno
278
282
  pluginCtx.sourceText = sourceText;
279
283
  pluginCtx.addScript = (s) => scripts.add(s);
280
284
  pluginCtx.addImport = (spec, pos, mod) => addImport(spec, undefined, undefined, undefined, pos, mod);
281
- pluginCtx.addImportGlob = (patterns, opts) => importGlobs.push({ patterns, base: opts?.base, filter: opts?.filter });
285
+ pluginCtx.markImportExpressionHandled = (pos) => handledImportExpressions.add(pos);
286
+ pluginCtx.addImportGlob = (patterns, opts) => importGlobs.push({ patterns, base: opts?.base, cwd: opts?.cwd, filter: opts?.filter });
282
287
  pluginCtx.markExportRegistered = (name) => registeredCustomElements.add(name);
283
288
  }
284
289
  const localRefs = _walkAST(result.program, sourceText, filePath, result.module.hasModuleSyntax, {
@@ -311,6 +316,7 @@ const getImportsAndExports = (filePath, sourceText, resolveModule, options, igno
311
316
  resolveModule,
312
317
  programFiles,
313
318
  entryFiles,
319
+ handledImportExpressions,
314
320
  visitor,
315
321
  getJSDocTags,
316
322
  });
@@ -1,6 +1,6 @@
1
1
  import { existsSync } from 'node:fs';
2
2
  import { _syncGlob } from '../util/glob.js';
3
- import { dirname, isAbsolute, join, toRelative } from '../util/path.js';
3
+ import { dirname, isAbsolute, join, toAbsolute, toRelative } from '../util/path.js';
4
4
  function resolveBaseDir(base, dir, resolveGlobPattern) {
5
5
  if (base.startsWith('.'))
6
6
  return join(dir, base);
@@ -15,8 +15,13 @@ function resolveBaseDir(base, dir, resolveGlobPattern) {
15
15
  export function resolveImportGlobs(items, containingFile, resolveGlobPattern, workspaceRoot) {
16
16
  const filePaths = [];
17
17
  const dir = dirname(containingFile);
18
- for (const { patterns, base, filter } of items) {
19
- if (base !== undefined) {
18
+ for (const { patterns, base, cwd, filter } of items) {
19
+ if (cwd !== undefined) {
20
+ for (const filePath of _syncGlob({ patterns, cwd: toAbsolute(cwd, workspaceRoot) })) {
21
+ filePaths.push(filePath);
22
+ }
23
+ }
24
+ else if (base !== undefined) {
20
25
  const cwd = resolveBaseDir(base, dir, resolveGlobPattern);
21
26
  if (!cwd)
22
27
  continue;
@@ -202,7 +202,7 @@ export function handleCallExpression(node, s) {
202
202
  addValue(internalImport.import, OPAQUE, s.filePath);
203
203
  else {
204
204
  internalImport.refs.add(arg.name);
205
- (internalImport.enumerated ??= new Set()).add(arg.name);
205
+ (internalImport.enumerated ??= new Set()).add(_import.importedName);
206
206
  }
207
207
  }
208
208
  }
@@ -256,7 +256,7 @@ export function handleNewExpression(node, s) {
256
256
  node.arguments[1].property.name === 'url') {
257
257
  const specifier = getStringValue(node.arguments[0]);
258
258
  if (specifier)
259
- s.addImport(specifier, undefined, undefined, undefined, node.arguments[0].start, IMPORT_FLAGS.ENTRY | IMPORT_FLAGS.OPTIONAL);
259
+ s.addImport(specifier, undefined, undefined, undefined, node.arguments[0].start, IMPORT_FLAGS.ENTRY | IMPORT_FLAGS.OPTIONAL, undefined, s.getJSDocTags(node.start));
260
260
  return;
261
261
  }
262
262
  if (s.hasWorkerThreadsImport &&
@@ -2,6 +2,12 @@ import { OPAQUE } from '../../constants.js';
2
2
  import { addValue } from '../../util/module-graph.js';
3
3
  import { getStringValue, isStringLiteral } from '../ast-nodes.js';
4
4
  import { isShadowed } from './walk.js';
5
+ function markWholeObjectRead(internalImport, id) {
6
+ (internalImport.enumerated ??= new Set()).add(id);
7
+ }
8
+ function isNumericKey(value) {
9
+ return value != null && Number.isFinite(Number(value)) && String(Number(value)) === value;
10
+ }
5
11
  export function handleMemberExpression(node, s) {
6
12
  if (node.object.type === 'MemberExpression' && node.object.object.type === 'MemberExpression') {
7
13
  s.chainedMemberExprs.add(node.object);
@@ -18,12 +24,21 @@ export function handleMemberExpression(node, s) {
18
24
  memberName = node.property.name;
19
25
  }
20
26
  else if (node.computed && isStringLiteral(node.property)) {
21
- memberName = getStringValue(node.property);
27
+ const value = getStringValue(node.property);
28
+ if (!_import.isNamespace && isNumericKey(value)) {
29
+ markWholeObjectRead(internalImport, _import.importedName);
30
+ return;
31
+ }
32
+ memberName = value;
22
33
  }
23
34
  else if (node.computed && _import.isNamespace) {
24
35
  addValue(internalImport.import, OPAQUE, s.filePath);
25
36
  return;
26
37
  }
38
+ else if (node.computed) {
39
+ markWholeObjectRead(internalImport, _import.importedName);
40
+ return;
41
+ }
27
42
  if (memberName) {
28
43
  if (_import.isDynamicImport) {
29
44
  addValue(internalImport.import, memberName, s.filePath);
@@ -44,18 +59,51 @@ export function handleMemberExpression(node, s) {
44
59
  if (aliases) {
45
60
  s.accessedAliases.add(localName);
46
61
  let memberName;
62
+ let isWholeRead = false;
47
63
  if (node.computed === false && node.property.type === 'Identifier') {
48
64
  memberName = node.property.name;
49
65
  }
50
66
  else if (node.computed && isStringLiteral(node.property)) {
51
- memberName = getStringValue(node.property);
67
+ const value = getStringValue(node.property);
68
+ if (isNumericKey(value))
69
+ isWholeRead = true;
70
+ else
71
+ memberName = value;
52
72
  }
53
- if (memberName) {
54
- for (const alias of aliases) {
55
- const internalImport = s.internal.get(alias.filePath);
56
- if (internalImport) {
57
- s.addNsMemberRefs(internalImport, alias.id, memberName);
58
- }
73
+ else if (node.computed) {
74
+ isWholeRead = true;
75
+ }
76
+ for (const alias of aliases) {
77
+ const internalImport = s.internal.get(alias.filePath);
78
+ if (!internalImport)
79
+ continue;
80
+ if (isWholeRead) {
81
+ const origin = s.localImportMap.get(alias.id);
82
+ markWholeObjectRead(internalImport, origin?.importedName ?? alias.id);
83
+ }
84
+ else if (memberName) {
85
+ s.addNsMemberRefs(internalImport, alias.id, memberName);
86
+ }
87
+ }
88
+ }
89
+ }
90
+ if (node.computed &&
91
+ node.object.type === 'MemberExpression' &&
92
+ !node.object.computed &&
93
+ node.object.object.type === 'Identifier' &&
94
+ node.object.property.type === 'Identifier') {
95
+ const rootName = node.object.object.name;
96
+ if (!isShadowed(rootName, node.object.object.start)) {
97
+ const _import = s.localImportMap.get(rootName);
98
+ if (_import?.isNamespace) {
99
+ const internalImport = s.internal.get(_import.filePath);
100
+ if (internalImport) {
101
+ const mid = node.object.property.name;
102
+ const value = isStringLiteral(node.property) ? getStringValue(node.property) : undefined;
103
+ if (value !== undefined && !isNumericKey(value))
104
+ s.addNsMemberRefs(internalImport, rootName, `${mid}.${value}`);
105
+ else
106
+ markWholeObjectRead(internalImport, mid);
59
107
  }
60
108
  }
61
109
  }