@fairfox/polly 0.1.1 → 0.1.2
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/cli/polly.ts +9 -3
- package/package.json +2 -2
- package/vendor/analysis/src/extract/adr.ts +212 -0
- package/vendor/analysis/src/extract/architecture.ts +160 -0
- package/vendor/analysis/src/extract/contexts.ts +298 -0
- package/vendor/analysis/src/extract/flows.ts +309 -0
- package/vendor/analysis/src/extract/handlers.ts +321 -0
- package/vendor/analysis/src/extract/index.ts +9 -0
- package/vendor/analysis/src/extract/integrations.ts +329 -0
- package/vendor/analysis/src/extract/manifest.ts +298 -0
- package/vendor/analysis/src/extract/types.ts +389 -0
- package/vendor/analysis/src/index.ts +7 -0
- package/vendor/analysis/src/types/adr.ts +53 -0
- package/vendor/analysis/src/types/architecture.ts +245 -0
- package/vendor/analysis/src/types/core.ts +210 -0
- package/vendor/analysis/src/types/index.ts +18 -0
- package/vendor/verify/src/adapters/base.ts +164 -0
- package/vendor/verify/src/adapters/detection.ts +281 -0
- package/vendor/verify/src/adapters/event-bus/index.ts +480 -0
- package/vendor/verify/src/adapters/web-extension/index.ts +508 -0
- package/vendor/verify/src/adapters/websocket/index.ts +486 -0
- package/vendor/verify/src/cli.ts +430 -0
- package/vendor/verify/src/codegen/config.ts +354 -0
- package/vendor/verify/src/codegen/tla.ts +719 -0
- package/vendor/verify/src/config/parser.ts +303 -0
- package/vendor/verify/src/config/types.ts +113 -0
- package/vendor/verify/src/core/model.ts +267 -0
- package/vendor/verify/src/core/primitives.ts +106 -0
- package/vendor/verify/src/extract/handlers.ts +2 -0
- package/vendor/verify/src/extract/types.ts +2 -0
- package/vendor/verify/src/index.ts +150 -0
- package/vendor/verify/src/primitives/index.ts +102 -0
- package/vendor/verify/src/runner/docker.ts +283 -0
- package/vendor/verify/src/types.ts +51 -0
- package/vendor/visualize/src/cli.ts +365 -0
- package/vendor/visualize/src/codegen/structurizr.ts +770 -0
- package/vendor/visualize/src/index.ts +13 -0
- package/vendor/visualize/src/runner/export.ts +235 -0
- package/vendor/visualize/src/viewer/server.ts +485 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════
|
|
2
|
+
// Adapter Auto-Detection
|
|
3
|
+
// ═══════════════════════════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// Automatically detects which adapter to use based on project structure,
|
|
6
|
+
// dependencies, and code patterns.
|
|
7
|
+
|
|
8
|
+
import { Project, type SourceFile } from "ts-morph";
|
|
9
|
+
import type { RoutingAdapter } from "./base";
|
|
10
|
+
import { WebExtensionAdapter, type WebExtensionAdapterConfig } from "./web-extension";
|
|
11
|
+
import { EventBusAdapter, type EventBusAdapterConfig } from "./event-bus";
|
|
12
|
+
|
|
13
|
+
// ─────────────────────────────────────────────────────────────────
|
|
14
|
+
// Detection Result
|
|
15
|
+
// ─────────────────────────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
export interface AdapterDetectionResult {
|
|
18
|
+
/** The recommended adapter type */
|
|
19
|
+
adapterType: "web-extension" | "event-bus" | "worker" | "unknown";
|
|
20
|
+
|
|
21
|
+
/** Confidence level (0-100) */
|
|
22
|
+
confidence: number;
|
|
23
|
+
|
|
24
|
+
/** Evidence supporting this detection */
|
|
25
|
+
evidence: string[];
|
|
26
|
+
|
|
27
|
+
/** Suggested adapter configuration */
|
|
28
|
+
suggestedAdapter?: RoutingAdapter;
|
|
29
|
+
|
|
30
|
+
/** Alternative adapters that might also work */
|
|
31
|
+
alternatives?: Array<{
|
|
32
|
+
adapterType: string;
|
|
33
|
+
confidence: number;
|
|
34
|
+
evidence: string[];
|
|
35
|
+
}>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ─────────────────────────────────────────────────────────────────
|
|
39
|
+
// Adapter Detector
|
|
40
|
+
// ─────────────────────────────────────────────────────────────────
|
|
41
|
+
|
|
42
|
+
export class AdapterDetector {
|
|
43
|
+
private project: Project;
|
|
44
|
+
|
|
45
|
+
constructor(tsConfigPath: string) {
|
|
46
|
+
this.project = new Project({
|
|
47
|
+
tsConfigFilePath: tsConfigPath,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Detect the most appropriate adapter for this project
|
|
53
|
+
*/
|
|
54
|
+
detect(): AdapterDetectionResult {
|
|
55
|
+
const sourceFiles = this.project.getSourceFiles();
|
|
56
|
+
|
|
57
|
+
// Run all detection heuristics
|
|
58
|
+
const webExtensionScore = this.detectWebExtension(sourceFiles);
|
|
59
|
+
const eventBusScore = this.detectEventBus(sourceFiles);
|
|
60
|
+
const workerScore = this.detectWorker(sourceFiles);
|
|
61
|
+
|
|
62
|
+
// Determine the best match
|
|
63
|
+
const scores = [
|
|
64
|
+
{ type: "web-extension" as const, ...webExtensionScore },
|
|
65
|
+
{ type: "event-bus" as const, ...eventBusScore },
|
|
66
|
+
{ type: "worker" as const, ...workerScore },
|
|
67
|
+
].sort((a, b) => b.confidence - a.confidence);
|
|
68
|
+
|
|
69
|
+
const best = scores[0]!;
|
|
70
|
+
const alternatives = scores.slice(1).filter((s) => s.confidence > 20);
|
|
71
|
+
|
|
72
|
+
// Create suggested adapter for the best match
|
|
73
|
+
let suggestedAdapter: RoutingAdapter | undefined;
|
|
74
|
+
if (best.confidence > 50) {
|
|
75
|
+
if (best.type === "web-extension") {
|
|
76
|
+
suggestedAdapter = new WebExtensionAdapter({
|
|
77
|
+
tsConfigPath:
|
|
78
|
+
(this.project.getCompilerOptions().configFilePath as string) || "tsconfig.json",
|
|
79
|
+
maxInFlight: 6,
|
|
80
|
+
maxTabs: 2,
|
|
81
|
+
});
|
|
82
|
+
} else if (best.type === "event-bus") {
|
|
83
|
+
suggestedAdapter = new EventBusAdapter({
|
|
84
|
+
tsConfigPath:
|
|
85
|
+
(this.project.getCompilerOptions().configFilePath as string) || "tsconfig.json",
|
|
86
|
+
maxInFlight: 5,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
adapterType: best.confidence > 30 ? best.type : "unknown",
|
|
93
|
+
confidence: best.confidence,
|
|
94
|
+
evidence: best.evidence,
|
|
95
|
+
suggestedAdapter,
|
|
96
|
+
alternatives: alternatives.map((a) => ({
|
|
97
|
+
adapterType: a.type,
|
|
98
|
+
confidence: a.confidence,
|
|
99
|
+
evidence: a.evidence,
|
|
100
|
+
})),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ─────────────────────────────────────────────────────────────────
|
|
105
|
+
// Detection Heuristics
|
|
106
|
+
// ─────────────────────────────────────────────────────────────────
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Detect web extension patterns
|
|
110
|
+
*/
|
|
111
|
+
private detectWebExtension(files: SourceFile[]): { confidence: number; evidence: string[] } {
|
|
112
|
+
let confidence = 0;
|
|
113
|
+
const evidence: string[] = [];
|
|
114
|
+
|
|
115
|
+
// Check for manifest.json
|
|
116
|
+
const hasManifest = files.some((f) => f.getFilePath().includes("manifest.json"));
|
|
117
|
+
if (hasManifest) {
|
|
118
|
+
confidence += 30;
|
|
119
|
+
evidence.push("Found manifest.json");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Check for chrome API imports
|
|
123
|
+
let chromeApiCount = 0;
|
|
124
|
+
for (const file of files) {
|
|
125
|
+
const text = file.getFullText();
|
|
126
|
+
if (text.includes("chrome.runtime") || text.includes("chrome.tabs")) {
|
|
127
|
+
chromeApiCount++;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (chromeApiCount > 0) {
|
|
131
|
+
confidence += Math.min(30, chromeApiCount * 10);
|
|
132
|
+
evidence.push(`Found ${chromeApiCount} file(s) using chrome.* APIs`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Check for extension directories
|
|
136
|
+
const hasBackground = files.some((f) => f.getFilePath().includes("/background/"));
|
|
137
|
+
const hasContent = files.some((f) => f.getFilePath().includes("/content/"));
|
|
138
|
+
const hasPopup = files.some((f) => f.getFilePath().includes("/popup/"));
|
|
139
|
+
|
|
140
|
+
const contextCount = [hasBackground, hasContent, hasPopup].filter(Boolean).length;
|
|
141
|
+
if (contextCount > 0) {
|
|
142
|
+
confidence += contextCount * 15;
|
|
143
|
+
evidence.push(`Found ${contextCount} extension context directories`);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Check for MessageBus usage
|
|
147
|
+
let messageBusCount = 0;
|
|
148
|
+
for (const file of files) {
|
|
149
|
+
const text = file.getFullText();
|
|
150
|
+
if (text.includes("MessageBus") || text.includes("getMessageBus")) {
|
|
151
|
+
messageBusCount++;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (messageBusCount > 0) {
|
|
155
|
+
confidence += Math.min(20, messageBusCount * 5);
|
|
156
|
+
evidence.push(`Found ${messageBusCount} file(s) using MessageBus`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return { confidence: Math.min(100, confidence), evidence };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Detect event bus patterns
|
|
164
|
+
*/
|
|
165
|
+
private detectEventBus(files: SourceFile[]): { confidence: number; evidence: string[] } {
|
|
166
|
+
let confidence = 0;
|
|
167
|
+
const evidence: string[] = [];
|
|
168
|
+
|
|
169
|
+
// Check for EventEmitter imports
|
|
170
|
+
let eventEmitterImports = 0;
|
|
171
|
+
for (const file of files) {
|
|
172
|
+
const imports = file.getImportDeclarations();
|
|
173
|
+
for (const imp of imports) {
|
|
174
|
+
const module = imp.getModuleSpecifierValue();
|
|
175
|
+
if (module === "events" || module === "eventemitter3" || module === "mitt") {
|
|
176
|
+
eventEmitterImports++;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (eventEmitterImports > 0) {
|
|
181
|
+
confidence += Math.min(40, eventEmitterImports * 15);
|
|
182
|
+
evidence.push(`Found ${eventEmitterImports} EventEmitter import(s)`);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Check for emitter.on() pattern
|
|
186
|
+
let emitterOnCount = 0;
|
|
187
|
+
for (const file of files) {
|
|
188
|
+
const text = file.getFullText();
|
|
189
|
+
const matches = text.match(/\.on\s*\(\s*['"`]/g);
|
|
190
|
+
if (matches) {
|
|
191
|
+
emitterOnCount += matches.length;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (emitterOnCount > 0) {
|
|
195
|
+
confidence += Math.min(30, emitterOnCount * 5);
|
|
196
|
+
evidence.push(`Found ${emitterOnCount} .on() call(s)`);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Check for emitter.emit() pattern
|
|
200
|
+
let emitterEmitCount = 0;
|
|
201
|
+
for (const file of files) {
|
|
202
|
+
const text = file.getFullText();
|
|
203
|
+
const matches = text.match(/\.emit\s*\(\s*['"`]/g);
|
|
204
|
+
if (matches) {
|
|
205
|
+
emitterEmitCount += matches.length;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (emitterEmitCount > 0) {
|
|
209
|
+
confidence += Math.min(30, emitterEmitCount * 3);
|
|
210
|
+
evidence.push(`Found ${emitterEmitCount} .emit() call(s)`);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Penalty if chrome APIs are present (likely not pure event bus)
|
|
214
|
+
let chromeApiCount = 0;
|
|
215
|
+
for (const file of files) {
|
|
216
|
+
if (file.getFullText().includes("chrome.runtime")) {
|
|
217
|
+
chromeApiCount++;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (chromeApiCount > 5) {
|
|
221
|
+
confidence = Math.max(0, confidence - 20);
|
|
222
|
+
evidence.push("Note: Also found Chrome APIs (might be extension)");
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return { confidence: Math.min(100, confidence), evidence };
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Detect web worker patterns
|
|
230
|
+
*/
|
|
231
|
+
private detectWorker(files: SourceFile[]): { confidence: number; evidence: string[] } {
|
|
232
|
+
let confidence = 0;
|
|
233
|
+
const evidence: string[] = [];
|
|
234
|
+
|
|
235
|
+
// Check for Worker usage
|
|
236
|
+
let workerCount = 0;
|
|
237
|
+
for (const file of files) {
|
|
238
|
+
const text = file.getFullText();
|
|
239
|
+
if (text.includes("new Worker(") || text.includes("new SharedWorker(")) {
|
|
240
|
+
workerCount++;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (workerCount > 0) {
|
|
244
|
+
confidence += Math.min(40, workerCount * 20);
|
|
245
|
+
evidence.push(`Found ${workerCount} Worker instantiation(s)`);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Check for postMessage usage
|
|
249
|
+
let postMessageCount = 0;
|
|
250
|
+
for (const file of files) {
|
|
251
|
+
const text = file.getFullText();
|
|
252
|
+
const matches = text.match(/\.postMessage\s*\(/g);
|
|
253
|
+
if (matches) {
|
|
254
|
+
postMessageCount += matches.length;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (postMessageCount > 0) {
|
|
258
|
+
confidence += Math.min(30, postMessageCount * 5);
|
|
259
|
+
evidence.push(`Found ${postMessageCount} .postMessage() call(s)`);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Check for worker directories
|
|
263
|
+
const hasWorkerDir = files.some(
|
|
264
|
+
(f) => f.getFilePath().includes("/worker/") || f.getFilePath().includes("/workers/")
|
|
265
|
+
);
|
|
266
|
+
if (hasWorkerDir) {
|
|
267
|
+
confidence += 20;
|
|
268
|
+
evidence.push("Found worker directory");
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return { confidence: Math.min(100, confidence), evidence };
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Detect the most appropriate adapter for a project
|
|
277
|
+
*/
|
|
278
|
+
export function detectAdapter(tsConfigPath: string): AdapterDetectionResult {
|
|
279
|
+
const detector = new AdapterDetector(tsConfigPath);
|
|
280
|
+
return detector.detect();
|
|
281
|
+
}
|