@fairfox/polly 0.5.2 → 0.6.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/dist/cli/polly.js +9 -9
- package/dist/cli/polly.js.map +4 -4
- package/dist/cli/template-utils.js +3 -3
- package/dist/cli/template-utils.js.map +3 -3
- package/dist/src/shared/state/app-state.d.ts +8 -0
- package/dist/vendor/verify/src/cli.js +78 -71
- package/dist/vendor/verify/src/cli.js.map +10 -10
- package/dist/vendor/verify/src/public-api.d.ts +41 -0
- package/dist/vendor/verify/src/public-api.js +26 -0
- package/dist/vendor/verify/src/public-api.js.map +10 -0
- package/dist/vendor/visualize/src/cli.js +108 -104
- package/dist/vendor/visualize/src/cli.js.map +13 -13
- package/package.json +15 -2
- package/templates/pwa/build.ts.template +37 -37
- package/templates/pwa/server.ts.template +53 -53
- package/templates/pwa/src/service-worker.ts.template +131 -135
- package/templates/pwa/src/shared-worker.ts.template +114 -109
- package/dist/shared/state/app-state.d.ts +0 -8
- /package/dist/{background → src/background}/api-client.d.ts +0 -0
- /package/dist/{background → src/background}/context-menu.d.ts +0 -0
- /package/dist/{background → src/background}/index.d.ts +0 -0
- /package/dist/{background → src/background}/log-store.d.ts +0 -0
- /package/dist/{background → src/background}/message-router.d.ts +0 -0
- /package/dist/{background → src/background}/offscreen-manager.d.ts +0 -0
- /package/dist/{index.d.ts → src/index.d.ts} +0 -0
- /package/dist/{shared → src/shared}/adapters/chrome/context-menus.chrome.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/chrome/offscreen.chrome.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/chrome/runtime.chrome.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/chrome/storage.chrome.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/chrome/tabs.chrome.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/chrome/window.chrome.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/context-menus.adapter.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/fetch.adapter.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/index.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/logger.adapter.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/offscreen.adapter.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/runtime.adapter.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/storage.adapter.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/tabs.adapter.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/window.adapter.d.ts +0 -0
- /package/dist/{shared → src/shared}/lib/context-helpers.d.ts +0 -0
- /package/dist/{shared → src/shared}/lib/context-specific-helpers.d.ts +0 -0
- /package/dist/{shared → src/shared}/lib/errors.d.ts +0 -0
- /package/dist/{shared → src/shared}/lib/handler-execution-tracker.d.ts +0 -0
- /package/dist/{shared → src/shared}/lib/message-bus.d.ts +0 -0
- /package/dist/{shared → src/shared}/lib/state.d.ts +0 -0
- /package/dist/{shared → src/shared}/lib/test-helpers.d.ts +0 -0
- /package/dist/{shared → src/shared}/types/messages.d.ts +0 -0
|
@@ -68,27 +68,27 @@ class ProjectDetector {
|
|
|
68
68
|
if (background) {
|
|
69
69
|
const file = background.service_worker || background.scripts?.[0] || background.page;
|
|
70
70
|
if (file) {
|
|
71
|
-
entryPoints
|
|
71
|
+
entryPoints["background"] = this.findSourceFile(file);
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
const contentScripts = manifest.content_scripts;
|
|
75
75
|
if (contentScripts && contentScripts.length > 0) {
|
|
76
76
|
const firstScript = contentScripts[0].js?.[0];
|
|
77
77
|
if (firstScript) {
|
|
78
|
-
entryPoints
|
|
78
|
+
entryPoints["content"] = this.findSourceFile(firstScript);
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
const popup = manifest.action?.default_popup || manifest.browser_action?.default_popup;
|
|
82
82
|
if (popup) {
|
|
83
83
|
const jsFile = this.findAssociatedJS(path3.join(this.projectRoot, popup));
|
|
84
84
|
if (jsFile)
|
|
85
|
-
entryPoints
|
|
85
|
+
entryPoints["popup"] = jsFile;
|
|
86
86
|
}
|
|
87
87
|
const options = manifest.options_ui?.page || manifest.options_page;
|
|
88
88
|
if (options) {
|
|
89
89
|
const jsFile = this.findAssociatedJS(path3.join(this.projectRoot, options));
|
|
90
90
|
if (jsFile)
|
|
91
|
-
entryPoints
|
|
91
|
+
entryPoints["options"] = jsFile;
|
|
92
92
|
}
|
|
93
93
|
return {
|
|
94
94
|
type: "chrome-extension",
|
|
@@ -112,7 +112,7 @@ class ProjectDetector {
|
|
|
112
112
|
for (const candidate of swCandidates) {
|
|
113
113
|
const fullPath = path3.join(this.projectRoot, candidate);
|
|
114
114
|
if (fs3.existsSync(fullPath)) {
|
|
115
|
-
entryPoints
|
|
115
|
+
entryPoints["worker"] = fullPath;
|
|
116
116
|
break;
|
|
117
117
|
}
|
|
118
118
|
}
|
|
@@ -126,7 +126,7 @@ class ProjectDetector {
|
|
|
126
126
|
for (const candidate of clientCandidates) {
|
|
127
127
|
const fullPath = path3.join(this.projectRoot, candidate);
|
|
128
128
|
if (fs3.existsSync(fullPath)) {
|
|
129
|
-
entryPoints
|
|
129
|
+
entryPoints["client"] = fullPath;
|
|
130
130
|
break;
|
|
131
131
|
}
|
|
132
132
|
}
|
|
@@ -156,7 +156,7 @@ class ProjectDetector {
|
|
|
156
156
|
for (const candidate of mainCandidates) {
|
|
157
157
|
const fullPath = path3.join(this.projectRoot, candidate);
|
|
158
158
|
if (fs3.existsSync(fullPath) || fs3.existsSync(fullPath.replace(/\.js$/, ".ts"))) {
|
|
159
|
-
entryPoints
|
|
159
|
+
entryPoints["main"] = fs3.existsSync(fullPath) ? fullPath : fullPath.replace(/\.js$/, ".ts");
|
|
160
160
|
break;
|
|
161
161
|
}
|
|
162
162
|
}
|
|
@@ -169,7 +169,7 @@ class ProjectDetector {
|
|
|
169
169
|
for (const candidate of rendererCandidates) {
|
|
170
170
|
const fullPath = path3.join(this.projectRoot, candidate);
|
|
171
171
|
if (fs3.existsSync(fullPath)) {
|
|
172
|
-
entryPoints
|
|
172
|
+
entryPoints["renderer"] = fullPath;
|
|
173
173
|
break;
|
|
174
174
|
}
|
|
175
175
|
}
|
|
@@ -207,13 +207,13 @@ class ProjectDetector {
|
|
|
207
207
|
const scoredServers = this.scoreServerCandidates(serverCandidates);
|
|
208
208
|
if (scoredServers.length > 0) {
|
|
209
209
|
const best = scoredServers[0];
|
|
210
|
-
entryPoints
|
|
210
|
+
entryPoints["server"] = best.path;
|
|
211
211
|
if (best.hasWebSocket) {
|
|
212
|
-
contextMapping
|
|
212
|
+
contextMapping["server"] = "WebSocket Server";
|
|
213
213
|
} else if (best.hasHTTP) {
|
|
214
|
-
contextMapping
|
|
214
|
+
contextMapping["server"] = "HTTP Server";
|
|
215
215
|
} else {
|
|
216
|
-
contextMapping
|
|
216
|
+
contextMapping["server"] = "Server";
|
|
217
217
|
}
|
|
218
218
|
}
|
|
219
219
|
const clientCandidates = [
|
|
@@ -227,8 +227,8 @@ class ProjectDetector {
|
|
|
227
227
|
for (const candidate of clientCandidates) {
|
|
228
228
|
const fullPath = path3.join(this.projectRoot, candidate);
|
|
229
229
|
if (fs3.existsSync(fullPath)) {
|
|
230
|
-
entryPoints
|
|
231
|
-
contextMapping
|
|
230
|
+
entryPoints["client"] = fullPath;
|
|
231
|
+
contextMapping["client"] = "Client";
|
|
232
232
|
break;
|
|
233
233
|
}
|
|
234
234
|
}
|
|
@@ -367,7 +367,7 @@ class ProjectDetector {
|
|
|
367
367
|
for (const candidate of commonEntries) {
|
|
368
368
|
const fullPath = path3.join(this.projectRoot, candidate);
|
|
369
369
|
if (fs3.existsSync(fullPath)) {
|
|
370
|
-
entryPoints
|
|
370
|
+
entryPoints["main"] = fullPath;
|
|
371
371
|
break;
|
|
372
372
|
}
|
|
373
373
|
}
|
|
@@ -512,14 +512,14 @@ class ManifestParser {
|
|
|
512
512
|
if (background) {
|
|
513
513
|
const entryFile = background.files[0];
|
|
514
514
|
if (entryFile) {
|
|
515
|
-
entryPoints
|
|
515
|
+
entryPoints["background"] = this.findSourceFile(entryFile);
|
|
516
516
|
}
|
|
517
517
|
}
|
|
518
518
|
const contentScripts = this.parseContentScripts();
|
|
519
519
|
if (contentScripts && contentScripts.length > 0) {
|
|
520
|
-
const firstScript = contentScripts[0]
|
|
520
|
+
const firstScript = contentScripts[0]?.js[0];
|
|
521
521
|
if (firstScript) {
|
|
522
|
-
entryPoints
|
|
522
|
+
entryPoints["content"] = this.findSourceFile(firstScript);
|
|
523
523
|
}
|
|
524
524
|
}
|
|
525
525
|
const popup = this.parsePopup();
|
|
@@ -527,7 +527,7 @@ class ManifestParser {
|
|
|
527
527
|
const htmlPath = path.join(this.baseDir, popup.html);
|
|
528
528
|
const jsPath = this.findAssociatedJS(htmlPath);
|
|
529
529
|
if (jsPath) {
|
|
530
|
-
entryPoints
|
|
530
|
+
entryPoints["popup"] = jsPath;
|
|
531
531
|
}
|
|
532
532
|
}
|
|
533
533
|
const options = this.parseOptions();
|
|
@@ -535,7 +535,7 @@ class ManifestParser {
|
|
|
535
535
|
const htmlPath = path.join(this.baseDir, options.page);
|
|
536
536
|
const jsPath = this.findAssociatedJS(htmlPath);
|
|
537
537
|
if (jsPath) {
|
|
538
|
-
entryPoints
|
|
538
|
+
entryPoints["options"] = jsPath;
|
|
539
539
|
}
|
|
540
540
|
}
|
|
541
541
|
const devtools = this.parseDevtools();
|
|
@@ -543,7 +543,7 @@ class ManifestParser {
|
|
|
543
543
|
const htmlPath = path.join(this.baseDir, devtools.page);
|
|
544
544
|
const jsPath = this.findAssociatedJS(htmlPath);
|
|
545
545
|
if (jsPath) {
|
|
546
|
-
entryPoints
|
|
546
|
+
entryPoints["devtools"] = jsPath;
|
|
547
547
|
}
|
|
548
548
|
}
|
|
549
549
|
return entryPoints;
|
|
@@ -705,9 +705,9 @@ class ContextAnalyzer {
|
|
|
705
705
|
handlers: contextHandlers,
|
|
706
706
|
chromeAPIs,
|
|
707
707
|
externalAPIs: [],
|
|
708
|
-
components,
|
|
708
|
+
...components ? { components } : {},
|
|
709
709
|
dependencies,
|
|
710
|
-
description
|
|
710
|
+
...description ? { description } : {}
|
|
711
711
|
};
|
|
712
712
|
}
|
|
713
713
|
extractChromeAPIs(sourceFile) {
|
|
@@ -717,20 +717,23 @@ class ContextAnalyzer {
|
|
|
717
717
|
const text = node.getText();
|
|
718
718
|
if (text.startsWith("chrome.")) {
|
|
719
719
|
const match = text.match(/^chrome\.([^.(]+(?:\.[^.(]+)?)/);
|
|
720
|
-
|
|
721
|
-
|
|
720
|
+
const api = match?.[1];
|
|
721
|
+
if (api) {
|
|
722
|
+
apis.add(api);
|
|
722
723
|
}
|
|
723
724
|
}
|
|
724
725
|
if (text.startsWith("browser.")) {
|
|
725
726
|
const match = text.match(/^browser\.([^.(]+(?:\.[^.(]+)?)/);
|
|
726
|
-
|
|
727
|
-
|
|
727
|
+
const api = match?.[1];
|
|
728
|
+
if (api) {
|
|
729
|
+
apis.add(api);
|
|
728
730
|
}
|
|
729
731
|
}
|
|
730
732
|
if (text.includes("bus.adapters.")) {
|
|
731
733
|
const match = text.match(/bus\.adapters\.([^.(]+)/);
|
|
732
|
-
|
|
733
|
-
|
|
734
|
+
const api = match?.[1];
|
|
735
|
+
if (api) {
|
|
736
|
+
apis.add(api);
|
|
734
737
|
}
|
|
735
738
|
}
|
|
736
739
|
}
|
|
@@ -767,13 +770,14 @@ class ContextAnalyzer {
|
|
|
767
770
|
if (Node.isFunctionDeclaration(node)) {
|
|
768
771
|
const name = node.getName();
|
|
769
772
|
if (name && this.looksLikeComponent(name, node)) {
|
|
773
|
+
const description = this.extractJSDocDescription(node);
|
|
770
774
|
components.push({
|
|
771
775
|
name,
|
|
772
776
|
type: "function",
|
|
773
777
|
filePath: sourceFile.getFilePath(),
|
|
774
778
|
line: node.getStartLineNumber(),
|
|
775
779
|
props: this.extractProps(node),
|
|
776
|
-
description:
|
|
780
|
+
...description ? { description } : {}
|
|
777
781
|
});
|
|
778
782
|
}
|
|
779
783
|
}
|
|
@@ -782,13 +786,14 @@ class ContextAnalyzer {
|
|
|
782
786
|
const initializer = node.getInitializer();
|
|
783
787
|
if (name && initializer && (Node.isArrowFunction(initializer) || Node.isFunctionExpression(initializer))) {
|
|
784
788
|
if (this.looksLikeComponent(name, initializer)) {
|
|
789
|
+
const description = this.extractJSDocDescription(node);
|
|
785
790
|
components.push({
|
|
786
791
|
name,
|
|
787
792
|
type: "function",
|
|
788
793
|
filePath: sourceFile.getFilePath(),
|
|
789
794
|
line: node.getStartLineNumber(),
|
|
790
795
|
props: this.extractProps(initializer),
|
|
791
|
-
description:
|
|
796
|
+
...description ? { description } : {}
|
|
792
797
|
});
|
|
793
798
|
}
|
|
794
799
|
}
|
|
@@ -796,13 +801,14 @@ class ContextAnalyzer {
|
|
|
796
801
|
if (Node.isClassDeclaration(node)) {
|
|
797
802
|
const name = node.getName();
|
|
798
803
|
if (name && this.looksLikeClassComponent(node)) {
|
|
804
|
+
const description = this.extractJSDocDescription(node);
|
|
799
805
|
components.push({
|
|
800
806
|
name,
|
|
801
807
|
type: "class",
|
|
802
808
|
filePath: sourceFile.getFilePath(),
|
|
803
809
|
line: node.getStartLineNumber(),
|
|
804
810
|
props: this.extractPropsFromClass(node),
|
|
805
|
-
description:
|
|
811
|
+
...description ? { description } : {}
|
|
806
812
|
});
|
|
807
813
|
}
|
|
808
814
|
}
|
|
@@ -905,9 +911,9 @@ class FlowAnalyzer {
|
|
|
905
911
|
messageType,
|
|
906
912
|
from: sender.context,
|
|
907
913
|
to: recipients,
|
|
908
|
-
trigger: flowMetadata.trigger,
|
|
909
|
-
flowName: flowMetadata.flowName,
|
|
910
|
-
description: flowMetadata.description,
|
|
914
|
+
...flowMetadata.trigger ? { trigger: flowMetadata.trigger } : {},
|
|
915
|
+
...flowMetadata.flowName ? { flowName: flowMetadata.flowName } : {},
|
|
916
|
+
...flowMetadata.description ? { description: flowMetadata.description } : {},
|
|
911
917
|
sequence
|
|
912
918
|
});
|
|
913
919
|
}
|
|
@@ -1218,7 +1224,7 @@ class IntegrationAnalyzer {
|
|
|
1218
1224
|
const moduleSpecifier = importDecl.getModuleSpecifierValue();
|
|
1219
1225
|
if (!moduleSpecifier.startsWith(".") && !moduleSpecifier.startsWith("/")) {
|
|
1220
1226
|
const packageName = moduleSpecifier.startsWith("@") ? moduleSpecifier.split("/").slice(0, 2).join("/") : moduleSpecifier.split("/")[0];
|
|
1221
|
-
if (!seen.has(packageName)) {
|
|
1227
|
+
if (packageName && !seen.has(packageName)) {
|
|
1222
1228
|
seen.add(packageName);
|
|
1223
1229
|
scripts.push({
|
|
1224
1230
|
type: "external-script",
|
|
@@ -1284,7 +1290,7 @@ class IntegrationAnalyzer {
|
|
|
1284
1290
|
const hostname = parsed.hostname;
|
|
1285
1291
|
const cleanHost = hostname.replace(/^www\./, "");
|
|
1286
1292
|
const parts = cleanHost.split(".");
|
|
1287
|
-
if (parts.length > 0) {
|
|
1293
|
+
if (parts.length > 0 && parts[0]) {
|
|
1288
1294
|
return parts[0].charAt(0).toUpperCase() + parts[0].slice(1) + " API";
|
|
1289
1295
|
}
|
|
1290
1296
|
} catch {}
|
|
@@ -1314,7 +1320,7 @@ class IntegrationAnalyzer {
|
|
|
1314
1320
|
}
|
|
1315
1321
|
|
|
1316
1322
|
// vendor/analysis/src/extract/handlers.ts
|
|
1317
|
-
import { Project as Project4, SyntaxKind
|
|
1323
|
+
import { Project as Project4, SyntaxKind, Node as Node5 } from "ts-morph";
|
|
1318
1324
|
|
|
1319
1325
|
// vendor/analysis/src/extract/relationships.ts
|
|
1320
1326
|
import { Node as Node4 } from "ts-morph";
|
|
@@ -1417,7 +1423,7 @@ class RelationshipExtractor {
|
|
|
1417
1423
|
const objectExpr = expr.getExpression();
|
|
1418
1424
|
const objectName = objectExpr.getText();
|
|
1419
1425
|
const methodName = expr.getName();
|
|
1420
|
-
targetComponent = this.inferComponentFromCall(objectName
|
|
1426
|
+
targetComponent = this.inferComponentFromCall(objectName);
|
|
1421
1427
|
if (!targetComponent) {
|
|
1422
1428
|
return null;
|
|
1423
1429
|
}
|
|
@@ -1448,7 +1454,7 @@ class RelationshipExtractor {
|
|
|
1448
1454
|
rootObject = rootObject.getExpression();
|
|
1449
1455
|
}
|
|
1450
1456
|
const objectName = rootObject.getText();
|
|
1451
|
-
const targetComponent = this.inferComponentFromCall(objectName
|
|
1457
|
+
const targetComponent = this.inferComponentFromCall(objectName);
|
|
1452
1458
|
if (!targetComponent) {
|
|
1453
1459
|
return null;
|
|
1454
1460
|
}
|
|
@@ -1485,7 +1491,7 @@ class RelationshipExtractor {
|
|
|
1485
1491
|
}
|
|
1486
1492
|
extractFromFetchCall(callExpr, handlerName) {
|
|
1487
1493
|
const args = callExpr.getArguments();
|
|
1488
|
-
if (args.length === 0) {
|
|
1494
|
+
if (args.length === 0 || !args[0]) {
|
|
1489
1495
|
return null;
|
|
1490
1496
|
}
|
|
1491
1497
|
const urlArg = args[0].getText();
|
|
@@ -1504,7 +1510,7 @@ class RelationshipExtractor {
|
|
|
1504
1510
|
evidence: [`fetch() call to: ${urlArg}`]
|
|
1505
1511
|
};
|
|
1506
1512
|
}
|
|
1507
|
-
inferComponentFromCall(objectName
|
|
1513
|
+
inferComponentFromCall(objectName) {
|
|
1508
1514
|
const mappings = {
|
|
1509
1515
|
db: "db_client",
|
|
1510
1516
|
database: "database",
|
|
@@ -1581,7 +1587,7 @@ class RelationshipExtractor {
|
|
|
1581
1587
|
}
|
|
1582
1588
|
if (modulePath.includes("/service") || modulePath.includes("/services")) {
|
|
1583
1589
|
const match = modulePath.match(/\/([^/]+)\.ts$/);
|
|
1584
|
-
if (match) {
|
|
1590
|
+
if (match && match[1]) {
|
|
1585
1591
|
return this.toComponentId(match[1]);
|
|
1586
1592
|
}
|
|
1587
1593
|
}
|
|
@@ -1666,7 +1672,7 @@ class HandlerExtractor {
|
|
|
1666
1672
|
const handlers = [];
|
|
1667
1673
|
const messageTypes = new Set;
|
|
1668
1674
|
const sourceFiles = this.project.getSourceFiles();
|
|
1669
|
-
if (process.env
|
|
1675
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
1670
1676
|
console.log(`[DEBUG] Loaded ${sourceFiles.length} source files`);
|
|
1671
1677
|
if (sourceFiles.length <= 20) {
|
|
1672
1678
|
for (const sf of sourceFiles) {
|
|
@@ -1681,7 +1687,7 @@ class HandlerExtractor {
|
|
|
1681
1687
|
messageTypes.add(handler.messageType);
|
|
1682
1688
|
}
|
|
1683
1689
|
}
|
|
1684
|
-
if (process.env
|
|
1690
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
1685
1691
|
console.log(`[DEBUG] Total handlers extracted: ${handlers.length}`);
|
|
1686
1692
|
}
|
|
1687
1693
|
return {
|
|
@@ -1798,7 +1804,7 @@ class HandlerExtractor {
|
|
|
1798
1804
|
extractVerificationConditions(funcNode, preconditions, postconditions) {
|
|
1799
1805
|
const body = funcNode.getBody();
|
|
1800
1806
|
const statements = Node5.isBlock(body) ? body.getStatements() : [body];
|
|
1801
|
-
statements.forEach((statement
|
|
1807
|
+
statements.forEach((statement) => {
|
|
1802
1808
|
if (Node5.isExpressionStatement(statement)) {
|
|
1803
1809
|
const expr = statement.getExpression();
|
|
1804
1810
|
if (Node5.isCallExpression(expr)) {
|
|
@@ -1862,13 +1868,13 @@ class HandlerExtractor {
|
|
|
1862
1868
|
if (Node5.isNumericLiteral(node)) {
|
|
1863
1869
|
return node.getLiteralValue();
|
|
1864
1870
|
}
|
|
1865
|
-
if (node.getKind() ===
|
|
1871
|
+
if (node.getKind() === SyntaxKind.TrueKeyword) {
|
|
1866
1872
|
return true;
|
|
1867
1873
|
}
|
|
1868
|
-
if (node.getKind() ===
|
|
1874
|
+
if (node.getKind() === SyntaxKind.FalseKeyword) {
|
|
1869
1875
|
return false;
|
|
1870
1876
|
}
|
|
1871
|
-
if (node.getKind() ===
|
|
1877
|
+
if (node.getKind() === SyntaxKind.NullKeyword) {
|
|
1872
1878
|
return null;
|
|
1873
1879
|
}
|
|
1874
1880
|
return;
|
|
@@ -1951,7 +1957,7 @@ class HandlerExtractor {
|
|
|
1951
1957
|
typeGuards = this.findTypePredicateFunctions(sourceFile);
|
|
1952
1958
|
this.typeGuardCache.set(sourceFile, typeGuards);
|
|
1953
1959
|
}
|
|
1954
|
-
if (process.env
|
|
1960
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
1955
1961
|
console.log(`[DEBUG] File: ${sourceFile.getBaseName()}`);
|
|
1956
1962
|
console.log(`[DEBUG] Local type guards found: ${typeGuards.size}`);
|
|
1957
1963
|
if (typeGuards.size > 0) {
|
|
@@ -1965,7 +1971,7 @@ class HandlerExtractor {
|
|
|
1965
1971
|
const handler = this.extractHandlerFromIfClause(currentIf, typeGuards, context, filePath);
|
|
1966
1972
|
if (handler) {
|
|
1967
1973
|
handlers.push(handler);
|
|
1968
|
-
if (process.env
|
|
1974
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
1969
1975
|
console.log(`[DEBUG] Found handler: ${handler.messageType} at line ${handler.location.line}`);
|
|
1970
1976
|
}
|
|
1971
1977
|
}
|
|
@@ -1977,7 +1983,7 @@ class HandlerExtractor {
|
|
|
1977
1983
|
}
|
|
1978
1984
|
}
|
|
1979
1985
|
} catch (error) {
|
|
1980
|
-
if (process.env
|
|
1986
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
1981
1987
|
console.log(`[DEBUG] Error in extractTypeGuardHandlers: ${error}`);
|
|
1982
1988
|
}
|
|
1983
1989
|
}
|
|
@@ -1985,7 +1991,8 @@ class HandlerExtractor {
|
|
|
1985
1991
|
}
|
|
1986
1992
|
extractHandlerFromIfClause(ifNode, typeGuards, context, filePath) {
|
|
1987
1993
|
try {
|
|
1988
|
-
const
|
|
1994
|
+
const ifStmt = ifNode;
|
|
1995
|
+
const condition = ifStmt.getExpression();
|
|
1989
1996
|
if (!Node5.isCallExpression(condition)) {
|
|
1990
1997
|
return null;
|
|
1991
1998
|
}
|
|
@@ -1994,32 +2001,32 @@ class HandlerExtractor {
|
|
|
1994
2001
|
if (Node5.isIdentifier(funcExpr)) {
|
|
1995
2002
|
funcName = funcExpr.getText();
|
|
1996
2003
|
}
|
|
1997
|
-
if (process.env
|
|
2004
|
+
if (process.env["POLLY_DEBUG"] && funcName) {
|
|
1998
2005
|
console.log(`[DEBUG] Processing if condition with function: ${funcName}`);
|
|
1999
2006
|
}
|
|
2000
2007
|
let messageType = undefined;
|
|
2001
2008
|
if (funcName && typeGuards.has(funcName)) {
|
|
2002
2009
|
messageType = typeGuards.get(funcName);
|
|
2003
|
-
if (process.env
|
|
2010
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
2004
2011
|
console.log(`[DEBUG] Found in local type guards: ${funcName} → ${messageType}`);
|
|
2005
2012
|
}
|
|
2006
2013
|
} else if (Node5.isIdentifier(funcExpr)) {
|
|
2007
|
-
if (process.env
|
|
2014
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
2008
2015
|
console.log(`[DEBUG] Not found locally, trying import resolution for: ${funcName}`);
|
|
2009
2016
|
}
|
|
2010
|
-
messageType = this.resolveImportedTypeGuard(funcExpr);
|
|
2017
|
+
messageType = this.resolveImportedTypeGuard(funcExpr) ?? undefined;
|
|
2011
2018
|
}
|
|
2012
2019
|
if (!messageType) {
|
|
2013
|
-
if (process.env
|
|
2020
|
+
if (process.env["POLLY_DEBUG"] && funcName) {
|
|
2014
2021
|
console.log(`[DEBUG] Could not resolve message type for: ${funcName}`);
|
|
2015
2022
|
}
|
|
2016
2023
|
return null;
|
|
2017
2024
|
}
|
|
2018
|
-
const line =
|
|
2019
|
-
const sourceFile =
|
|
2025
|
+
const line = ifStmt.getStartLineNumber();
|
|
2026
|
+
const sourceFile = ifStmt.getSourceFile();
|
|
2020
2027
|
const handlerName = `${messageType}_handler`;
|
|
2021
2028
|
let relationships = undefined;
|
|
2022
|
-
const thenStatement =
|
|
2029
|
+
const thenStatement = ifStmt.getThenStatement();
|
|
2023
2030
|
if (thenStatement) {
|
|
2024
2031
|
const detectedRelationships = this.relationshipExtractor.extractFromHandler(thenStatement, sourceFile, handlerName);
|
|
2025
2032
|
if (detectedRelationships.length > 0) {
|
|
@@ -2072,7 +2079,7 @@ class HandlerExtractor {
|
|
|
2072
2079
|
const bodyText = body.getText();
|
|
2073
2080
|
const typeValueMatch = bodyText.match(/\.type\s*===?\s*['"](\w+)['"]/);
|
|
2074
2081
|
if (typeValueMatch) {
|
|
2075
|
-
messageType = typeValueMatch[1];
|
|
2082
|
+
messageType = typeValueMatch[1] ?? null;
|
|
2076
2083
|
}
|
|
2077
2084
|
}
|
|
2078
2085
|
}
|
|
@@ -2090,7 +2097,7 @@ class HandlerExtractor {
|
|
|
2090
2097
|
const funcName = identifier.getText();
|
|
2091
2098
|
const definitions = identifier.getDefinitionNodes();
|
|
2092
2099
|
if (definitions.length === 0) {
|
|
2093
|
-
if (process.env
|
|
2100
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
2094
2101
|
console.log(`[DEBUG] No definitions found for imported function: ${funcName}`);
|
|
2095
2102
|
}
|
|
2096
2103
|
return null;
|
|
@@ -2098,7 +2105,7 @@ class HandlerExtractor {
|
|
|
2098
2105
|
for (const def of definitions) {
|
|
2099
2106
|
if (Node5.isFunctionDeclaration(def) || Node5.isFunctionExpression(def) || Node5.isArrowFunction(def)) {
|
|
2100
2107
|
const returnTypeNode = def.getReturnTypeNode();
|
|
2101
|
-
if (process.env
|
|
2108
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
2102
2109
|
const returnType = def.getReturnType().getText();
|
|
2103
2110
|
console.log(`[DEBUG] Function ${funcName} return type (resolved): ${returnType}`);
|
|
2104
2111
|
console.log(`[DEBUG] Has return type node: ${!!returnTypeNode}`);
|
|
@@ -2110,7 +2117,7 @@ class HandlerExtractor {
|
|
|
2110
2117
|
const typeName = typeNode.getText();
|
|
2111
2118
|
const messageType = this.extractMessageTypeFromTypeName(typeName);
|
|
2112
2119
|
if (messageType) {
|
|
2113
|
-
if (process.env
|
|
2120
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
2114
2121
|
console.log(`[DEBUG] Resolved ${funcName} → ${messageType} (from AST type predicate)`);
|
|
2115
2122
|
}
|
|
2116
2123
|
return messageType;
|
|
@@ -2122,8 +2129,8 @@ class HandlerExtractor {
|
|
|
2122
2129
|
const bodyText = body.getText();
|
|
2123
2130
|
const typeValueMatch = bodyText.match(/\.type\s*===?\s*['"](\w+)['"]/);
|
|
2124
2131
|
if (typeValueMatch) {
|
|
2125
|
-
const messageType = typeValueMatch[1];
|
|
2126
|
-
if (process.env
|
|
2132
|
+
const messageType = typeValueMatch[1] ?? null;
|
|
2133
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
2127
2134
|
console.log(`[DEBUG] Resolved ${funcName} → ${messageType} (from body)`);
|
|
2128
2135
|
}
|
|
2129
2136
|
return messageType;
|
|
@@ -2132,7 +2139,7 @@ class HandlerExtractor {
|
|
|
2132
2139
|
}
|
|
2133
2140
|
}
|
|
2134
2141
|
} catch (error) {
|
|
2135
|
-
if (process.env
|
|
2142
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
2136
2143
|
console.log(`[DEBUG] Error resolving imported type guard: ${error}`);
|
|
2137
2144
|
}
|
|
2138
2145
|
}
|
|
@@ -2228,9 +2235,9 @@ class ADRExtractor {
|
|
|
2228
2235
|
const content = fs2.readFileSync(filePath, "utf-8");
|
|
2229
2236
|
const fileName = path2.basename(filePath, ".md");
|
|
2230
2237
|
const idMatch = fileName.match(/^(\d+)/);
|
|
2231
|
-
const id = idMatch
|
|
2238
|
+
const id = idMatch?.[1] ?? fileName;
|
|
2232
2239
|
const titleMatch = content.match(/^#\s+(.+)$/m);
|
|
2233
|
-
const title = titleMatch
|
|
2240
|
+
const title = titleMatch?.[1]?.trim() ?? fileName;
|
|
2234
2241
|
const status = this.extractStatus(content);
|
|
2235
2242
|
const date = this.extractDate(content);
|
|
2236
2243
|
const context = this.extractSection(content, "Context");
|
|
@@ -2251,8 +2258,8 @@ class ADRExtractor {
|
|
|
2251
2258
|
context,
|
|
2252
2259
|
decision,
|
|
2253
2260
|
consequences,
|
|
2254
|
-
alternatives,
|
|
2255
|
-
links,
|
|
2261
|
+
...alternatives && alternatives.length > 0 ? { alternatives } : {},
|
|
2262
|
+
...links.length > 0 ? { links } : {},
|
|
2256
2263
|
source: filePath
|
|
2257
2264
|
};
|
|
2258
2265
|
}
|
|
@@ -2260,20 +2267,20 @@ class ADRExtractor {
|
|
|
2260
2267
|
const statusMatch = content.match(/Status:\s*(\w+)/i);
|
|
2261
2268
|
if (!statusMatch)
|
|
2262
2269
|
return "accepted";
|
|
2263
|
-
const status = statusMatch[1]
|
|
2264
|
-
if (["proposed", "accepted", "deprecated", "superseded"].includes(status)) {
|
|
2270
|
+
const status = statusMatch[1]?.toLowerCase();
|
|
2271
|
+
if (status && ["proposed", "accepted", "deprecated", "superseded"].includes(status)) {
|
|
2265
2272
|
return status;
|
|
2266
2273
|
}
|
|
2267
2274
|
return "accepted";
|
|
2268
2275
|
}
|
|
2269
2276
|
extractDate(content) {
|
|
2270
2277
|
const dateMatch = content.match(/Date:\s*(\d{4}-\d{2}-\d{2})/i) || content.match(/(\d{4}-\d{2}-\d{2})/i);
|
|
2271
|
-
return dateMatch
|
|
2278
|
+
return dateMatch?.[1] ?? new Date().toISOString().split("T")[0];
|
|
2272
2279
|
}
|
|
2273
2280
|
extractSection(content, sectionName) {
|
|
2274
2281
|
const regex = new RegExp(`##\\s+${sectionName}\\s*\\n([\\s\\S]*?)(?=\\n##|$)`, "i");
|
|
2275
2282
|
const match = content.match(regex);
|
|
2276
|
-
return match
|
|
2283
|
+
return match?.[1]?.trim() ?? "";
|
|
2277
2284
|
}
|
|
2278
2285
|
extractLinks(content) {
|
|
2279
2286
|
const links = [];
|
|
@@ -2281,10 +2288,11 @@ class ADRExtractor {
|
|
|
2281
2288
|
if (supersedesMatch) {
|
|
2282
2289
|
for (const match of supersedesMatch) {
|
|
2283
2290
|
const idMatch = match.match(/ADR-(\d+)/);
|
|
2284
|
-
|
|
2291
|
+
const id = idMatch?.[1];
|
|
2292
|
+
if (id) {
|
|
2285
2293
|
links.push({
|
|
2286
2294
|
type: "supersedes",
|
|
2287
|
-
adrId:
|
|
2295
|
+
adrId: id
|
|
2288
2296
|
});
|
|
2289
2297
|
}
|
|
2290
2298
|
}
|
|
@@ -2293,10 +2301,11 @@ class ADRExtractor {
|
|
|
2293
2301
|
if (supersededByMatch) {
|
|
2294
2302
|
for (const match of supersededByMatch) {
|
|
2295
2303
|
const idMatch = match.match(/ADR-(\d+)/);
|
|
2296
|
-
|
|
2304
|
+
const id = idMatch?.[1];
|
|
2305
|
+
if (id) {
|
|
2297
2306
|
links.push({
|
|
2298
2307
|
type: "superseded-by",
|
|
2299
|
-
adrId:
|
|
2308
|
+
adrId: id
|
|
2300
2309
|
});
|
|
2301
2310
|
}
|
|
2302
2311
|
}
|
|
@@ -2327,7 +2336,7 @@ class ArchitectureAnalyzer {
|
|
|
2327
2336
|
systemInfo = {
|
|
2328
2337
|
name: manifest.name,
|
|
2329
2338
|
version: manifest.version,
|
|
2330
|
-
description: manifest.description
|
|
2339
|
+
...manifest.description ? { description: manifest.description } : {}
|
|
2331
2340
|
};
|
|
2332
2341
|
} else {
|
|
2333
2342
|
const { detectProjectConfig: detectProjectConfig2 } = await Promise.resolve().then(() => (init_project_detector(), exports_project_detector));
|
|
@@ -2336,7 +2345,7 @@ class ArchitectureAnalyzer {
|
|
|
2336
2345
|
systemInfo = {
|
|
2337
2346
|
name: projectConfig.metadata?.name || "Unknown Project",
|
|
2338
2347
|
version: projectConfig.metadata?.version || "0.0.0",
|
|
2339
|
-
description: projectConfig.metadata
|
|
2348
|
+
...projectConfig.metadata?.description ? { description: projectConfig.metadata.description } : {}
|
|
2340
2349
|
};
|
|
2341
2350
|
}
|
|
2342
2351
|
const handlerExtractor = new HandlerExtractor(this.options.tsConfigPath);
|
|
@@ -2361,13 +2370,13 @@ class ArchitectureAnalyzer {
|
|
|
2361
2370
|
return {
|
|
2362
2371
|
projectRoot: this.options.projectRoot,
|
|
2363
2372
|
system: systemInfo,
|
|
2364
|
-
manifest,
|
|
2365
|
-
projectConfig,
|
|
2373
|
+
...manifest ? { manifest } : {},
|
|
2374
|
+
...projectConfig ? { projectConfig } : {},
|
|
2366
2375
|
contexts,
|
|
2367
2376
|
messageFlows,
|
|
2368
2377
|
integrations,
|
|
2369
|
-
adrs
|
|
2370
|
-
repository
|
|
2378
|
+
...adrs.adrs.length > 0 ? { adrs } : {},
|
|
2379
|
+
...repository ? { repository } : {}
|
|
2371
2380
|
};
|
|
2372
2381
|
}
|
|
2373
2382
|
mergeExternalAPIsIntoContexts(contexts, integrations) {
|
|
@@ -2578,7 +2587,6 @@ class StructurizrDSLGenerator {
|
|
|
2578
2587
|
const parts = [];
|
|
2579
2588
|
for (const integration of this.analysis.integrations) {
|
|
2580
2589
|
if (integration.type === "api" || integration.type === "websocket") {
|
|
2581
|
-
const tech = integration.technology || (integration.type === "websocket" ? "WebSocket" : "REST API");
|
|
2582
2590
|
let desc = integration.description || "";
|
|
2583
2591
|
if (!desc && integration.calls && integration.calls.length > 0) {
|
|
2584
2592
|
const endpoints = integration.calls.slice(0, 3).map((c) => c.endpoint).join(", ");
|
|
@@ -2691,7 +2699,7 @@ class StructurizrDSLGenerator {
|
|
|
2691
2699
|
return parts.join(`
|
|
2692
2700
|
`);
|
|
2693
2701
|
}
|
|
2694
|
-
generateComponentDescription(messageType,
|
|
2702
|
+
generateComponentDescription(messageType, _handler) {
|
|
2695
2703
|
const type = messageType.toLowerCase();
|
|
2696
2704
|
if (type.includes("login")) {
|
|
2697
2705
|
return "Authenticates users and establishes sessions";
|
|
@@ -2721,7 +2729,7 @@ class StructurizrDSLGenerator {
|
|
|
2721
2729
|
}
|
|
2722
2730
|
return `Processes ${messageType} messages and coordinates business logic`;
|
|
2723
2731
|
}
|
|
2724
|
-
getComponentTags(messageType,
|
|
2732
|
+
getComponentTags(messageType, _handler) {
|
|
2725
2733
|
const tags = ["Message Handler"];
|
|
2726
2734
|
const type = messageType.toLowerCase();
|
|
2727
2735
|
if (type.includes("login") || type.includes("logout") || type.includes("auth")) {
|
|
@@ -2780,7 +2788,7 @@ class StructurizrDSLGenerator {
|
|
|
2780
2788
|
}
|
|
2781
2789
|
return properties;
|
|
2782
2790
|
}
|
|
2783
|
-
generateComponentRelationships(
|
|
2791
|
+
generateComponentRelationships(_contextType, contextInfo) {
|
|
2784
2792
|
const parts = [];
|
|
2785
2793
|
const handlersByType = new Map;
|
|
2786
2794
|
for (const handler of contextInfo.handlers) {
|
|
@@ -2792,7 +2800,7 @@ class StructurizrDSLGenerator {
|
|
|
2792
2800
|
if (contextInfo.chromeAPIs && contextInfo.chromeAPIs.length > 0) {
|
|
2793
2801
|
for (const api of contextInfo.chromeAPIs) {
|
|
2794
2802
|
const apiId = this.toId(`chrome_${api}`);
|
|
2795
|
-
for (const [messageType,
|
|
2803
|
+
for (const [messageType, _handlers] of handlersByType) {
|
|
2796
2804
|
const componentId = this.toId(this.toComponentName(messageType));
|
|
2797
2805
|
let description = `Uses ${api}`;
|
|
2798
2806
|
if (api === "storage") {
|
|
@@ -2838,7 +2846,7 @@ class StructurizrDSLGenerator {
|
|
|
2838
2846
|
}
|
|
2839
2847
|
const stateHandlers = [];
|
|
2840
2848
|
const queryHandlers = [];
|
|
2841
|
-
for (const [messageType,
|
|
2849
|
+
for (const [messageType, _handlers] of handlersByType) {
|
|
2842
2850
|
const type = messageType.toLowerCase();
|
|
2843
2851
|
const componentId = this.toId(this.toComponentName(messageType));
|
|
2844
2852
|
if (type.includes("add") || type.includes("create") || type.includes("update") || type.includes("delete") || type.includes("remove") || type.includes("toggle") || type.includes("clear") || type.includes("login") || type.includes("logout")) {
|
|
@@ -2994,7 +3002,6 @@ class StructurizrDSLGenerator {
|
|
|
2994
3002
|
}
|
|
2995
3003
|
generateAutomaticDynamicDiagrams() {
|
|
2996
3004
|
const diagrams = [];
|
|
2997
|
-
const processedHandlers = new Set;
|
|
2998
3005
|
const handlersWithRelationships = [];
|
|
2999
3006
|
for (const [contextType, contextInfo] of Object.entries(this.analysis.contexts)) {
|
|
3000
3007
|
for (const handler of contextInfo.handlers) {
|
|
@@ -3059,7 +3066,7 @@ class StructurizrDSLGenerator {
|
|
|
3059
3066
|
const scope = handlers[0]?.contextName ? `extension.${handlers[0].contextName}` : "extension";
|
|
3060
3067
|
parts.push(` dynamic ${scope} "${title}" "${description}" {`);
|
|
3061
3068
|
let stepCount = 0;
|
|
3062
|
-
for (const { handler, contextName } of handlers) {
|
|
3069
|
+
for (const { handler, contextName: _contextName } of handlers) {
|
|
3063
3070
|
const handlerComponentId = this.toId(`${handler.messageType}_handler`);
|
|
3064
3071
|
for (const rel of handler.relationships) {
|
|
3065
3072
|
const toComponent = this.toId(rel.to);
|
|
@@ -3142,7 +3149,7 @@ class StructurizrDSLGenerator {
|
|
|
3142
3149
|
state: "Application state synchronization",
|
|
3143
3150
|
general: "Message flow through the system"
|
|
3144
3151
|
};
|
|
3145
|
-
return descriptions[domain] || descriptions
|
|
3152
|
+
return descriptions[domain] || descriptions["general"];
|
|
3146
3153
|
}
|
|
3147
3154
|
getUserAction(domain) {
|
|
3148
3155
|
const actions = {
|
|
@@ -3151,7 +3158,7 @@ class StructurizrDSLGenerator {
|
|
|
3151
3158
|
state: "Requests state",
|
|
3152
3159
|
general: "Interacts"
|
|
3153
3160
|
};
|
|
3154
|
-
return actions[domain] || actions
|
|
3161
|
+
return actions[domain] || actions["general"];
|
|
3155
3162
|
}
|
|
3156
3163
|
getMessageDescription(messageType) {
|
|
3157
3164
|
const type = messageType.toLowerCase();
|
|
@@ -3360,9 +3367,6 @@ class StructurizrDSLGenerator {
|
|
|
3360
3367
|
toId(name) {
|
|
3361
3368
|
return name.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_|_$/g, "");
|
|
3362
3369
|
}
|
|
3363
|
-
toViewName(flowName) {
|
|
3364
|
-
return flowName.split(/[_-]/).map((part) => this.capitalize(part)).join(" ");
|
|
3365
|
-
}
|
|
3366
3370
|
capitalize(str) {
|
|
3367
3371
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
3368
3372
|
}
|
|
@@ -3429,12 +3433,12 @@ class StructurizrDSLGenerator {
|
|
|
3429
3433
|
let entity = null;
|
|
3430
3434
|
const underscoreMatch = type.match(/^([a-z]+)_(add|create|update|delete|remove|get|fetch|load|list|query)/);
|
|
3431
3435
|
if (underscoreMatch) {
|
|
3432
|
-
entity = underscoreMatch[1];
|
|
3436
|
+
entity = underscoreMatch[1] ?? null;
|
|
3433
3437
|
}
|
|
3434
3438
|
if (!entity) {
|
|
3435
3439
|
const camelMatch = type.match(/(add|create|update|delete|remove|get|fetch|load|list|query)([a-z]+)/i);
|
|
3436
3440
|
if (camelMatch) {
|
|
3437
|
-
entity = camelMatch[2]
|
|
3441
|
+
entity = camelMatch[2]?.toLowerCase() ?? null;
|
|
3438
3442
|
}
|
|
3439
3443
|
}
|
|
3440
3444
|
if (!entity && type.match(/^[a-z]+$/)) {
|
|
@@ -3811,7 +3815,7 @@ Stack trace:`, COLORS.gray));
|
|
|
3811
3815
|
process.exit(1);
|
|
3812
3816
|
}
|
|
3813
3817
|
}
|
|
3814
|
-
async function exportCommand(
|
|
3818
|
+
async function exportCommand(_args) {
|
|
3815
3819
|
console.log(color(`
|
|
3816
3820
|
\uD83D\uDCE4 Generating static site...
|
|
3817
3821
|
`, COLORS.blue));
|
|
@@ -3884,7 +3888,7 @@ async function serveCommand(args) {
|
|
|
3884
3888
|
if (!BunGlobal) {
|
|
3885
3889
|
throw new Error("Bun runtime is required to run the server");
|
|
3886
3890
|
}
|
|
3887
|
-
|
|
3891
|
+
BunGlobal.serve({
|
|
3888
3892
|
port,
|
|
3889
3893
|
fetch(req) {
|
|
3890
3894
|
const url = new URL(req.url);
|
|
@@ -3999,4 +4003,4 @@ Stack trace:`, COLORS.gray));
|
|
|
3999
4003
|
process.exit(1);
|
|
4000
4004
|
});
|
|
4001
4005
|
|
|
4002
|
-
//# debugId=
|
|
4006
|
+
//# debugId=3ECE56D6DA69F32764756E2164756E21
|