knip 6.29.0 → 6.31.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 (119) hide show
  1. package/dist/CatalogCounselor.d.ts +5 -2
  2. package/dist/CatalogCounselor.js +26 -8
  3. package/dist/ConfigurationChief.d.ts +7 -1
  4. package/dist/ConfigurationChief.js +29 -36
  5. package/dist/DependencyDeputy.d.ts +8 -1
  6. package/dist/DependencyDeputy.js +5 -5
  7. package/dist/PackagePeeker.d.ts +5 -0
  8. package/dist/PackagePeeker.js +31 -3
  9. package/dist/WorkspaceWorker.d.ts +1 -1
  10. package/dist/WorkspaceWorker.js +11 -7
  11. package/dist/binaries/bash-parser.js +3 -3
  12. package/dist/binaries/create-script-parser-context.d.ts +7 -0
  13. package/dist/binaries/create-script-parser-context.js +17 -0
  14. package/dist/binaries/resolvers/pnpx.js +10 -5
  15. package/dist/compilers/index.d.ts +15 -5
  16. package/dist/compilers/scss.js +32 -5
  17. package/dist/compilers/shared.d.ts +1 -0
  18. package/dist/compilers/shared.js +1 -1
  19. package/dist/compilers/svelte.d.ts +2 -0
  20. package/dist/compilers/svelte.js +22 -0
  21. package/dist/constants.d.ts +4 -1
  22. package/dist/constants.js +4 -0
  23. package/dist/graph/analyze.js +5 -2
  24. package/dist/graph/build.d.ts +3 -1
  25. package/dist/graph/build.js +38 -19
  26. package/dist/graph-explorer/operations/build-exports-tree.js +2 -1
  27. package/dist/graph-explorer/operations/is-referenced.js +7 -4
  28. package/dist/graph-explorer/utils.js +2 -2
  29. package/dist/plugins/_template/index.js +1 -1
  30. package/dist/plugins/astro-markdoc/index.js +3 -2
  31. package/dist/plugins/eleventy/index.js +1 -1
  32. package/dist/plugins/esbuild/index.js +1 -1
  33. package/dist/plugins/eslint/helpers.js +2 -1
  34. package/dist/plugins/gatsby/index.js +2 -2
  35. package/dist/plugins/index.d.ts +1 -0
  36. package/dist/plugins/index.js +2 -0
  37. package/dist/plugins/jest/helpers.js +1 -1
  38. package/dist/plugins/marko/compiler.d.ts +2 -0
  39. package/dist/plugins/marko/compiler.js +85 -0
  40. package/dist/plugins/marko/index.d.ts +3 -0
  41. package/dist/plugins/marko/index.js +63 -0
  42. package/dist/plugins/marko/taglibs.d.ts +4 -0
  43. package/dist/plugins/marko/taglibs.js +111 -0
  44. package/dist/plugins/marko/types.d.ts +9 -0
  45. package/dist/plugins/marko/types.js +1 -0
  46. package/dist/plugins/metro/index.js +1 -1
  47. package/dist/plugins/nest/index.js +1 -1
  48. package/dist/plugins/node/index.js +11 -2
  49. package/dist/plugins/nx/index.js +4 -3
  50. package/dist/plugins/openclaw/index.js +1 -1
  51. package/dist/plugins/oxlint/index.js +9 -2
  52. package/dist/plugins/remark/helpers.d.ts +3 -0
  53. package/dist/plugins/remark/helpers.js +42 -0
  54. package/dist/plugins/remark/index.js +4 -5
  55. package/dist/plugins/rolldown/index.js +1 -1
  56. package/dist/plugins/rollup/index.js +1 -1
  57. package/dist/plugins/rslib/index.js +1 -1
  58. package/dist/plugins/stryker/index.js +6 -1
  59. package/dist/plugins/svelte/compiler.js +7 -5
  60. package/dist/plugins/tsdown/index.js +2 -2
  61. package/dist/plugins/tsup/index.js +1 -1
  62. package/dist/plugins/vitest/index.js +1 -1
  63. package/dist/plugins/vitest/types.d.ts +1 -1
  64. package/dist/reporters/codeclimate.js +1 -5
  65. package/dist/reporters/github-actions.js +5 -3
  66. package/dist/reporters/index.d.ts +1 -0
  67. package/dist/reporters/index.js +2 -0
  68. package/dist/reporters/json.d.ts +1 -0
  69. package/dist/reporters/json.js +1 -0
  70. package/dist/reporters/sarif.d.ts +3 -0
  71. package/dist/reporters/sarif.js +79 -0
  72. package/dist/reporters/trace.js +3 -2
  73. package/dist/reporters/util/util.d.ts +2 -1
  74. package/dist/reporters/util/util.js +6 -1
  75. package/dist/run.d.ts +1 -1
  76. package/dist/run.js +30 -0
  77. package/dist/schema/configuration.d.ts +21 -6
  78. package/dist/schema/configuration.js +1 -0
  79. package/dist/schema/plugins.d.ts +5 -0
  80. package/dist/schema/plugins.js +1 -0
  81. package/dist/session/build-maps.js +2 -1
  82. package/dist/types/PluginNames.d.ts +2 -2
  83. package/dist/types/PluginNames.js +1 -0
  84. package/dist/types/issues.d.ts +1 -0
  85. package/dist/types/package-json.d.ts +10 -0
  86. package/dist/typescript/get-imports-and-exports.js +3 -2
  87. package/dist/typescript/get-published-type-dependencies.d.ts +13 -0
  88. package/dist/typescript/get-published-type-dependencies.js +155 -0
  89. package/dist/typescript/visitors/calls.js +8 -0
  90. package/dist/util/catalog.d.ts +6 -1
  91. package/dist/util/catalog.js +16 -2
  92. package/dist/util/cli-arguments.d.ts +1 -1
  93. package/dist/util/cli-arguments.js +3 -3
  94. package/dist/util/codeowners.js +1 -1
  95. package/dist/util/create-input-handler.js +8 -2
  96. package/dist/util/create-options.d.ts +16 -5
  97. package/dist/util/disk-cache.js +1 -1
  98. package/dist/util/errors.js +3 -2
  99. package/dist/util/file-entry-cache.js +5 -1
  100. package/dist/util/fs.js +2 -2
  101. package/dist/util/get-included-issue-types.js +2 -1
  102. package/dist/util/gitignore-cache.js +4 -1
  103. package/dist/util/glob-cache.js +2 -2
  104. package/dist/util/glob-core.js +3 -1
  105. package/dist/util/input.d.ts +7 -1
  106. package/dist/util/input.js +6 -0
  107. package/dist/util/package-json.d.ts +347 -0
  108. package/dist/util/package-json.js +123 -0
  109. package/dist/util/path.d.ts +8 -7
  110. package/dist/util/resolve.d.ts +6 -0
  111. package/dist/util/resolve.js +24 -0
  112. package/dist/util/string.d.ts +2 -0
  113. package/dist/util/string.js +6 -0
  114. package/dist/util/table.js +2 -2
  115. package/dist/util/to-source-path.js +1 -1
  116. package/dist/version.d.ts +1 -1
  117. package/dist/version.js +1 -1
  118. package/package.json +5 -5
  119. package/schema.json +8 -0
@@ -0,0 +1,2 @@
1
+ import type { CompilerSync } from './types.ts';
2
+ export declare const dynamicImportsWithinTemplate: CompilerSync;
@@ -0,0 +1,22 @@
1
+ import { scriptExtractor, styleExtractor } from './compilers.js';
2
+ const htmlCommentMatcher = /<!--[\s\S]*?-->/g;
3
+ const dynamicImportMatcher = /(?<![.\w$#])import(?:\s|\/\/[^\r\n\u2028\u2029]*(?:[\r\n\u2028\u2029]|$)|\/\*[\s\S]*?(?:\*\/|$))*\((?:\s|\/\/[^\r\n\u2028\u2029]*(?:[\r\n\u2028\u2029]|$)|\/\*[\s\S]*?(?:\*\/|$))*(?:"(?:\\[\s\S]|[^"\\])*"|'(?:\\[\s\S]|[^'\\])*'|`(?:\\[\s\S]|[^`\\$]|\$(?!\{))*`)[^)]*\)/g;
4
+ const svelteExpressionMatcher = /{(?:[^{}]|{(?:[^{}]|{[^{}]*})*})*}/g;
5
+ const javascriptNonCodeMatcher = /"(?:\\[\s\S]|[^"\\])*"|'(?:\\[\s\S]|[^'\\])*'|`(?:\\[\s\S]|[^`\\$]|\$(?!\{))*`|\/\/[^\r\n\u2028\u2029]*|\/\*[\s\S]*?(?:\*\/|$)/g;
6
+ export const dynamicImportsWithinTemplate = text => {
7
+ const template = text.replace(scriptExtractor, '').replace(styleExtractor, '').replace(htmlCommentMatcher, '');
8
+ if (!template.includes('import'))
9
+ return '';
10
+ const imports = [];
11
+ for (const expressionMatch of template.matchAll(svelteExpressionMatcher)) {
12
+ const expression = expressionMatch[0];
13
+ const code = expression.replace(javascriptNonCodeMatcher, match => ' '.repeat(match.length));
14
+ dynamicImportMatcher.lastIndex = 0;
15
+ let importMatch;
16
+ while ((importMatch = dynamicImportMatcher.exec(expression))) {
17
+ if (code.startsWith('import', importMatch.index))
18
+ imports.push(importMatch[0]);
19
+ }
20
+ }
21
+ return imports.join(';\n');
22
+ };
@@ -16,7 +16,7 @@ export declare const IGNORED_DEPENDENCIES: Set<string>;
16
16
  export declare const IGNORED_RUNTIME_DEPENDENCIES: Set<string>;
17
17
  export declare const FOREIGN_FILE_EXTENSIONS: Set<string>;
18
18
  export declare const IGNORE_DEFINITELY_TYPED: Set<string>;
19
- export declare const ISSUE_TYPES: readonly ['files', 'dependencies', 'devDependencies', 'optionalPeerDependencies', 'unlisted', 'binaries', 'unresolved', 'exports', 'nsExports', 'types', 'nsTypes', 'enumMembers', 'namespaceMembers', 'duplicates', 'catalog', 'cycles'];
19
+ export declare const ISSUE_TYPES: readonly ['files', 'dependencies', 'devDependencies', 'optionalPeerDependencies', 'unlisted', 'binaries', 'unresolved', 'exports', 'nsExports', 'types', 'nsTypes', 'enumMembers', 'namespaceMembers', 'duplicates', 'catalog', 'catalogReferences', 'cycles'];
20
20
  export declare const ISSUE_TYPE_TITLE: {
21
21
  readonly files: 'Unused files';
22
22
  readonly dependencies: 'Unused dependencies';
@@ -33,6 +33,7 @@ export declare const ISSUE_TYPE_TITLE: {
33
33
  readonly namespaceMembers: 'Unused exported namespace members';
34
34
  readonly duplicates: 'Duplicate exports';
35
35
  readonly catalog: 'Unused catalog entries';
36
+ readonly catalogReferences: 'Unresolved catalog references';
36
37
  readonly cycles: 'Circular dependencies';
37
38
  };
38
39
  export declare const SYMBOL_TYPE: {
@@ -54,6 +55,7 @@ export declare const FIX_FLAGS: {
54
55
  };
55
56
  export declare const SIDE_EFFECTS = "__side-effects";
56
57
  export declare const OPAQUE = "__opaque";
58
+ export declare const LOADER_DEFAULT = "__loader-default";
57
59
  export declare const SCRIPT_INTERPOLATION = "$__knip__";
58
60
  export declare const IMPORT_FLAGS: {
59
61
  readonly NONE: 0;
@@ -66,4 +68,5 @@ export declare const IMPORT_FLAGS: {
66
68
  readonly OPAQUE: number;
67
69
  readonly AUGMENT: number;
68
70
  readonly DYNAMIC: number;
71
+ readonly LOADER: number;
69
72
  };
package/dist/constants.js CHANGED
@@ -219,6 +219,7 @@ export const ISSUE_TYPES = [
219
219
  'namespaceMembers',
220
220
  'duplicates',
221
221
  'catalog',
222
+ 'catalogReferences',
222
223
  'cycles',
223
224
  ];
224
225
  export const ISSUE_TYPE_TITLE = {
@@ -237,6 +238,7 @@ export const ISSUE_TYPE_TITLE = {
237
238
  namespaceMembers: 'Unused exported namespace members',
238
239
  duplicates: 'Duplicate exports',
239
240
  catalog: 'Unused catalog entries',
241
+ catalogReferences: 'Unresolved catalog references',
240
242
  cycles: 'Circular dependencies',
241
243
  };
242
244
  export const SYMBOL_TYPE = {
@@ -258,6 +260,7 @@ export const FIX_FLAGS = {
258
260
  };
259
261
  export const SIDE_EFFECTS = '__side-effects';
260
262
  export const OPAQUE = '__opaque';
263
+ export const LOADER_DEFAULT = '__loader-default';
261
264
  export const SCRIPT_INTERPOLATION = '$__knip__';
262
265
  export const IMPORT_FLAGS = {
263
266
  NONE: 0,
@@ -270,4 +273,5 @@ export const IMPORT_FLAGS = {
270
273
  OPAQUE: 1 << 6,
271
274
  AUGMENT: 1 << 7,
272
275
  DYNAMIC: 1 << 8,
276
+ LOADER: 1 << 9,
273
277
  };
@@ -154,7 +154,7 @@ export const analyze = async ({ analyzedFiles, counselor, chief, collector, depu
154
154
  }
155
155
  }
156
156
  const [hasStrictlyNsRefs, namespace] = explorer.hasStrictlyNsReferences(filePath, identifier);
157
- const isType = ['enum', 'type', 'interface'].includes(exportedItem.type);
157
+ const isType = exportedItem.type === 'enum' || exportedItem.type === 'type' || exportedItem.type === 'interface';
158
158
  if (isIgnored ||
159
159
  exportedItem.hasRefsInFile ||
160
160
  exportedItem.isRegistered ||
@@ -195,7 +195,10 @@ export const analyze = async ({ analyzedFiles, counselor, chief, collector, depu
195
195
  for (const extImport of file.imports.external) {
196
196
  const packageName = getPackageNameFromModuleSpecifier(extImport.specifier);
197
197
  const isHandled = packageName &&
198
- deputy.maybeAddReferencedExternalDependency(ws, packageName, undefined, extImport.isTypeOnly, extImport.filePath !== undefined);
198
+ deputy.maybeAddReferencedExternalDependency(ws, packageName, {
199
+ isTypeOnly: extImport.isTypeOnly,
200
+ isResolved: extImport.filePath !== undefined,
201
+ });
199
202
  if (!isHandled)
200
203
  collector.addIssue({
201
204
  type: 'unlisted',
@@ -1,3 +1,4 @@
1
+ import type { ScriptParserContext } from '../binaries/create-script-parser-context.ts';
1
2
  import type { CatalogCounselor } from '../CatalogCounselor.ts';
2
3
  import type { ConfigurationChief, Workspace } from '../ConfigurationChief.ts';
3
4
  import type { ConsoleStreamer } from '../ConsoleStreamer.ts';
@@ -13,11 +14,12 @@ interface BuildOptions {
13
14
  deputy: DependencyDeputy;
14
15
  principal: ProjectPrincipal;
15
16
  isGitIgnored: (path: string) => boolean;
17
+ scriptParserContext: ScriptParserContext;
16
18
  streamer: ConsoleStreamer;
17
19
  workspaces: Workspace[];
18
20
  options: MainOptions;
19
21
  }
20
- export declare function build({ chief, collector, counselor, deputy, principal, isGitIgnored, streamer, workspaces, options, }: BuildOptions): Promise<{
22
+ export declare function build({ chief, collector, counselor, deputy, principal, isGitIgnored, scriptParserContext, streamer, workspaces, options, }: BuildOptions): Promise<{
21
23
  graph: ModuleGraph;
22
24
  entryPaths: Set<string>;
23
25
  analyzedFiles: Set<string>;
@@ -9,9 +9,10 @@ import picomatch from 'picomatch';
9
9
  import { tryRealpath } from '../util/fs.js';
10
10
  import { createManifest } from '../util/package-json.js';
11
11
  import { _glob, _syncGlob, negate, prependDirToPattern as prependDir } from '../util/glob.js';
12
- import { isAlias, isConfig, isDeferResolveEntry, isDeferResolveProductionEntry, isEntry, isIgnore, isProductionEntry, isProject, toProductionEntry, } from '../util/input.js';
12
+ import { isAlias, isCatalog, isConfig, isDeferResolveEntry, isDeferResolveProductionEntry, isEntry, isIgnore, isProductionEntry, isProject, toProductionEntry, } from '../util/input.js';
13
13
  import { isAmbientDeclarationFile } from '../typescript/ast-nodes.js';
14
14
  import { resolveImportGlobs } from '../typescript/glob-imports.js';
15
+ import { createPublishedTypeDependencyAnalyzer } from '../typescript/get-published-type-dependencies.js';
15
16
  import { loadTSConfig } from '../util/load-tsconfig.js';
16
17
  import { createFileNode, updateImportMap } from '../util/module-graph.js';
17
18
  import { getPackageNameFromModuleSpecifier, isStartsLikePackageName, sanitizeSpecifier } from '../util/modules.js';
@@ -21,7 +22,7 @@ import { dirname, extname, isAbsolute, isInNodeModules, join, relative } from '.
21
22
  import { extensionAlias } from '../util/resolve.js';
22
23
  import { augmentWorkspace, getToSourcePathsHandler, toSourceMappedSpecifiers } from '../util/to-source-path.js';
23
24
  import { WorkspaceWorker } from '../WorkspaceWorker.js';
24
- export async function build({ chief, collector, counselor, deputy, principal, isGitIgnored, streamer, workspaces, options, }) {
25
+ export async function build({ chief, collector, counselor, deputy, principal, isGitIgnored, scriptParserContext, streamer, workspaces, options, }) {
25
26
  const configFilesMap = new Map();
26
27
  const enabledPluginsStore = new Map();
27
28
  const registeredVisitorPlugins = new Set();
@@ -29,19 +30,10 @@ export async function build({ chief, collector, counselor, deputy, principal, is
29
30
  const addIssue = (issue) => collector.addIssue(issue) && options.isWatch && collector.retainIssue(issue);
30
31
  const externalRefsFromInputs = options.isSession ? new Map() : undefined;
31
32
  const handleInput = createInputHandler(deputy, chief, isGitIgnored, addIssue, externalRefsFromInputs, options);
32
- const rawRootManifest = chief.getManifestForWorkspace('.');
33
- const rootManifest = rawRootManifest ? createManifest(rawRootManifest) : undefined;
34
- const manifestsByWorkspaceName = new Map();
35
- const getManifest = (dir) => {
36
- const workspace = chief.findWorkspaceByFilePath(`${dir}/`);
37
- if (!workspace)
38
- return undefined;
39
- if (!manifestsByWorkspaceName.has(workspace.name)) {
40
- const raw = chief.getManifestForWorkspace(workspace.name);
41
- manifestsByWorkspaceName.set(workspace.name, raw ? createManifest(raw) : undefined);
42
- }
43
- return manifestsByWorkspaceName.get(workspace.name);
44
- };
33
+ const getPublishedTypeDependencies = options.isReportDependencies
34
+ ? createPublishedTypeDependencyAnalyzer()
35
+ : undefined;
36
+ const { rootManifest, getManifest } = scriptParserContext;
45
37
  for (const workspace of workspaces) {
46
38
  const { name, dir, manifestPath, manifestStr } = workspace;
47
39
  const manifest = chief.getManifestForWorkspace(name);
@@ -56,7 +48,6 @@ export async function build({ chief, collector, counselor, deputy, principal, is
56
48
  manifest,
57
49
  ...chief.getIgnores(name),
58
50
  });
59
- counselor.addWorkspace(manifest);
60
51
  }
61
52
  deputy.setWorkspacePkgNames(chief.availableWorkspacePkgNames);
62
53
  collector.addIgnorePatterns(chief.config.ignore.map(id => ({ pattern: prependDir(options.cwd, id), id })));
@@ -65,13 +56,12 @@ export async function build({ chief, collector, counselor, deputy, principal, is
65
56
  principal.addEntryPath(options.configFilePath, { skipExportsAnalysis: true });
66
57
  }
67
58
  for (const workspace of workspaces) {
68
- const { name, dir, ancestors, manifestPath: filePath } = workspace;
59
+ const { name, dir, ancestors, config: baseConfig, manifestPath: filePath } = workspace;
69
60
  streamer.cast('Analyzing workspace', name);
70
61
  const manifest = chief.getManifestForWorkspace(name);
71
62
  if (!manifest)
72
63
  continue;
73
64
  const dependencies = deputy.getDependencies(name);
74
- const baseConfig = chief.getConfigForWorkspace(name);
75
65
  const tsConfigFilePath = join(dir, options.tsConfigFile ?? 'tsconfig.json');
76
66
  const { isFile, compilerOptions, fileNames, include, exclude, sourceMapPairs, paths: tsConfigPaths, } = await loadTSConfig(tsConfigFilePath);
77
67
  const [definitionPaths, tscSourcePaths] = partition(fileNames, filePath => IS_DTS.test(filePath));
@@ -124,6 +114,28 @@ export async function build({ chief, collector, counselor, deputy, principal, is
124
114
  if (!isGitIgnored(filePath))
125
115
  inputs.add(toProductionEntry(filePath));
126
116
  }
117
+ if (getPublishedTypeDependencies && !manifest.private && !manifest.publishConfig?.directory) {
118
+ for (const dependency of getPublishedTypeDependencies(workspace, manifest)) {
119
+ const isHandled = deputy.maybeAddReferencedExternalDependency(workspace, dependency.packageName, {
120
+ isTypeOnly: true,
121
+ isResolved: dependency.isResolved,
122
+ isPublishedType: true,
123
+ });
124
+ if (!isHandled) {
125
+ addIssue({
126
+ type: 'unlisted',
127
+ filePath: dependency.containingFilePath,
128
+ workspace: name,
129
+ symbol: dependency.packageName,
130
+ specifier: dependency.specifier,
131
+ pos: dependency.pos,
132
+ line: dependency.line,
133
+ col: dependency.col,
134
+ fixes: [],
135
+ });
136
+ }
137
+ }
138
+ }
127
139
  for (const identifier of entrySpecifiersFromManifest) {
128
140
  if (identifier.startsWith('!') || isGitIgnored(join(dir, identifier)))
129
141
  continue;
@@ -175,7 +187,10 @@ export async function build({ chief, collector, counselor, deputy, principal, is
175
187
  if (input.group)
176
188
  groups.add(input.group);
177
189
  const specifier = input.specifier;
178
- if (isEntry(input)) {
190
+ if (isCatalog(input)) {
191
+ counselor.addReference({ catalogName: input.catalogName, packageName: specifier });
192
+ }
193
+ else if (isEntry(input)) {
179
194
  const targetMap = input.skipExportsAnalysis ? entryPatternsSkipExports : entryPatterns;
180
195
  addPattern(targetMap, input, toWorkspaceRelative(specifier));
181
196
  }
@@ -390,6 +405,10 @@ export async function build({ chief, collector, counselor, deputy, principal, is
390
405
  };
391
406
  const inputs = _getInputsFromScripts(file.scripts, opts);
392
407
  for (const input of inputs) {
408
+ if (isCatalog(input)) {
409
+ counselor.addReference({ catalogName: input.catalogName, packageName: input.specifier });
410
+ continue;
411
+ }
393
412
  input.containingFilePath ??= filePath;
394
413
  input.dir ??= dir;
395
414
  const specifierFilePath = handleInput(input, workspace);
@@ -1,3 +1,4 @@
1
+ import { substringBefore } from '../../util/string.js';
1
2
  import { CONTINUE } from '../constants.js';
2
3
  import { walkDown } from '../walk-down.js';
3
4
  export const buildExportsTree = (graph, entryPaths, options) => {
@@ -38,7 +39,7 @@ const buildExportTree = (graph, entryPaths, filePath, identifier) => {
38
39
  walkDown(graph, filePath, identifier, (sourceFile, sourceId, importingFile, id, isEntry, via) => {
39
40
  const importMaps = graph.get(importingFile)?.imports.internal.get(sourceFile);
40
41
  const importRefs = importMaps?.refs;
41
- const ns = id.split('.')[0];
42
+ const ns = substringBefore(id, '.');
42
43
  if (via === 'importNS' && !hasRelevantRef(importRefs, id) && !isNsReExported(importMaps, ns))
43
44
  return CONTINUE;
44
45
  const key = `${importingFile}:${id}`;
@@ -1,4 +1,4 @@
1
- import { OPAQUE } from '../../constants.js';
1
+ import { LOADER_DEFAULT, OPAQUE } from '../../constants.js';
2
2
  import { getAliasReExportMap, getNamespaceReExportSources, getPassThroughReExportSources, getStarReExportSources, } from '../visitors.js';
3
3
  const hasOnlyNsRefs = (file) => {
4
4
  if (file.importNs.size === 0)
@@ -33,8 +33,9 @@ export const isReferenced = (graph, entryPaths, filePath, id, options) => {
33
33
  isReferenced = true;
34
34
  return hasCompleteResult();
35
35
  }
36
- const file = graph.get(path)?.importedBy;
37
- if (!identifier || !file) {
36
+ const node = graph.get(path);
37
+ const file = node?.importedBy;
38
+ if (!identifier || !node || !file) {
38
39
  return false;
39
40
  }
40
41
  const follow = (sources, nextId, nextViaStar = viaStar) => {
@@ -45,7 +46,9 @@ export const isReferenced = (graph, entryPaths, filePath, id, options) => {
45
46
  return false;
46
47
  };
47
48
  if (!isReferenced) {
48
- const hasDirectReference = (file.import.get(OPAQUE) && !hasOnlyNsRefs(file)) ||
49
+ const isLoaderImport = file.import.has(LOADER_DEFAULT);
50
+ const hasDirectReference = ((file.import.get(OPAQUE) || (isLoaderImport && !node.exports.has('default'))) && !hasOnlyNsRefs(file)) ||
51
+ (isLoaderImport && identifier === 'default') ||
49
52
  ((identifier === id || (identifier !== id && file.refs.has(id))) &&
50
53
  (file.import.has(identifier) || file.importAs.has(identifier)));
51
54
  if (hasDirectReference) {
@@ -1,4 +1,4 @@
1
- import { IMPORT_FLAGS, IMPORT_STAR, OPAQUE, SIDE_EFFECTS } from '../constants.js';
1
+ import { IMPORT_FLAGS, IMPORT_STAR, LOADER_DEFAULT, OPAQUE, SIDE_EFFECTS } from '../constants.js';
2
2
  import { getCachedExportedIdentifiers, setCachedExportedIdentifiers } from './cache.js';
3
3
  import { forEachAliasReExport, forEachNamespaceReExport, forEachPassThroughReExport, getStarReExportSources, } from './visitors.js';
4
4
  const IGNORED_CYCLE_IMPORT_FLAGS = IMPORT_FLAGS.ENTRY | IMPORT_FLAGS.DYNAMIC;
@@ -79,7 +79,7 @@ const getImportKind = (importMaps, identifier, modifiers) => {
79
79
  return 'importNS';
80
80
  if (identifier && importMaps.importAs.has(identifier))
81
81
  return 'importAs';
82
- if (identifier === OPAQUE)
82
+ if (identifier === OPAQUE || identifier === LOADER_DEFAULT)
83
83
  return 'dynamicImport';
84
84
  if (identifier === SIDE_EFFECTS)
85
85
  return 'sideEffectImport';
@@ -8,7 +8,7 @@ const entry = [];
8
8
  const production = [];
9
9
  const resolveConfig = async (config) => {
10
10
  const inputs = config?.plugins ?? [];
11
- return [...inputs].map(id => toDeferResolve(id));
11
+ return Array.from(inputs, id => toDeferResolve(id));
12
12
  };
13
13
  const plugin = {
14
14
  title,
@@ -1,17 +1,18 @@
1
1
  import { toProductionEntry } from '../../util/input.js';
2
2
  import { hasDependency } from '../../util/plugin.js';
3
+ import { substringBefore } from '../../util/string.js';
3
4
  const title = 'Astro Markdoc';
4
5
  const enablers = ['@astrojs/markdoc'];
5
6
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
6
7
  const config = ['markdoc.config.{js,ts,mjs,mts}'];
7
8
  const extractSpecifiers = (renderField) => {
8
9
  if (typeof renderField === 'string') {
9
- return [renderField.split('#')[0]];
10
+ return [substringBefore(renderField, '#')];
10
11
  }
11
12
  if (renderField && typeof renderField === 'object') {
12
13
  for (const key of ['Component', 'file', 'path']) {
13
14
  if (typeof renderField[key] === 'string') {
14
- return [renderField[key].split('#')[0]];
15
+ return [substringBefore(renderField[key], '#')];
15
16
  }
16
17
  }
17
18
  }
@@ -17,7 +17,7 @@ const resolveConfig = async (localConfig, options) => {
17
17
  const inputDir = localConfig?.dir?.input || defaultEleventyConfig.dir.input;
18
18
  const dataDir = localConfig?.dir?.data || defaultEleventyConfig.dir.data;
19
19
  const templateFormats = localConfig?.templateFormats || defaultEleventyConfig.templateFormats;
20
- const exts = [...DEFAULT_EXTENSIONS].map(extname => extname.slice(1)).join(',');
20
+ const exts = Array.from(DEFAULT_EXTENSIONS, extname => extname.slice(1)).join(',');
21
21
  const copiedEntries = new Set();
22
22
  const copiedPackages = new Set();
23
23
  for (const path of Object.keys(dummyUserConfig.passthroughCopies)) {
@@ -6,7 +6,7 @@ const title = 'esbuild';
6
6
  const enablers = ['esbuild'];
7
7
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
8
8
  const config = ['esbuild.config.{js,mjs,cjs,ts,mts,cts}', 'esbuild.{js,mjs,cjs,ts,mts,cts}'];
9
- const resolveFromAST = (program, { configFileDir }) => [...collectPropertyValues(program, 'entryPoints')].map(id => toProductionEntry(join(configFileDir, id)));
9
+ const resolveFromAST = (program, { configFileDir }) => Array.from(collectPropertyValues(program, 'entryPoints'), id => toProductionEntry(join(configFileDir, id)));
10
10
  const plugin = {
11
11
  title,
12
12
  enablers,
@@ -2,6 +2,7 @@ import { compact } from '../../util/array.js';
2
2
  import { toConfig, toDeferResolve, toDependency } from '../../util/input.js';
3
3
  import { getPackageNameFromFilePath, getPackageNameFromModuleSpecifier } from '../../util/modules.js';
4
4
  import { extname, isAbsolute, isInternal } from '../../util/path.js';
5
+ import { substringBefore } from '../../util/string.js';
5
6
  import { getDependenciesFromConfig } from '../babel/index.js';
6
7
  export const isFlatConfig = (fileName) => /eslint\.config/.test(fileName);
7
8
  export const getInputs = (config, options) => {
@@ -41,7 +42,7 @@ const resolveSpecifier = (namespace, rawSpecifier) => {
41
42
  if (!specifier.startsWith('@')) {
42
43
  const id = rawSpecifier.startsWith('plugin:')
43
44
  ? getPackageNameFromModuleSpecifier(specifier)
44
- : specifier.split('/')[0];
45
+ : substringBefore(specifier, '/');
45
46
  return `${namespace}-${id}`;
46
47
  }
47
48
  const [scope, name, ...rest] = specifier.split('/');
@@ -14,12 +14,12 @@ const production = [
14
14
  ];
15
15
  const resolveConfig = async (localConfig, options) => {
16
16
  const { configFileName } = options;
17
- if (/gatsby-config/.test(configFileName)) {
17
+ if (configFileName.includes('gatsby-config')) {
18
18
  return localConfig.plugins
19
19
  .map(plugin => (typeof plugin === 'string' ? plugin : plugin.resolve))
20
20
  .map(id => toDeferResolve(id));
21
21
  }
22
- if (/gatsby-node/.test(configFileName)) {
22
+ if (configFileName.includes('gatsby-node')) {
23
23
  const plugins = new Set();
24
24
  const actions = { setBabelPlugin: plugin => plugins.add(plugin.name) };
25
25
  const _config = localConfig;
@@ -63,6 +63,7 @@ export declare const Plugins: {
63
63
  'lost-pixel': import("../types/config.ts").Plugin;
64
64
  lunaria: import("../types/config.ts").Plugin;
65
65
  markdownlint: import("../types/config.ts").Plugin;
66
+ marko: import("../types/config.ts").Plugin;
66
67
  mdx: import("../types/config.ts").Plugin;
67
68
  mdxlint: import("../types/config.ts").Plugin;
68
69
  metro: import("../types/config.ts").Plugin;
@@ -57,6 +57,7 @@ import { default as lockfileLint } from './lockfile-lint/index.js';
57
57
  import { default as lostPixel } from './lost-pixel/index.js';
58
58
  import { default as lunaria } from './lunaria/index.js';
59
59
  import { default as markdownlint } from './markdownlint/index.js';
60
+ import { default as marko } from './marko/index.js';
60
61
  import { default as mdx } from './mdx/index.js';
61
62
  import { default as mdxlint } from './mdxlint/index.js';
62
63
  import { default as metro } from './metro/index.js';
@@ -236,6 +237,7 @@ export const Plugins = {
236
237
  'lost-pixel': lostPixel,
237
238
  lunaria,
238
239
  markdownlint,
240
+ marko,
239
241
  mdx,
240
242
  mdxlint,
241
243
  metro,
@@ -35,7 +35,7 @@ export const getReportersDependencies = (config, options) => {
35
35
  const reporters = config.reporters
36
36
  ? config.reporters
37
37
  .map(reporter => (typeof reporter === 'string' ? reporter : reporter[0]))
38
- .filter(reporter => !['default', 'github-actions', 'summary'].includes(reporter))
38
+ .filter(reporter => reporter !== 'default' && reporter !== 'github-actions' && reporter !== 'summary')
39
39
  : [];
40
40
  return [...reporters, ...jUnitReporterDeps];
41
41
  };
@@ -0,0 +1,2 @@
1
+ import type { CompilerSync } from '../../compilers/types.ts';
2
+ export declare const createCompiler: (tagDependencies?: Map<string, string[]>, fallbackDependencies?: string[]) => CompilerSync;
@@ -0,0 +1,85 @@
1
+ import { getStyleLang, styleExtractor } from '../../compilers/compilers.js';
2
+ import { compiler as lessCompiler } from '../../compilers/less.js';
3
+ import { compiler as scssCompiler } from '../../compilers/scss.js';
4
+ import { compiler as stylusCompiler } from '../../compilers/stylus.js';
5
+ const commentMatcher = /<!--[\s\S]*?-->|\/\*[\s\S]*?\*\/|^[ \t]*\/\/.*$/gm;
6
+ const conciseStyleMatcher = /^[ \t]*style(?:\.([\w.-]+))?[^\n{]*\{([\s\S]*?)^[ \t]*\}/gm;
7
+ const htmlTagMatcher = /<([a-z][\w.-]*)(?=[\s/|>])/g;
8
+ const conciseTagMatcher = /^[ \t]*([a-z][\w.-]*)(?=[ \t/|]|--|$)/gm;
9
+ const tagImportMatcher = /^[ \t]*(?:(?:server|client|static|\$)[ \t]+)?import[ \t\r\n]+(?:type[ \t\r\n]+)?(?:[$\w]+(?:[ \t\r\n]*,[ \t\r\n]*(?:\*[ \t\r\n]+as[ \t\r\n]+[$\w]+|\{[^}]*\}))?|\*[ \t\r\n]+as[ \t\r\n]+[$\w]+|\{[^}]*\})[ \t\r\n]+from[ \t\r\n]*(["'])<[^"'\r\n]+>\1(?:[ \t\r\n]+with[ \t\r\n]*\{(?:[^}"']+|"[^"]*"|'[^']*')*\})?[ \t]*;?[ \t]*(?:\r?\n|$)/gm;
10
+ const markupLineMatcher = /^[ \t]*<.*$/gm;
11
+ const markoPrefixMatcher = /^([ \t]*)(?:server|client|\$)[ \t]+/gm;
12
+ const staticPrefixMatcher = /^([ \t]*)static[ \t]+(?=(?:import|export|const|let|var|function|class|interface|type|enum|namespace|async[ \t]+function)\b)/gm;
13
+ const staticBlockPrefixMatcher = /^([ \t]*)static[ \t]+(?=\{)/gm;
14
+ const classBodyMatcher = /^([ \t]*)class\b[^{]*\{[\s\S]*?^\1\}/gm;
15
+ const classStaticBlockMatcher = /^([ \t]*)static(?=[ \t]*\{)/gm;
16
+ const classStaticBlockPlaceholder = '__MARKO_CLASS_STATIC_BLOCK__';
17
+ const anonymousClassMatcher = /^([ \t]*)class[ \t]*\{/gm;
18
+ const localExportDeclarationMatcher = /^([ \t]*)export[ \t]+(?:default[ \t]+)?(?=(?:(?:declare|abstract|async)[ \t]+)*(?:interface|type[ \t]+[$\w]+|const|let|var|function|class|enum|namespace)\b)/gm;
19
+ const localExportListMatcher = /^[ \t]*export[ \t]+(?:type[ \t]+)?\{[^}]*\}(?![ \t\r\n]*from\b)[ \t]*;?[ \t]*(?=\r?$)/gm;
20
+ const compileStyle = (body, lang, path) => {
21
+ switch (lang) {
22
+ case 'less':
23
+ return lessCompiler(body, path);
24
+ case 'styl':
25
+ case 'stylus':
26
+ return stylusCompiler(body, path);
27
+ default:
28
+ return scssCompiler(body, path);
29
+ }
30
+ };
31
+ const collectStyles = (text, path) => {
32
+ const imports = [];
33
+ styleExtractor.lastIndex = 0;
34
+ let match;
35
+ while ((match = styleExtractor.exec(text))) {
36
+ const lang = getStyleLang(match[1]) ?? match[1].match(/\.([\w-]+)/)?.[1];
37
+ const output = compileStyle(match[2], lang, path);
38
+ if (output)
39
+ imports.push(output);
40
+ }
41
+ conciseStyleMatcher.lastIndex = 0;
42
+ while ((match = conciseStyleMatcher.exec(text))) {
43
+ const output = compileStyle(match[2], match[1]?.split('.').pop(), path);
44
+ if (output)
45
+ imports.push(output);
46
+ }
47
+ return imports;
48
+ };
49
+ const sanitize = (text) => {
50
+ const source = text
51
+ .replace(styleExtractor, '')
52
+ .replace(conciseStyleMatcher, '')
53
+ .replace(tagImportMatcher, '')
54
+ .replace(markupLineMatcher, '')
55
+ .replace(markoPrefixMatcher, '$1')
56
+ .replace(staticPrefixMatcher, '$1')
57
+ .replace(localExportDeclarationMatcher, '$1')
58
+ .replace(localExportListMatcher, '');
59
+ return source
60
+ .replace(classBodyMatcher, body => body.replace(classStaticBlockMatcher, `$1${classStaticBlockPlaceholder}`))
61
+ .replace(staticBlockPrefixMatcher, '$1')
62
+ .replaceAll(classStaticBlockPlaceholder, 'static')
63
+ .replace(anonymousClassMatcher, '$1class MarkoComponent {');
64
+ };
65
+ const collectTagDependencies = (text, tagDependencies, fallbackDependencies) => {
66
+ const dependencies = new Set(fallbackDependencies);
67
+ for (const matcher of [htmlTagMatcher, conciseTagMatcher]) {
68
+ matcher.lastIndex = 0;
69
+ let match;
70
+ while ((match = matcher.exec(text))) {
71
+ for (const dependency of tagDependencies.get(match[1]) ?? [])
72
+ dependencies.add(dependency);
73
+ }
74
+ }
75
+ return Array.from(dependencies, dependency => `import "${dependency}";`);
76
+ };
77
+ export const createCompiler = (tagDependencies = new Map(), fallbackDependencies = []) => (text, path) => {
78
+ const source = text.replace(commentMatcher, '');
79
+ return [
80
+ 'import "marko";',
81
+ ...collectTagDependencies(source, tagDependencies, fallbackDependencies),
82
+ ...collectStyles(source, path),
83
+ sanitize(source),
84
+ ].join('\n');
85
+ };
@@ -0,0 +1,3 @@
1
+ import type { Plugin } from '../../types/config.ts';
2
+ declare const plugin: Plugin;
3
+ export default plugin;
@@ -0,0 +1,63 @@
1
+ import { toDeferResolve, toProductionEntry } from '../../util/input.js';
2
+ import { join, relative } from '../../util/path.js';
3
+ import { hasDependency } from '../../util/plugin.js';
4
+ import { createCompiler } from './compiler.js';
5
+ import { getTaglibDependencies } from './taglibs.js';
6
+ const title = 'Marko';
7
+ const enablers = ['marko'];
8
+ const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
9
+ const config = ['**/marko.json', '**/marko-tag.json'];
10
+ const tagDiscoveryDirs = ['components', 'tags'];
11
+ const scriptExtensions = '{js,jsx,ts,tsx,mjs,cjs,mts,cts}';
12
+ const styleExtensions = '{css,less,scss,sass,styl,stylus}';
13
+ const tagFilePatterns = [
14
+ '**/*.marko',
15
+ `**/{component,component-browser}.${scriptExtensions}`,
16
+ `**/*.{component,component-browser}.${scriptExtensions}`,
17
+ `**/style.${styleExtensions}`,
18
+ `**/*.style.${styleExtensions}`,
19
+ ];
20
+ const tagProduction = tagFilePatterns.map(pattern => `**/{${tagDiscoveryDirs.join(',')}}/${pattern}`);
21
+ const production = tagProduction;
22
+ const tagDefFields = [
23
+ 'template',
24
+ 'renderer',
25
+ 'parse',
26
+ 'migrate',
27
+ 'transform',
28
+ 'analyze',
29
+ 'translate',
30
+ ];
31
+ const resolveConfig = (localConfig, options) => {
32
+ const { configFileName, configFileDir, cwd } = options;
33
+ const inputs = [];
34
+ if (!localConfig)
35
+ return inputs;
36
+ if (configFileName === 'marko.json') {
37
+ const dir = relative(cwd, configFileDir);
38
+ return tagProduction.map(pattern => toProductionEntry(join(dir, pattern)));
39
+ }
40
+ for (const field of tagDefFields) {
41
+ for (const id of [localConfig[field]].flat()) {
42
+ if (typeof id === 'string')
43
+ inputs.push(toDeferResolve(join(configFileDir, id)));
44
+ }
45
+ }
46
+ return inputs;
47
+ };
48
+ const registerCompilers = async ({ cwd, registerCompiler, hasDependency }) => {
49
+ if (hasDependency('marko')) {
50
+ const { tagDependencies, fallbackDependencies } = await getTaglibDependencies(cwd);
51
+ registerCompiler({ extension: '.marko', compiler: createCompiler(tagDependencies, fallbackDependencies) });
52
+ }
53
+ };
54
+ const plugin = {
55
+ title,
56
+ enablers,
57
+ isEnabled,
58
+ config,
59
+ production,
60
+ resolveConfig,
61
+ registerCompilers,
62
+ };
63
+ export default plugin;
@@ -0,0 +1,4 @@
1
+ export declare const getTaglibDependencies: (cwd: string) => Promise<{
2
+ tagDependencies: Map<string, string[]>;
3
+ fallbackDependencies: string[];
4
+ }>;