projscan 2.0.0 → 2.1.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.
- package/README.md +15 -7
- package/dist/cli/_shared.d.ts +1 -0
- package/dist/cli/_shared.js +19 -3
- package/dist/cli/_shared.js.map +1 -1
- package/dist/cli/commands/analyze.js +7 -3
- package/dist/cli/commands/analyze.js.map +1 -1
- package/dist/cli/commands/applyFix.js +2 -2
- package/dist/cli/commands/applyFix.js.map +1 -1
- package/dist/cli/commands/audit.js +2 -2
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/badge.js +2 -1
- package/dist/cli/commands/badge.js.map +1 -1
- package/dist/cli/commands/ci.js +3 -3
- package/dist/cli/commands/ci.js.map +1 -1
- package/dist/cli/commands/coupling.js +2 -2
- package/dist/cli/commands/coupling.js.map +1 -1
- package/dist/cli/commands/coverage.js +2 -2
- package/dist/cli/commands/coverage.js.map +1 -1
- package/dist/cli/commands/dependencies.js +2 -2
- package/dist/cli/commands/dependencies.js.map +1 -1
- package/dist/cli/commands/diagram.js +2 -2
- package/dist/cli/commands/diagram.js.map +1 -1
- package/dist/cli/commands/diff.js +2 -2
- package/dist/cli/commands/diff.js.map +1 -1
- package/dist/cli/commands/doctor.js +3 -3
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/explain.js +2 -2
- package/dist/cli/commands/explain.js.map +1 -1
- package/dist/cli/commands/explainIssue.js +2 -2
- package/dist/cli/commands/explainIssue.js.map +1 -1
- package/dist/cli/commands/file.js +2 -2
- package/dist/cli/commands/file.js.map +1 -1
- package/dist/cli/commands/fix.js +2 -1
- package/dist/cli/commands/fix.js.map +1 -1
- package/dist/cli/commands/fixSuggest.js +2 -2
- package/dist/cli/commands/fixSuggest.js.map +1 -1
- package/dist/cli/commands/help.js +2 -1
- package/dist/cli/commands/help.js.map +1 -1
- package/dist/cli/commands/hotspots.js +2 -2
- package/dist/cli/commands/hotspots.js.map +1 -1
- package/dist/cli/commands/impact.js +2 -2
- package/dist/cli/commands/impact.js.map +1 -1
- package/dist/cli/commands/init.js +2 -1
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/installHook.js +2 -1
- package/dist/cli/commands/installHook.js.map +1 -1
- package/dist/cli/commands/mcp.js +2 -1
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/memory.js +5 -4
- package/dist/cli/commands/memory.js.map +1 -1
- package/dist/cli/commands/outdated.js +2 -2
- package/dist/cli/commands/outdated.js.map +1 -1
- package/dist/cli/commands/plugin.js +83 -3
- package/dist/cli/commands/plugin.js.map +1 -1
- package/dist/cli/commands/prDiff.js +2 -2
- package/dist/cli/commands/prDiff.js.map +1 -1
- package/dist/cli/commands/preflight.d.ts +1 -0
- package/dist/cli/commands/preflight.js +80 -0
- package/dist/cli/commands/preflight.js.map +1 -0
- package/dist/cli/commands/review.js +2 -2
- package/dist/cli/commands/review.js.map +1 -1
- package/dist/cli/commands/search.js +2 -2
- package/dist/cli/commands/search.js.map +1 -1
- package/dist/cli/commands/session.js +5 -5
- package/dist/cli/commands/session.js.map +1 -1
- package/dist/cli/commands/structure.js +2 -2
- package/dist/cli/commands/structure.js.map +1 -1
- package/dist/cli/commands/taint.js +2 -2
- package/dist/cli/commands/taint.js.map +1 -1
- package/dist/cli/commands/upgrade.js +2 -2
- package/dist/cli/commands/upgrade.js.map +1 -1
- package/dist/cli/commands/watch.js +2 -1
- package/dist/cli/commands/watch.js.map +1 -1
- package/dist/cli/commands/workspace.js +4 -2
- package/dist/cli/commands/workspace.js.map +1 -1
- package/dist/cli/commands/workspaces.js +2 -2
- package/dist/cli/commands/workspaces.js.map +1 -1
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/core/pluginDx.d.ts +14 -0
- package/dist/core/pluginDx.js +298 -0
- package/dist/core/pluginDx.js.map +1 -0
- package/dist/core/plugins.d.ts +5 -6
- package/dist/core/plugins.js +99 -13
- package/dist/core/plugins.js.map +1 -1
- package/dist/core/preflight.d.ts +11 -0
- package/dist/core/preflight.js +416 -0
- package/dist/core/preflight.js.map +1 -0
- package/dist/core/review.js +101 -1
- package/dist/core/review.js.map +1 -1
- package/dist/core/sessionResources.d.ts +6 -0
- package/dist/core/sessionResources.js +216 -0
- package/dist/core/sessionResources.js.map +1 -0
- package/dist/mcp/resources.js +25 -0
- package/dist/mcp/resources.js.map +1 -1
- package/dist/mcp/tools/preflight.d.ts +2 -0
- package/dist/mcp/tools/preflight.js +51 -0
- package/dist/mcp/tools/preflight.js.map +1 -0
- package/dist/mcp/tools.js +2 -0
- package/dist/mcp/tools.js.map +1 -1
- package/dist/reporters/htmlReporter.d.ts +2 -1
- package/dist/reporters/htmlReporter.js +70 -0
- package/dist/reporters/htmlReporter.js.map +1 -1
- package/dist/tool-manifest.json +33 -3
- package/dist/types.d.ts +137 -0
- package/dist/utils/banner.js +14 -4
- package/dist/utils/banner.js.map +1 -1
- package/dist/utils/fileWalker.js +4 -0
- package/dist/utils/fileWalker.js.map +1 -1
- package/dist/utils/formatSupport.d.ts +58 -0
- package/dist/utils/formatSupport.js +63 -0
- package/dist/utils/formatSupport.js.map +1 -0
- package/docs/PLUGIN-AUTHORING.md +30 -0
- package/package.json +4 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import { program, getRootPath,
|
|
2
|
+
import { program, getRootPath, setupLogLevel, maybeCompactBanner, assertFormatSupported } from '../_shared.js';
|
|
3
3
|
import { addRepo, loadOrCreateWorkspace, loadWorkspace, removeRepo, saveWorkspace, } from '../../core/workspace.js';
|
|
4
4
|
/**
|
|
5
5
|
* `projscan workspace` (1.6+) — register and inspect cross-repo
|
|
@@ -42,7 +42,7 @@ async function runList() {
|
|
|
42
42
|
setupLogLevel();
|
|
43
43
|
maybeCompactBanner();
|
|
44
44
|
const rootPath = getRootPath();
|
|
45
|
-
const format =
|
|
45
|
+
const format = assertFormatSupported('workspace list');
|
|
46
46
|
try {
|
|
47
47
|
const w = await loadWorkspace(rootPath);
|
|
48
48
|
if (format === 'json') {
|
|
@@ -59,6 +59,7 @@ async function runList() {
|
|
|
59
59
|
async function runAdd(repoPath, name) {
|
|
60
60
|
setupLogLevel();
|
|
61
61
|
maybeCompactBanner();
|
|
62
|
+
assertFormatSupported('workspace add');
|
|
62
63
|
const rootPath = getRootPath();
|
|
63
64
|
try {
|
|
64
65
|
const w = await loadOrCreateWorkspace(rootPath);
|
|
@@ -75,6 +76,7 @@ async function runAdd(repoPath, name) {
|
|
|
75
76
|
async function runRemove(pathOrName) {
|
|
76
77
|
setupLogLevel();
|
|
77
78
|
maybeCompactBanner();
|
|
79
|
+
assertFormatSupported('workspace remove');
|
|
78
80
|
const rootPath = getRootPath();
|
|
79
81
|
try {
|
|
80
82
|
const w = await loadWorkspace(rootPath);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../../src/cli/commands/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../../src/cli/commands/workspace.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import { program,
|
|
2
|
+
import { program, getRootPath, setupLogLevel, maybeCompactBanner, assertFormatSupported } from '../_shared.js';
|
|
3
3
|
import { detectWorkspaces } from '../../core/monorepo.js';
|
|
4
4
|
import { reportWorkspaces } from '../../reporters/consoleReporter.js';
|
|
5
5
|
import { reportWorkspacesJson } from '../../reporters/jsonReporter.js';
|
|
@@ -12,7 +12,7 @@ export function registerWorkspaces() {
|
|
|
12
12
|
setupLogLevel();
|
|
13
13
|
maybeCompactBanner();
|
|
14
14
|
const rootPath = getRootPath();
|
|
15
|
-
const format =
|
|
15
|
+
const format = assertFormatSupported('workspaces');
|
|
16
16
|
try {
|
|
17
17
|
const info = await detectWorkspaces(rootPath);
|
|
18
18
|
switch (format) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspaces.js","sourceRoot":"","sources":["../../../src/cli/commands/workspaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"workspaces.js","sourceRoot":"","sources":["../../../src/cli/commands/workspaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC/G,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAE/E,MAAM,UAAU,kBAAkB;IAChC,OAAO;SACJ,OAAO,CAAC,YAAY,CAAC;SACrB,WAAW,CAAC,sGAAsG,CAAC;SACnH,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,aAAa,EAAE,CAAC;QAChB,kBAAkB,EAAE,CAAC;QACrB,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAC;QACnD,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YAC9C,QAAQ,MAAM,EAAE,CAAC;gBACf,KAAK,MAAM;oBACT,oBAAoB,CAAC,IAAI,CAAC,CAAC;oBAC3B,MAAM;gBACR,KAAK,UAAU;oBACb,wBAAwB,CAAC,IAAI,CAAC,CAAC;oBAC/B,MAAM;gBACR;oBACE,gBAAgB,CAAC,IAAI,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACjF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
|
package/dist/cli/index.js
CHANGED
|
@@ -34,6 +34,7 @@ import { registerInstallHook } from './commands/installHook.js';
|
|
|
34
34
|
import { registerTaint } from './commands/taint.js';
|
|
35
35
|
import { registerBadge } from './commands/badge.js';
|
|
36
36
|
import { registerPlugin } from './commands/plugin.js';
|
|
37
|
+
import { registerPreflight } from './commands/preflight.js';
|
|
37
38
|
import { registerHelp } from './commands/help.js';
|
|
38
39
|
registerAnalyze();
|
|
39
40
|
registerDoctor();
|
|
@@ -69,6 +70,7 @@ registerInstallHook();
|
|
|
69
70
|
registerTaint();
|
|
70
71
|
registerBadge();
|
|
71
72
|
registerPlugin();
|
|
73
|
+
registerPreflight();
|
|
72
74
|
registerHelp();
|
|
73
75
|
program.parse();
|
|
74
76
|
//# sourceMappingURL=index.js.map
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,eAAe,EAAE,CAAC;AAClB,cAAc,EAAE,CAAC;AACjB,UAAU,EAAE,CAAC;AACb,YAAY,EAAE,CAAC;AACf,WAAW,EAAE,CAAC;AACd,YAAY,EAAE,CAAC;AACf,eAAe,EAAE,CAAC;AAClB,eAAe,EAAE,CAAC;AAClB,iBAAiB,EAAE,CAAC;AACpB,oBAAoB,EAAE,CAAC;AACvB,gBAAgB,EAAE,CAAC;AACnB,gBAAgB,EAAE,CAAC;AACnB,cAAc,EAAE,CAAC;AACjB,cAAc,EAAE,CAAC;AACjB,kBAAkB,EAAE,CAAC;AACrB,oBAAoB,EAAE,CAAC;AACvB,cAAc,EAAE,CAAC;AACjB,aAAa,EAAE,CAAC;AAChB,kBAAkB,EAAE,CAAC;AACrB,gBAAgB,EAAE,CAAC;AACnB,aAAa,EAAE,CAAC;AAChB,eAAe,EAAE,CAAC;AAClB,cAAc,EAAE,CAAC;AACjB,gBAAgB,EAAE,CAAC;AACnB,WAAW,EAAE,CAAC;AACd,eAAe,EAAE,CAAC;AAClB,cAAc,EAAE,CAAC;AACjB,iBAAiB,EAAE,CAAC;AACpB,gBAAgB,EAAE,CAAC;AACnB,YAAY,EAAE,CAAC;AACf,mBAAmB,EAAE,CAAC;AACtB,aAAa,EAAE,CAAC;AAChB,aAAa,EAAE,CAAC;AAChB,cAAc,EAAE,CAAC;AACjB,iBAAiB,EAAE,CAAC;AACpB,YAAY,EAAE,CAAC;AAEf,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { PluginTestResult } from '../types.js';
|
|
2
|
+
export interface InitPluginOptions {
|
|
3
|
+
kind?: 'analyzer' | 'reporter';
|
|
4
|
+
name?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface InitPluginResult {
|
|
7
|
+
manifestPath: string;
|
|
8
|
+
modulePath: string;
|
|
9
|
+
}
|
|
10
|
+
export interface TestPluginOptions {
|
|
11
|
+
fixtureRoot?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function initPlugin(rootPath: string, options?: InitPluginOptions): Promise<InitPluginResult>;
|
|
14
|
+
export declare function testPlugin(manifestPath: string, options?: TestPluginOptions): Promise<PluginTestResult>;
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { pathToFileURL } from 'node:url';
|
|
4
|
+
import { scanRepository } from './repositoryScanner.js';
|
|
5
|
+
import { PLUGIN_DIR, PLUGIN_MANIFEST_EXT, PLUGIN_REPORTER_COMMANDS, readPluginManifestFile, } from './plugins.js';
|
|
6
|
+
const dynamicImport = new Function('specifier', 'return import(specifier)');
|
|
7
|
+
export async function initPlugin(rootPath, options = {}) {
|
|
8
|
+
const kind = options.kind ?? 'analyzer';
|
|
9
|
+
const name = options.name ?? (kind === 'analyzer' ? 'policy' : 'team-report');
|
|
10
|
+
const fileName = safePluginFileName(name);
|
|
11
|
+
const pluginDir = path.join(rootPath, PLUGIN_DIR);
|
|
12
|
+
const manifestPath = path.join(pluginDir, `${fileName}${PLUGIN_MANIFEST_EXT}`);
|
|
13
|
+
const modulePath = path.join(pluginDir, `${fileName}.mjs`);
|
|
14
|
+
await fs.mkdir(pluginDir, { recursive: true });
|
|
15
|
+
await assertDoesNotExist(manifestPath);
|
|
16
|
+
await assertDoesNotExist(modulePath);
|
|
17
|
+
const manifest = kind === 'analyzer'
|
|
18
|
+
? analyzerManifest(name, `./${fileName}.mjs`)
|
|
19
|
+
: reporterManifest(name, `./${fileName}.mjs`);
|
|
20
|
+
const moduleSource = kind === 'analyzer' ? analyzerTemplate(name) : reporterTemplate(name);
|
|
21
|
+
await fs.writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, { flag: 'wx' });
|
|
22
|
+
await fs.writeFile(modulePath, moduleSource, { flag: 'wx' });
|
|
23
|
+
return { manifestPath, modulePath };
|
|
24
|
+
}
|
|
25
|
+
export async function testPlugin(manifestPath, options = {}) {
|
|
26
|
+
const resolvedManifestPath = path.resolve(manifestPath);
|
|
27
|
+
const manifestResult = await readPluginManifestFile(resolvedManifestPath);
|
|
28
|
+
if (!manifestResult.ok) {
|
|
29
|
+
return failResult(resolvedManifestPath, {
|
|
30
|
+
code: manifestResult.diagnostic.code,
|
|
31
|
+
severity: 'error',
|
|
32
|
+
message: manifestResult.diagnostic.message,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
const manifest = manifestResult.manifest;
|
|
36
|
+
const modulePath = path.resolve(path.dirname(resolvedManifestPath), manifest.module);
|
|
37
|
+
let exportsObj;
|
|
38
|
+
try {
|
|
39
|
+
const mod = await importPluginModule(modulePath);
|
|
40
|
+
exportsObj = (mod.default ?? mod);
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
return failResult(resolvedManifestPath, {
|
|
44
|
+
code: 'module-load-error',
|
|
45
|
+
severity: 'error',
|
|
46
|
+
message: `plugin module failed to load: ${err instanceof Error ? err.message : String(err)}`,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return manifest.kind === 'analyzer'
|
|
50
|
+
? testAnalyzerPlugin(resolvedManifestPath, manifest, exportsObj, options)
|
|
51
|
+
: testReporterPlugin(resolvedManifestPath, manifest, exportsObj, options);
|
|
52
|
+
}
|
|
53
|
+
function analyzerManifest(name, modulePath) {
|
|
54
|
+
return {
|
|
55
|
+
schemaVersion: 1,
|
|
56
|
+
name,
|
|
57
|
+
kind: 'analyzer',
|
|
58
|
+
module: modulePath,
|
|
59
|
+
category: 'policy',
|
|
60
|
+
description: 'Example local policy analyzer.',
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function reporterManifest(name, modulePath) {
|
|
64
|
+
return {
|
|
65
|
+
schemaVersion: 1,
|
|
66
|
+
name,
|
|
67
|
+
kind: 'reporter',
|
|
68
|
+
module: modulePath,
|
|
69
|
+
commands: [...PLUGIN_REPORTER_COMMANDS],
|
|
70
|
+
description: 'Example local reporter.',
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function analyzerTemplate(name) {
|
|
74
|
+
return `import { readFile } from 'node:fs/promises';
|
|
75
|
+
|
|
76
|
+
export default {
|
|
77
|
+
async check(_rootPath, files) {
|
|
78
|
+
const issues = [];
|
|
79
|
+
for (const file of files) {
|
|
80
|
+
if (file.relativePath.startsWith('.projscan-plugins/')) continue;
|
|
81
|
+
let text = '';
|
|
82
|
+
try {
|
|
83
|
+
text = await readFile(file.absolutePath, 'utf-8');
|
|
84
|
+
} catch {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (!text.includes('PROJSCAN_PLUGIN_EXAMPLE')) continue;
|
|
88
|
+
issues.push({
|
|
89
|
+
id: 'example-marker',
|
|
90
|
+
title: '${escapeForSingleQuotedJs(name)} example marker found',
|
|
91
|
+
description: 'Remove PROJSCAN_PLUGIN_EXAMPLE before committing production code.',
|
|
92
|
+
severity: 'info',
|
|
93
|
+
category: 'policy',
|
|
94
|
+
fixAvailable: false,
|
|
95
|
+
locations: [{ file: file.relativePath, line: 1 }],
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return issues;
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
`;
|
|
102
|
+
}
|
|
103
|
+
function reporterTemplate(name) {
|
|
104
|
+
return `export default {
|
|
105
|
+
render({ command, payload }) {
|
|
106
|
+
const issueCount = Array.isArray(payload?.issues)
|
|
107
|
+
? payload.issues.length
|
|
108
|
+
: Array.isArray(payload?.ci?.issues)
|
|
109
|
+
? payload.ci.issues.length
|
|
110
|
+
: 0;
|
|
111
|
+
const score = payload?.health?.score ?? payload?.ci?.score ?? 'n/a';
|
|
112
|
+
return '${escapeForSingleQuotedJs(name)}:' + command + ': score=' + score + ', issues=' + issueCount;
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
`;
|
|
116
|
+
}
|
|
117
|
+
async function testAnalyzerPlugin(manifestPath, manifest, exportsObj, options) {
|
|
118
|
+
if (typeof exportsObj.check !== 'function') {
|
|
119
|
+
return failResult(manifestPath, {
|
|
120
|
+
code: 'invalid-analyzer-export',
|
|
121
|
+
severity: 'error',
|
|
122
|
+
message: `analyzer plugin "${manifest.name}" missing required export "check"`,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
const rootPath = options.fixtureRoot ?? path.dirname(path.dirname(manifestPath));
|
|
126
|
+
const scan = await scanRepository(rootPath);
|
|
127
|
+
let rawIssues;
|
|
128
|
+
try {
|
|
129
|
+
rawIssues = await exportsObj.check(rootPath, scan.files);
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
return failResult(manifestPath, {
|
|
133
|
+
code: 'analyzer-runtime-error',
|
|
134
|
+
severity: 'error',
|
|
135
|
+
message: `analyzer plugin "${manifest.name}" threw: ${err instanceof Error ? err.message : String(err)}`,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
if (!Array.isArray(rawIssues)) {
|
|
139
|
+
return failResult(manifestPath, {
|
|
140
|
+
code: 'invalid-analyzer-result',
|
|
141
|
+
severity: 'error',
|
|
142
|
+
message: `analyzer plugin "${manifest.name}" returned ${typeof rawIssues}; expected Issue[]`,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
const issues = rawIssues;
|
|
146
|
+
const malformed = issues.find((issue) => !isIssueShape(issue));
|
|
147
|
+
if (malformed) {
|
|
148
|
+
return failResult(manifestPath, {
|
|
149
|
+
code: 'invalid-analyzer-issue',
|
|
150
|
+
severity: 'error',
|
|
151
|
+
message: `analyzer plugin "${manifest.name}" returned a malformed issue`,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
schemaVersion: 1,
|
|
156
|
+
manifestPath,
|
|
157
|
+
ok: true,
|
|
158
|
+
diagnostics: [],
|
|
159
|
+
analyzer: { issues },
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
async function testReporterPlugin(manifestPath, manifest, exportsObj, options) {
|
|
163
|
+
if (typeof exportsObj.render !== 'function') {
|
|
164
|
+
return failResult(manifestPath, {
|
|
165
|
+
code: 'invalid-reporter-export',
|
|
166
|
+
severity: 'error',
|
|
167
|
+
message: `reporter plugin "${manifest.name}" missing required export "render"`,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
const rootPath = options.fixtureRoot ?? path.dirname(path.dirname(manifestPath));
|
|
171
|
+
const outputs = [];
|
|
172
|
+
for (const command of manifest.commands) {
|
|
173
|
+
const context = {
|
|
174
|
+
command,
|
|
175
|
+
rootPath,
|
|
176
|
+
manifest,
|
|
177
|
+
payload: sampleReporterPayload(command),
|
|
178
|
+
};
|
|
179
|
+
let text;
|
|
180
|
+
try {
|
|
181
|
+
text = await exportsObj.render(context);
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
return failResult(manifestPath, {
|
|
185
|
+
code: 'reporter-render-error',
|
|
186
|
+
severity: 'error',
|
|
187
|
+
message: `reporter plugin "${manifest.name}" threw for ${command}: ${err instanceof Error ? err.message : String(err)}`,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
if (typeof text !== 'string') {
|
|
191
|
+
return failResult(manifestPath, {
|
|
192
|
+
code: 'reporter-render-error',
|
|
193
|
+
severity: 'error',
|
|
194
|
+
message: `reporter plugin "${manifest.name}" returned ${typeof text}; expected string`,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
outputs.push({ command, text });
|
|
198
|
+
}
|
|
199
|
+
return {
|
|
200
|
+
schemaVersion: 1,
|
|
201
|
+
manifestPath,
|
|
202
|
+
ok: true,
|
|
203
|
+
diagnostics: [],
|
|
204
|
+
reporter: { outputs },
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
function sampleReporterPayload(command) {
|
|
208
|
+
switch (command) {
|
|
209
|
+
case 'ci':
|
|
210
|
+
return { ci: { score: 100, grade: 'A', issues: [] } };
|
|
211
|
+
case 'analyze':
|
|
212
|
+
return { projectName: 'fixture', issues: [] };
|
|
213
|
+
case 'doctor':
|
|
214
|
+
default:
|
|
215
|
+
return { health: { score: 100, grade: 'A', errors: 0, warnings: 0, infos: 0 }, issues: [] };
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
function failResult(manifestPath, diagnostic) {
|
|
219
|
+
return {
|
|
220
|
+
schemaVersion: 1,
|
|
221
|
+
manifestPath,
|
|
222
|
+
ok: false,
|
|
223
|
+
diagnostics: [diagnostic],
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
async function assertDoesNotExist(filePath) {
|
|
227
|
+
try {
|
|
228
|
+
await fs.access(filePath);
|
|
229
|
+
throw new Error(`${filePath} already exists`);
|
|
230
|
+
}
|
|
231
|
+
catch (err) {
|
|
232
|
+
if (err instanceof Error && err.message.includes('already exists'))
|
|
233
|
+
throw err;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
function safePluginFileName(name) {
|
|
237
|
+
const safe = name
|
|
238
|
+
.trim()
|
|
239
|
+
.toLowerCase()
|
|
240
|
+
.replace(/[^a-z0-9._-]+/g, '-')
|
|
241
|
+
.replace(/^-+|-+$/g, '');
|
|
242
|
+
return safe || 'plugin';
|
|
243
|
+
}
|
|
244
|
+
function isIssueShape(value) {
|
|
245
|
+
if (!value || typeof value !== 'object')
|
|
246
|
+
return false;
|
|
247
|
+
const issue = value;
|
|
248
|
+
return (typeof issue.id === 'string' &&
|
|
249
|
+
typeof issue.title === 'string' &&
|
|
250
|
+
typeof issue.description === 'string' &&
|
|
251
|
+
(issue.severity === 'info' || issue.severity === 'warning' || issue.severity === 'error') &&
|
|
252
|
+
typeof issue.category === 'string' &&
|
|
253
|
+
typeof issue.fixAvailable === 'boolean');
|
|
254
|
+
}
|
|
255
|
+
function importPluginModule(modulePath) {
|
|
256
|
+
return dynamicImport(pathToFileURL(modulePath).href).catch(async (err) => {
|
|
257
|
+
if (!(err instanceof TypeError) || !err.message.includes('dynamic import callback was not specified')) {
|
|
258
|
+
throw err;
|
|
259
|
+
}
|
|
260
|
+
return importPluginModuleFromSource(modulePath);
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
async function importPluginModuleFromSource(modulePath) {
|
|
264
|
+
const originalSource = await fs.readFile(modulePath, 'utf-8');
|
|
265
|
+
const { source, bindings } = stripSupportedImports(originalSource);
|
|
266
|
+
const defaultMatch = source.match(/^\s*export\s+default\s+([\s\S]*?)\s*;?\s*$/);
|
|
267
|
+
if (defaultMatch) {
|
|
268
|
+
const expression = defaultMatch[1].trim().replace(/;$/, '');
|
|
269
|
+
return {
|
|
270
|
+
default: new Function(...Object.keys(bindings), `return (${expression});`)(...Object.values(bindings)),
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
const names = [];
|
|
274
|
+
let transformed = source.replace(/\bexport\s+(async\s+function|function)\s+([A-Za-z_$][\w$]*)/g, (_m, kind, name) => {
|
|
275
|
+
names.push(String(name));
|
|
276
|
+
return `${kind} ${name}`;
|
|
277
|
+
});
|
|
278
|
+
transformed = transformed.replace(/\bexport\s+const\s+([A-Za-z_$][\w$]*)\s*=/g, (_m, name) => {
|
|
279
|
+
names.push(String(name));
|
|
280
|
+
return `const ${name} =`;
|
|
281
|
+
});
|
|
282
|
+
if (names.length === 0) {
|
|
283
|
+
throw new Error('unsupported module syntax in Vitest VM fallback');
|
|
284
|
+
}
|
|
285
|
+
return new Function(`${transformed}\nreturn { ${names.join(', ')} };`)();
|
|
286
|
+
}
|
|
287
|
+
function stripSupportedImports(source) {
|
|
288
|
+
const bindings = {};
|
|
289
|
+
const stripped = source.replace(/^\s*import\s+\{\s*readFile\s*\}\s+from\s+['"]node:fs\/promises['"];\s*/m, () => {
|
|
290
|
+
bindings.readFile = fs.readFile;
|
|
291
|
+
return '';
|
|
292
|
+
});
|
|
293
|
+
return { source: stripped, bindings };
|
|
294
|
+
}
|
|
295
|
+
function escapeForSingleQuotedJs(value) {
|
|
296
|
+
return value.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
297
|
+
}
|
|
298
|
+
//# sourceMappingURL=pluginDx.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pluginDx.js","sourceRoot":"","sources":["../../src/core/pluginDx.ts"],"names":[],"mappings":"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"}
|
package/dist/core/plugins.d.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import type { FileEntry, Issue } from '../types.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Stable local plugin API (2.0+).
|
|
4
4
|
*
|
|
5
|
-
* Gated behind PROJSCAN_PLUGINS_PREVIEW=1
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* disk — so a half-written plugin can't accidentally light up.
|
|
5
|
+
* Gated behind PROJSCAN_PLUGINS_PREVIEW=1 as an explicit local-code trust
|
|
6
|
+
* boundary. Without the env flag, `loadPlugins()` returns [] and projscan
|
|
7
|
+
* ignores manifests on disk, so a half-written plugin cannot accidentally
|
|
8
|
+
* affect a scan.
|
|
10
9
|
*
|
|
11
10
|
* Goal for 2.0: third parties write `.projscan-plugin.json` declaring an
|
|
12
11
|
* analyzer that produces Issue[], projscan dispatches to it during
|
package/dist/core/plugins.js
CHANGED
|
@@ -2,13 +2,12 @@ import fs from 'node:fs/promises';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { pathToFileURL } from 'node:url';
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Stable local plugin API (2.0+).
|
|
6
6
|
*
|
|
7
|
-
* Gated behind PROJSCAN_PLUGINS_PREVIEW=1
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* disk — so a half-written plugin can't accidentally light up.
|
|
7
|
+
* Gated behind PROJSCAN_PLUGINS_PREVIEW=1 as an explicit local-code trust
|
|
8
|
+
* boundary. Without the env flag, `loadPlugins()` returns [] and projscan
|
|
9
|
+
* ignores manifests on disk, so a half-written plugin cannot accidentally
|
|
10
|
+
* affect a scan.
|
|
12
11
|
*
|
|
13
12
|
* Goal for 2.0: third parties write `.projscan-plugin.json` declaring an
|
|
14
13
|
* analyzer that produces Issue[], projscan dispatches to it during
|
|
@@ -20,6 +19,8 @@ export const PLUGIN_PREVIEW_FLAG = 'PROJSCAN_PLUGINS_PREVIEW';
|
|
|
20
19
|
export const PLUGIN_SCHEMA_VERSION = 1;
|
|
21
20
|
export const PLUGIN_DIR = '.projscan-plugins';
|
|
22
21
|
export const PLUGIN_MANIFEST_EXT = '.projscan-plugin.json';
|
|
22
|
+
// Keep arbitrary plugin file URLs out of Vite/Vitest's static import transform.
|
|
23
|
+
const dynamicImport = new Function('specifier', 'return import(specifier)');
|
|
23
24
|
export const PLUGIN_REPORTER_COMMANDS = ['doctor', 'analyze', 'ci'];
|
|
24
25
|
export function pluginsEnabled() {
|
|
25
26
|
const v = process.env[PLUGIN_PREVIEW_FLAG];
|
|
@@ -116,10 +117,11 @@ export async function loadPlugins(rootPath) {
|
|
|
116
117
|
continue;
|
|
117
118
|
const modulePath = path.resolve(path.dirname(entry.manifestPath), entry.manifest.module);
|
|
118
119
|
try {
|
|
119
|
-
|
|
120
|
+
await assertPluginModuleReadable(entry.manifest.module, modulePath);
|
|
121
|
+
const mod = await importPluginModule(modulePath);
|
|
120
122
|
const exportsObj = (mod.default ?? mod);
|
|
121
123
|
if (typeof exportsObj.check !== 'function') {
|
|
122
|
-
process.stderr.write(`[projscan] plugin "${entry.manifest.name}" missing required export "check"; skipped.\n`);
|
|
124
|
+
process.stderr.write(`[projscan] plugin "${entry.manifest.name}" missing required export "check"; export default { check(rootPath, files) { ... } } or export a named check function. skipped.\n`);
|
|
123
125
|
continue;
|
|
124
126
|
}
|
|
125
127
|
loaded.push({
|
|
@@ -130,7 +132,8 @@ export async function loadPlugins(rootPath) {
|
|
|
130
132
|
});
|
|
131
133
|
}
|
|
132
134
|
catch (err) {
|
|
133
|
-
|
|
135
|
+
const detail = describePluginModuleLoadError(err, entry.manifest.module, modulePath, 'manifest');
|
|
136
|
+
process.stderr.write(`[projscan] plugin "${entry.manifest.name}" failed to load: ${detail.message}${detail.hint ? ` ${detail.hint}` : ''}. skipped.\n`);
|
|
134
137
|
}
|
|
135
138
|
}
|
|
136
139
|
return loaded;
|
|
@@ -185,13 +188,14 @@ export async function renderReporterPlugin(plugin, context) {
|
|
|
185
188
|
async function loadReporterPlugin(manifest, manifestPath) {
|
|
186
189
|
const modulePath = path.resolve(path.dirname(manifestPath), manifest.module);
|
|
187
190
|
try {
|
|
188
|
-
|
|
191
|
+
await assertPluginModuleReadable(manifest.module, modulePath);
|
|
192
|
+
const mod = await importPluginModule(modulePath);
|
|
189
193
|
const exportsObj = (mod.default ?? mod);
|
|
190
194
|
if (typeof exportsObj.render !== 'function') {
|
|
191
195
|
return pluginRuntimeFail({
|
|
192
196
|
code: 'invalid-reporter-export',
|
|
193
197
|
message: `reporter plugin "${manifest.name}" missing required export "render"`,
|
|
194
|
-
hint: '
|
|
198
|
+
hint: 'Use export default { render(context) { ... } } or export a named render function.',
|
|
195
199
|
});
|
|
196
200
|
}
|
|
197
201
|
return {
|
|
@@ -205,13 +209,95 @@ async function loadReporterPlugin(manifest, manifestPath) {
|
|
|
205
209
|
};
|
|
206
210
|
}
|
|
207
211
|
catch (err) {
|
|
212
|
+
const detail = describePluginModuleLoadError(err, manifest.module, modulePath, 'reporter manifest');
|
|
208
213
|
return pluginRuntimeFail({
|
|
209
214
|
code: 'reporter-load-error',
|
|
210
|
-
message: `reporter plugin "${manifest.name}" failed to load: ${
|
|
211
|
-
hint: 'Check the reporter module path and module syntax.',
|
|
215
|
+
message: `reporter plugin "${manifest.name}" failed to load: ${detail.message}`,
|
|
216
|
+
hint: detail.hint ?? 'Check the reporter module path and module syntax.',
|
|
212
217
|
});
|
|
213
218
|
}
|
|
214
219
|
}
|
|
220
|
+
class PluginModuleMissingError extends Error {
|
|
221
|
+
manifestModule;
|
|
222
|
+
modulePath;
|
|
223
|
+
constructor(manifestModule, modulePath) {
|
|
224
|
+
super(`module "${manifestModule}" was not found at ${modulePath}`);
|
|
225
|
+
this.manifestModule = manifestModule;
|
|
226
|
+
this.modulePath = modulePath;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
class PluginModuleReadError extends Error {
|
|
230
|
+
manifestModule;
|
|
231
|
+
modulePath;
|
|
232
|
+
constructor(manifestModule, modulePath, err) {
|
|
233
|
+
super(`module "${manifestModule}" could not be read at ${modulePath}: ${formatError(err)}`);
|
|
234
|
+
this.manifestModule = manifestModule;
|
|
235
|
+
this.modulePath = modulePath;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
async function assertPluginModuleReadable(manifestModule, modulePath) {
|
|
239
|
+
try {
|
|
240
|
+
await fs.access(modulePath);
|
|
241
|
+
}
|
|
242
|
+
catch (err) {
|
|
243
|
+
const code = typeof err === 'object' && err !== null && 'code' in err ? String(err.code) : '';
|
|
244
|
+
if (code === 'ENOENT')
|
|
245
|
+
throw new PluginModuleMissingError(manifestModule, modulePath);
|
|
246
|
+
throw new PluginModuleReadError(manifestModule, modulePath, err);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function describePluginModuleLoadError(err, manifestModule, modulePath, manifestLabel) {
|
|
250
|
+
if (err instanceof PluginModuleMissingError) {
|
|
251
|
+
return {
|
|
252
|
+
message: err.message,
|
|
253
|
+
hint: `Check the ${manifestLabel} "module" path.`,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
if (err instanceof PluginModuleReadError) {
|
|
257
|
+
return {
|
|
258
|
+
message: err.message,
|
|
259
|
+
hint: `Check file permissions for the ${manifestLabel} "module" path.`,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
if (err instanceof SyntaxError) {
|
|
263
|
+
return {
|
|
264
|
+
message: `syntax error in module "${manifestModule}": ${formatError(err)}`,
|
|
265
|
+
hint: `Run node "${modulePath}" to reproduce the syntax error.`,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
return { message: formatError(err) };
|
|
269
|
+
}
|
|
270
|
+
function importPluginModule(modulePath) {
|
|
271
|
+
return dynamicImport(pathToFileURL(modulePath).href).catch(async (err) => {
|
|
272
|
+
if (!isMissingDynamicImportCallback(err))
|
|
273
|
+
throw err;
|
|
274
|
+
return importPluginModuleFromSource(modulePath);
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
function isMissingDynamicImportCallback(err) {
|
|
278
|
+
return err instanceof TypeError && err.message.includes('dynamic import callback was not specified');
|
|
279
|
+
}
|
|
280
|
+
async function importPluginModuleFromSource(modulePath) {
|
|
281
|
+
const source = await fs.readFile(modulePath, 'utf-8');
|
|
282
|
+
const defaultMatch = source.match(/^\s*export\s+default\s+([\s\S]*?)\s*;?\s*$/);
|
|
283
|
+
if (defaultMatch) {
|
|
284
|
+
const expression = defaultMatch[1].trim().replace(/;$/, '');
|
|
285
|
+
return { default: new Function(`return (${expression});`)() };
|
|
286
|
+
}
|
|
287
|
+
const names = [];
|
|
288
|
+
let transformed = source.replace(/\bexport\s+(async\s+function|function)\s+([A-Za-z_$][\w$]*)/g, (_m, kind, name) => {
|
|
289
|
+
names.push(String(name));
|
|
290
|
+
return `${kind} ${name}`;
|
|
291
|
+
});
|
|
292
|
+
transformed = transformed.replace(/\bexport\s+const\s+([A-Za-z_$][\w$]*)\s*=/g, (_m, name) => {
|
|
293
|
+
names.push(String(name));
|
|
294
|
+
return `const ${name} =`;
|
|
295
|
+
});
|
|
296
|
+
if (names.length === 0) {
|
|
297
|
+
throw new Error('unsupported module syntax in Vitest VM fallback');
|
|
298
|
+
}
|
|
299
|
+
return new Function(`${transformed}\nreturn { ${names.join(', ')} };`)();
|
|
300
|
+
}
|
|
215
301
|
/**
|
|
216
302
|
* Run every loaded analyzer plugin against `files`. Issues that don't pass
|
|
217
303
|
* a tight shape check are dropped so a malformed plugin can't poison the
|