@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,354 @@
|
|
|
1
|
+
// Configuration file generator with smart comments
|
|
2
|
+
|
|
3
|
+
import type { FieldAnalysis, CodebaseAnalysis, TypeInfo } from "../types";
|
|
4
|
+
|
|
5
|
+
export class ConfigGenerator {
|
|
6
|
+
private lines: string[] = [];
|
|
7
|
+
private indent = 0;
|
|
8
|
+
|
|
9
|
+
generate(analysis: CodebaseAnalysis): string {
|
|
10
|
+
this.lines = [];
|
|
11
|
+
this.indent = 0;
|
|
12
|
+
|
|
13
|
+
this.addHeader();
|
|
14
|
+
this.addImports();
|
|
15
|
+
this.addExport();
|
|
16
|
+
this.addStateConfig(analysis.fields);
|
|
17
|
+
this.addMessagesConfig();
|
|
18
|
+
this.addBehaviorConfig();
|
|
19
|
+
this.closeExport();
|
|
20
|
+
|
|
21
|
+
return this.lines.join("\n");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
private addHeader(): void {
|
|
25
|
+
this.line("// ═══════════════════════════════════════════════════════════════");
|
|
26
|
+
this.line("// Verification Configuration");
|
|
27
|
+
this.line("// ═══════════════════════════════════════════════════════════════");
|
|
28
|
+
this.line("//");
|
|
29
|
+
this.line("// This file configures TLA+ verification for your extension.");
|
|
30
|
+
this.line("// Some values are auto-configured, others need your input.");
|
|
31
|
+
this.line("//");
|
|
32
|
+
this.line("// Look for:");
|
|
33
|
+
this.line("// • /* CONFIGURE */ - Replace with your value");
|
|
34
|
+
this.line("// • /* REVIEW */ - Check the auto-generated value");
|
|
35
|
+
this.line("// • null - Must be replaced with a concrete value");
|
|
36
|
+
this.line("//");
|
|
37
|
+
this.line("// Run 'bun verify' to check for incomplete configuration.");
|
|
38
|
+
this.line("// Run 'bun verify --setup' for interactive help.");
|
|
39
|
+
this.line("//");
|
|
40
|
+
this.line("");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private addImports(): void {
|
|
44
|
+
this.line("import { defineVerification } from '@fairfox/polly/verify'");
|
|
45
|
+
this.line("");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private addExport(): void {
|
|
49
|
+
this.line("export default defineVerification({");
|
|
50
|
+
this.indent++;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private closeExport(): void {
|
|
54
|
+
this.indent--;
|
|
55
|
+
this.line("})");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private addStateConfig(fields: FieldAnalysis[]): void {
|
|
59
|
+
this.line("state: {");
|
|
60
|
+
this.indent++;
|
|
61
|
+
|
|
62
|
+
for (let i = 0; i < fields.length; i++) {
|
|
63
|
+
const field = fields[i];
|
|
64
|
+
|
|
65
|
+
// Add blank line between fields
|
|
66
|
+
if (i > 0) {
|
|
67
|
+
this.line("");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
this.addFieldConfig(field);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
this.indent--;
|
|
74
|
+
this.line("},");
|
|
75
|
+
this.line("");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private addFieldConfig(field: FieldAnalysis): void {
|
|
79
|
+
// Generate comment block
|
|
80
|
+
this.addFieldComment(field);
|
|
81
|
+
|
|
82
|
+
// Generate configuration line
|
|
83
|
+
const config = this.generateFieldConfig(field);
|
|
84
|
+
this.line(`"${field.path}": ${config},`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private addFieldComment(field: FieldAnalysis): void {
|
|
88
|
+
const separator = "─".repeat(60);
|
|
89
|
+
|
|
90
|
+
// Header
|
|
91
|
+
this.line(`// ${separator}`);
|
|
92
|
+
this.line(`// ${field.path}: ${this.formatTypeName(field.type)}`);
|
|
93
|
+
this.line(`// ${separator}`);
|
|
94
|
+
|
|
95
|
+
// High confidence: auto-configured
|
|
96
|
+
if (field.confidence === "high") {
|
|
97
|
+
this.line("// ✓ Auto-configured from code analysis");
|
|
98
|
+
if (field.evidence.length > 0) {
|
|
99
|
+
for (const evidence of field.evidence) {
|
|
100
|
+
this.line(`// ${evidence}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
this.line("//");
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Medium confidence: needs review
|
|
108
|
+
if (field.confidence === "medium") {
|
|
109
|
+
this.line("// ⚠️ Please review this auto-generated value");
|
|
110
|
+
if (field.evidence.length > 0) {
|
|
111
|
+
for (const evidence of field.evidence) {
|
|
112
|
+
this.line(`// Found: ${evidence}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
this.line("//");
|
|
116
|
+
this.line("// REVIEW: Adjust if needed");
|
|
117
|
+
this.line("//");
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Low confidence: manual configuration required
|
|
122
|
+
this.line("// ⚠️ Manual configuration required");
|
|
123
|
+
this.line("//");
|
|
124
|
+
|
|
125
|
+
// Type-specific guidance
|
|
126
|
+
this.addTypeGuidance(field);
|
|
127
|
+
|
|
128
|
+
// Suggestions
|
|
129
|
+
if (field.suggestions.length > 0) {
|
|
130
|
+
this.line("//");
|
|
131
|
+
for (const suggestion of field.suggestions) {
|
|
132
|
+
this.line(`// ${suggestion}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
this.line("//");
|
|
137
|
+
this.line("// CONFIGURE: Fill in the value below");
|
|
138
|
+
this.line("//");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
private addTypeGuidance(field: FieldAnalysis): void {
|
|
142
|
+
switch (field.type.kind) {
|
|
143
|
+
case "array":
|
|
144
|
+
this.line("// This array has no bounds in your code. Choose a maximum");
|
|
145
|
+
this.line("// length for verification. Tradeoffs:");
|
|
146
|
+
this.line("// • Small (3-5): Fast, catches basic bugs");
|
|
147
|
+
this.line("// • Medium (10-15): Balanced, catches most bugs");
|
|
148
|
+
this.line("// • Large (20+): Thorough, much slower");
|
|
149
|
+
break;
|
|
150
|
+
|
|
151
|
+
case "string":
|
|
152
|
+
this.line("// Strings need concrete values for precise verification.");
|
|
153
|
+
this.line("// Provide 2-3 representative values from your app.");
|
|
154
|
+
if (field.type.nullable) {
|
|
155
|
+
this.line("//");
|
|
156
|
+
this.line("// Note: This field is nullable (can be null)");
|
|
157
|
+
}
|
|
158
|
+
this.line("//");
|
|
159
|
+
this.line("// Examples:");
|
|
160
|
+
this.line('// ["user_abc123", "user_xyz789", "guest_000"]');
|
|
161
|
+
this.line('// ["active", "inactive", "pending"]');
|
|
162
|
+
this.line("//");
|
|
163
|
+
this.line("// Alternative: Use abstract verification (less precise, faster)");
|
|
164
|
+
this.line("// { abstract: true }");
|
|
165
|
+
break;
|
|
166
|
+
|
|
167
|
+
case "number":
|
|
168
|
+
this.line("// Numbers need a range. Choose min and max values based on");
|
|
169
|
+
this.line("// realistic bounds in your application.");
|
|
170
|
+
if (field.type.nullable) {
|
|
171
|
+
this.line("//");
|
|
172
|
+
this.line("// Note: This field is nullable (can be null)");
|
|
173
|
+
}
|
|
174
|
+
this.line("//");
|
|
175
|
+
this.line("// Examples:");
|
|
176
|
+
this.line("// { min: 0, max: 100 } // Counter");
|
|
177
|
+
this.line("// { min: 0, max: 999999 } // Timestamp");
|
|
178
|
+
break;
|
|
179
|
+
|
|
180
|
+
case "map":
|
|
181
|
+
case "set":
|
|
182
|
+
this.line(`// ${field.type.kind} needs a maximum size. How many entries`);
|
|
183
|
+
this.line("// do you need to model to catch bugs?");
|
|
184
|
+
this.line("//");
|
|
185
|
+
this.line("// Recommended: 3-5 for most cases");
|
|
186
|
+
break;
|
|
187
|
+
|
|
188
|
+
case "object":
|
|
189
|
+
this.line("// Complex nested object. Configure each field separately.");
|
|
190
|
+
break;
|
|
191
|
+
|
|
192
|
+
default:
|
|
193
|
+
this.line(`// ${field.type.kind} type requires configuration.`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
private generateFieldConfig(field: FieldAnalysis): string {
|
|
198
|
+
switch (field.type.kind) {
|
|
199
|
+
case "boolean":
|
|
200
|
+
return "{ type: 'boolean' }";
|
|
201
|
+
|
|
202
|
+
case "enum":
|
|
203
|
+
if (field.type.enumValues) {
|
|
204
|
+
const values = field.type.enumValues.map((v) => `"${v}"`).join(", ");
|
|
205
|
+
return `{ type: "enum", values: [${values}] }`;
|
|
206
|
+
}
|
|
207
|
+
return "{ type: 'enum', values: /* CONFIGURE */ null }";
|
|
208
|
+
|
|
209
|
+
case "array":
|
|
210
|
+
if (field.bounds?.maxLength !== undefined && field.bounds.maxLength !== null) {
|
|
211
|
+
if (field.confidence === "medium") {
|
|
212
|
+
return `{ maxLength: /* REVIEW */ ${field.bounds.maxLength} }`;
|
|
213
|
+
}
|
|
214
|
+
return `{ maxLength: ${field.bounds.maxLength} }`;
|
|
215
|
+
}
|
|
216
|
+
return "{ maxLength: /* CONFIGURE */ null }";
|
|
217
|
+
|
|
218
|
+
case "number":
|
|
219
|
+
if (field.bounds?.min !== undefined && field.bounds?.max !== undefined) {
|
|
220
|
+
const minStr = field.bounds.min !== null ? field.bounds.min : "/* CONFIGURE */";
|
|
221
|
+
const maxStr = field.bounds.max !== null ? field.bounds.max : "/* CONFIGURE */";
|
|
222
|
+
|
|
223
|
+
if (field.confidence === "high") {
|
|
224
|
+
return `{ min: ${minStr}, max: ${maxStr} }`;
|
|
225
|
+
}
|
|
226
|
+
return `{ min: /* REVIEW */ ${minStr}, max: /* REVIEW */ ${maxStr} }`;
|
|
227
|
+
}
|
|
228
|
+
return "{ min: /* CONFIGURE */ null, max: /* CONFIGURE */ null }";
|
|
229
|
+
|
|
230
|
+
case "string":
|
|
231
|
+
return "{ values: /* CONFIGURE */ null }";
|
|
232
|
+
|
|
233
|
+
case "map":
|
|
234
|
+
case "set":
|
|
235
|
+
return "{ maxSize: /* CONFIGURE */ null }";
|
|
236
|
+
|
|
237
|
+
default:
|
|
238
|
+
return "{ /* CONFIGURE */ }";
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
private addMessagesConfig(): void {
|
|
243
|
+
this.line("messages: {");
|
|
244
|
+
this.indent++;
|
|
245
|
+
|
|
246
|
+
this.line("// Maximum messages in flight simultaneously across all contexts.");
|
|
247
|
+
this.line("// Higher = more realistic concurrency, but exponentially slower.");
|
|
248
|
+
this.line("//");
|
|
249
|
+
this.line("// Recommended values:");
|
|
250
|
+
this.line("// • 2-3: Fast verification (< 10 seconds)");
|
|
251
|
+
this.line("// • 4-6: Balanced (10-60 seconds)");
|
|
252
|
+
this.line("// • 8+: Thorough but slow (minutes)");
|
|
253
|
+
this.line("//");
|
|
254
|
+
this.line("// WARNING: State space grows exponentially! Start small.");
|
|
255
|
+
this.line("maxInFlight: 3,");
|
|
256
|
+
this.line("");
|
|
257
|
+
this.line("// Maximum tab IDs to model (content scripts are per-tab).");
|
|
258
|
+
this.line("//");
|
|
259
|
+
this.line("// Recommended:");
|
|
260
|
+
this.line("// • 0-1: Most extensions (single tab or tab-agnostic)");
|
|
261
|
+
this.line("// • 2-3: Multi-tab coordination");
|
|
262
|
+
this.line("//");
|
|
263
|
+
this.line("// Start with 0 or 1 for faster verification.");
|
|
264
|
+
this.line("maxTabs: 1,");
|
|
265
|
+
|
|
266
|
+
this.indent--;
|
|
267
|
+
this.line("},");
|
|
268
|
+
this.line("");
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
private addBehaviorConfig(): void {
|
|
272
|
+
this.line("// Verification behavior");
|
|
273
|
+
this.line("// ─────────────────────");
|
|
274
|
+
this.line("//");
|
|
275
|
+
this.line("// onBuild: What to do during development builds");
|
|
276
|
+
this.line("// • 'warn' - Show warnings but don't fail (recommended)");
|
|
277
|
+
this.line("// • 'error' - Fail the build on violations");
|
|
278
|
+
this.line("// • 'off' - Skip verification");
|
|
279
|
+
this.line("//");
|
|
280
|
+
this.line("onBuild: 'warn',");
|
|
281
|
+
this.line("");
|
|
282
|
+
this.line("// onRelease: What to do during production builds");
|
|
283
|
+
this.line("// • 'error' - Fail the build on violations (recommended)");
|
|
284
|
+
this.line("// • 'warn' - Show warnings but don't fail");
|
|
285
|
+
this.line("// • 'off' - Skip verification");
|
|
286
|
+
this.line("//");
|
|
287
|
+
this.line("onRelease: 'error',");
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
private formatTypeName(type: TypeInfo): string {
|
|
291
|
+
let typeName: string;
|
|
292
|
+
|
|
293
|
+
switch (type.kind) {
|
|
294
|
+
case "boolean":
|
|
295
|
+
typeName = "boolean";
|
|
296
|
+
break;
|
|
297
|
+
case "string":
|
|
298
|
+
typeName = "string";
|
|
299
|
+
break;
|
|
300
|
+
case "number":
|
|
301
|
+
typeName = "number";
|
|
302
|
+
break;
|
|
303
|
+
case "enum":
|
|
304
|
+
if (type.enumValues) {
|
|
305
|
+
typeName = type.enumValues.map((v) => `"${v}"`).join(" | ");
|
|
306
|
+
} else {
|
|
307
|
+
typeName = "enum";
|
|
308
|
+
}
|
|
309
|
+
break;
|
|
310
|
+
case "array":
|
|
311
|
+
if (type.elementType) {
|
|
312
|
+
typeName = `${this.formatTypeName(type.elementType)}[]`;
|
|
313
|
+
} else {
|
|
314
|
+
typeName = "array";
|
|
315
|
+
}
|
|
316
|
+
break;
|
|
317
|
+
case "object":
|
|
318
|
+
typeName = "object";
|
|
319
|
+
break;
|
|
320
|
+
case "map":
|
|
321
|
+
typeName = "Map";
|
|
322
|
+
break;
|
|
323
|
+
case "set":
|
|
324
|
+
typeName = "Set";
|
|
325
|
+
break;
|
|
326
|
+
case "null":
|
|
327
|
+
typeName = "null";
|
|
328
|
+
break;
|
|
329
|
+
default:
|
|
330
|
+
typeName = "unknown";
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Append " | null" if type is nullable
|
|
334
|
+
if (type.nullable && type.kind !== "null") {
|
|
335
|
+
typeName += " | null";
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return typeName;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
private line(content: string): void {
|
|
342
|
+
if (content === "") {
|
|
343
|
+
this.lines.push("");
|
|
344
|
+
} else {
|
|
345
|
+
const indentation = " ".repeat(this.indent);
|
|
346
|
+
this.lines.push(indentation + content);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export function generateConfig(analysis: CodebaseAnalysis): string {
|
|
352
|
+
const generator = new ConfigGenerator();
|
|
353
|
+
return generator.generate(analysis);
|
|
354
|
+
}
|