@fairfox/polly 0.19.0 → 0.20.1
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 +131 -943
- package/dist/cli/polly.js +25 -4
- package/dist/cli/polly.js.map +3 -3
- package/dist/src/background/index.js +22 -12
- package/dist/src/background/index.js.map +3 -3
- package/dist/src/background/message-router.js +22 -12
- package/dist/src/background/message-router.js.map +3 -3
- package/dist/src/client/index.js +187 -154
- package/dist/src/client/index.js.map +4 -4
- package/dist/src/elysia/index.js +19 -9
- package/dist/src/elysia/index.js.map +2 -2
- package/dist/src/elysia/plugin.d.ts +3 -3
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +67 -14
- package/dist/src/index.js.map +7 -6
- package/dist/src/shared/adapters/index.js +22 -12
- package/dist/src/shared/adapters/index.js.map +3 -3
- package/dist/src/shared/lib/context-helpers.js +22 -12
- package/dist/src/shared/lib/context-helpers.js.map +3 -3
- package/dist/src/shared/lib/errors.js +19 -9
- package/dist/src/shared/lib/errors.js.map +2 -2
- package/dist/src/shared/lib/message-bus.js +22 -12
- package/dist/src/shared/lib/message-bus.js.map +3 -3
- package/dist/src/shared/lib/resource.d.ts +54 -0
- package/dist/src/shared/lib/resource.js +593 -0
- package/dist/src/shared/lib/resource.js.map +13 -0
- package/dist/src/shared/lib/state.d.ts +1 -0
- package/dist/src/shared/lib/state.js +23 -12
- package/dist/src/shared/lib/state.js.map +4 -4
- package/dist/src/shared/lib/test-helpers.js +19 -9
- package/dist/src/shared/lib/test-helpers.js.map +2 -2
- package/dist/src/shared/state/app-state.js +22 -12
- package/dist/src/shared/state/app-state.js.map +4 -4
- package/dist/src/shared/types/messages.js +19 -9
- package/dist/src/shared/types/messages.js.map +2 -2
- package/dist/tools/init/src/cli.js +6 -2
- package/dist/tools/init/src/cli.js.map +2 -2
- package/dist/tools/init/templates/pwa/package.json.template +1 -2
- package/dist/tools/test/src/adapters/index.d.ts +2 -2
- package/dist/tools/test/src/adapters/index.js +19 -9
- package/dist/tools/test/src/adapters/index.js.map +3 -3
- package/dist/tools/test/src/index.js +19 -9
- package/dist/tools/test/src/index.js.map +3 -3
- package/dist/tools/test/src/test-utils.js +19 -9
- package/dist/tools/test/src/test-utils.js.map +2 -2
- package/dist/tools/verify/specs/docker-compose.yml +1 -1
- package/dist/tools/verify/src/cli.js +185 -14
- package/dist/tools/verify/src/cli.js.map +7 -7
- package/dist/tools/verify/src/config.js +19 -9
- package/dist/tools/verify/src/config.js.map +2 -2
- package/dist/tools/visualize/src/cli.js +144 -5
- package/dist/tools/visualize/src/cli.js.map +3 -3
- package/package.json +12 -14
- package/dist/src/elysia/tla-generator.d.ts +0 -16
- package/dist/tools/verify/specs/verification.config.ts +0 -64
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
"import type { StorageAdapter, StorageChanges } from \"@/shared/adapters/storage.adapter\";\n\nexport interface MockStorageArea extends StorageAdapter {\n _data: Map<string, unknown>;\n}\n\nexport function createMockStorageArea(): MockStorageArea {\n const data = new Map<string, unknown>();\n\n return {\n get: async <T = Record<string, unknown>>(\n keys?: string | string[] | Record<string, unknown> | null\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Mock storage needs to handle multiple key types\n ): Promise<T> => {\n if (!keys) {\n return Object.fromEntries(data) as T;\n }\n if (typeof keys === \"string\") {\n return (data.has(keys) ? { [keys]: data.get(keys) } : {}) as T;\n }\n if (Array.isArray(keys)) {\n const result: Record<string, unknown> = {};\n for (const key of keys) {\n if (data.has(key)) {\n result[key] = data.get(key);\n }\n }\n return result as T;\n }\n // Object with defaults\n const result: Record<string, unknown> = {};\n for (const [key, defaultValue] of Object.entries(keys)) {\n result[key] = data.has(key) ? data.get(key) : defaultValue;\n }\n return result as T;\n },\n set: async (items) => {\n for (const [key, value] of Object.entries(items)) {\n data.set(key, value);\n }\n },\n remove: async (keys) => {\n const keyArray = Array.isArray(keys) ? keys : [keys];\n for (const key of keyArray) {\n data.delete(key);\n }\n },\n clear: async () => {\n data.clear();\n },\n onChanged: (_callback: (changes: StorageChanges, areaName: string) => void) => {\n // Mock implementation - not needed for current tests\n },\n _data: data,\n };\n}\n",
|
|
11
11
|
"import type { TabsAdapter } from \"@/shared/adapters/tabs.adapter\";\n\nexport interface MockTabs extends TabsAdapter {\n _tabs: Map<number, chrome.tabs.Tab>;\n}\n\nexport function createMockTabs(): MockTabs {\n const tabs = new Map<number, chrome.tabs.Tab>();\n\n return {\n query: async (queryInfo: chrome.tabs.QueryInfo): Promise<chrome.tabs.Tab[]> => {\n const results: chrome.tabs.Tab[] = [];\n for (const tab of tabs.values()) {\n let matches = true;\n if (queryInfo.active !== undefined && tab.active !== queryInfo.active) {\n matches = false;\n }\n if (queryInfo.currentWindow !== undefined) {\n matches = false;\n }\n if (matches) {\n results.push(tab);\n }\n }\n return results;\n },\n get: async (tabId: number): Promise<chrome.tabs.Tab> => {\n const tab = tabs.get(tabId);\n if (!tab) {\n throw new Error(`Tab ${tabId} not found`);\n }\n return tab;\n },\n sendMessage: async (_tabId: number, _message: unknown): Promise<unknown> => {\n return Promise.resolve({ success: true });\n },\n reload: async (\n _tabId: number,\n _reloadProperties?: { bypassCache?: boolean }\n ): Promise<void> => {\n // Mock implementation\n },\n onRemoved: (\n _callback: (tabId: number, removeInfo: chrome.tabs.OnRemovedInfo) => void\n ): void => {\n // Mock implementation - register listener\n },\n onUpdated: (\n _callback: (\n tabId: number,\n changeInfo: chrome.tabs.OnUpdatedInfo,\n tab: chrome.tabs.Tab\n ) => void\n ): void => {\n // Mock implementation - register listener\n },\n onActivated: (_callback: (activeInfo: { tabId: number; windowId: number }) => void): void => {\n // Mock implementation - register listener\n },\n create: async (createProperties: chrome.tabs.CreateProperties): Promise<chrome.tabs.Tab> => {\n const newTab: chrome.tabs.Tab = {\n id: Math.floor(Math.random() * 10000),\n index: tabs.size,\n pinned: false,\n highlighted: false,\n windowId: 1,\n active: true,\n incognito: false,\n selected: true,\n discarded: false,\n autoDiscardable: true,\n groupId: -1,\n url: createProperties.url || \"about:blank\",\n title: createProperties.url || \"New Tab\",\n frozen: false,\n };\n if (newTab.id !== undefined) {\n tabs.set(newTab.id, newTab);\n }\n return newTab;\n },\n _tabs: tabs,\n };\n}\n",
|
|
12
12
|
"import type { WindowAdapter } from \"@/shared/adapters/window.adapter\";\n\nexport interface MockWindow extends WindowAdapter {\n _messageListeners: Set<(event: MessageEvent) => void>;\n}\n\nexport function createMockWindow(): MockWindow {\n const messageListeners = new Set<(event: MessageEvent) => void>();\n\n return {\n postMessage: (message: unknown, targetOrigin: string) => {\n const event = new MessageEvent(\"message\", {\n data: message,\n origin: targetOrigin,\n source: null,\n });\n for (const listener of messageListeners) {\n listener(event);\n }\n },\n addEventListener: (type: string, listener: (event: MessageEvent) => void) => {\n if (type === \"message\") {\n messageListeners.add(listener);\n }\n },\n removeEventListener: (type: string, listener: (event: MessageEvent) => void) => {\n if (type === \"message\") {\n messageListeners.delete(listener);\n }\n },\n _messageListeners: messageListeners,\n };\n}\n",
|
|
13
|
-
"import { createMockContextMenus, type MockContextMenus } from \"./context-menus.mock\";\nimport { createMockFetch, type MockFetch } from \"./fetch.mock\";\nimport { createMockLogger, type MockLogger } from \"./logger.mock\";\nimport { createMockOffscreen, type MockOffscreen } from \"./offscreen.mock\";\nimport { createMockPort, createMockRuntime, type MockPort, type MockRuntime } from \"./runtime.mock\";\nimport { createMockStorageArea, type MockStorageArea } from \"./storage.mock\";\nimport { createMockTabs, type MockTabs } from \"./tabs.mock\";\nimport { createMockWindow, type MockWindow } from \"./window.mock\";\n\n/**\n * Mock adapters with full type information including mock-specific properties\n */\nexport interface MockExtensionAdapters {\n runtime: MockRuntime;\n storage: MockStorageArea;\n tabs: MockTabs;\n window: MockWindow;\n offscreen: MockOffscreen;\n contextMenus: MockContextMenus;\n fetch: MockFetch;\n logger: MockLogger;\n}\n\n/**\n * Convenience interface grouping Chrome-like mock APIs\n * Useful when tests need direct access to internal mock state\n */\nexport interface MockChrome {\n runtime: MockRuntime;\n storage: {\n local: MockStorageArea;\n };\n tabs: MockTabs;\n}\n\n/**\n * Create a mock Chrome object with grouped APIs\n * Use this when you need access to internal mock state (e.g., mockChrome.tabs._tabs)\n */\nexport function createMockChrome(): MockChrome {\n return {\n runtime: createMockRuntime(),\n storage: {\n local: createMockStorageArea(),\n },\n tabs: createMockTabs(),\n };\n}\n\n/**\n * Create a complete set of mock adapters for testing\n * Returns mock adapters with full type information\n */\nexport function createMockAdapters(): MockExtensionAdapters {\n return {\n runtime: createMockRuntime(),\n storage: createMockStorageArea(),\n tabs: createMockTabs(),\n window: createMockWindow(),\n offscreen: createMockOffscreen(),\n contextMenus: createMockContextMenus(),\n fetch: createMockFetch(),\n logger: createMockLogger({ silent: true }),\n };\n}\n\
|
|
13
|
+
"import { createMockContextMenus, type MockContextMenus } from \"./context-menus.mock\";\nimport { createMockFetch, type MockFetch } from \"./fetch.mock\";\nimport { createMockLogger, type MockLogger } from \"./logger.mock\";\nimport { createMockOffscreen, type MockOffscreen } from \"./offscreen.mock\";\nimport { createMockPort, createMockRuntime, type MockPort, type MockRuntime } from \"./runtime.mock\";\nimport { createMockStorageArea, type MockStorageArea } from \"./storage.mock\";\nimport { createMockTabs, type MockTabs } from \"./tabs.mock\";\nimport { createMockWindow, type MockWindow } from \"./window.mock\";\n\n/**\n * Mock adapters with full type information including mock-specific properties\n */\nexport interface MockExtensionAdapters {\n runtime: MockRuntime;\n storage: MockStorageArea;\n tabs: MockTabs;\n window: MockWindow;\n offscreen: MockOffscreen;\n contextMenus: MockContextMenus;\n fetch: MockFetch;\n logger: MockLogger;\n}\n\n/**\n * Convenience interface grouping Chrome-like mock APIs\n * Useful when tests need direct access to internal mock state\n */\nexport interface MockChrome {\n runtime: MockRuntime;\n storage: {\n local: MockStorageArea;\n };\n tabs: MockTabs;\n}\n\n/**\n * Create a mock Chrome object with grouped APIs\n * Use this when you need access to internal mock state (e.g., mockChrome.tabs._tabs)\n */\nexport function createMockChrome(): MockChrome {\n return {\n runtime: createMockRuntime(),\n storage: {\n local: createMockStorageArea(),\n },\n tabs: createMockTabs(),\n };\n}\n\n/**\n * Create a complete set of mock adapters for testing\n * Returns mock adapters with full type information\n */\nexport function createMockAdapters(): MockExtensionAdapters {\n return {\n runtime: createMockRuntime(),\n storage: createMockStorageArea(),\n tabs: createMockTabs(),\n window: createMockWindow(),\n offscreen: createMockOffscreen(),\n contextMenus: createMockContextMenus(),\n fetch: createMockFetch(),\n logger: createMockLogger({ silent: true }),\n };\n}\n\nexport type {\n MockContextMenus,\n MockFetch,\n MockLogger,\n MockOffscreen,\n MockPort,\n MockRuntime,\n MockStorageArea,\n MockTabs,\n MockWindow,\n};\n// Re-export individual mock factories and types for convenience\nexport {\n createMockContextMenus,\n createMockFetch,\n createMockLogger,\n createMockOffscreen,\n createMockPort,\n createMockRuntime,\n createMockStorageArea,\n createMockTabs,\n createMockWindow,\n};\n",
|
|
14
14
|
"import type { ExtensionMessage, RoutedMessage } from \"@fairfox/polly/types\";\n\n/**\n * Test utilities for extension testing\n */\n\nexport function createMockRoutedMessage<T extends ExtensionMessage>(\n payload: T,\n overrides?: Partial<Omit<RoutedMessage<T>, \"payload\">>\n): RoutedMessage<T> {\n return {\n id: overrides?.id || `msg-${Date.now()}-${Math.random()}`,\n source: overrides?.source || \"background\",\n targets: overrides?.targets || [\"content\"],\n tabId: overrides?.tabId,\n timestamp: overrides?.timestamp || Date.now(),\n payload,\n };\n}\n\nexport function waitFor(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function waitForCondition(\n condition: () => boolean,\n timeout = 1000,\n interval = 10\n): Promise<void> {\n const startTime = Date.now();\n while (!condition()) {\n if (Date.now() - startTime > timeout) {\n throw new Error(\"Condition not met within timeout\");\n }\n await waitFor(interval);\n }\n}\n\nexport function expectType<T>(_value: T): void {\n // Type assertion helper for compile-time checks\n}\n\n/**\n * No-op function for mocks that don't need to do anything\n * Use this instead of empty arrow functions to satisfy linter\n */\n// biome-ignore lint/suspicious/noEmptyBlockStatements: intentional no-op for mocks\nexport function noOp(): void {}\n\n/**\n * Async no-op function for async mocks that don't need to do anything\n * Use this instead of empty async arrow functions to satisfy linter\n */\n// biome-ignore lint/suspicious/noEmptyBlockStatements: intentional no-op for mocks\nexport async function noOpAsync(): Promise<void> {}\n"
|
|
15
15
|
],
|
|
16
|
-
"mappings": "
|
|
17
|
-
"debugId": "
|
|
16
|
+
"mappings": "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",
|
|
17
|
+
"debugId": "91CFEC8B98E4A03564756E2164756E21",
|
|
18
18
|
"names": []
|
|
19
19
|
}
|
|
@@ -2,27 +2,37 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
-
|
|
5
|
+
function __accessProp(key) {
|
|
6
|
+
return this[key];
|
|
7
|
+
}
|
|
6
8
|
var __toCommonJS = (from) => {
|
|
7
|
-
var entry = __moduleCache.get(from), desc;
|
|
9
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
8
10
|
if (entry)
|
|
9
11
|
return entry;
|
|
10
12
|
entry = __defProp({}, "__esModule", { value: true });
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function")
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (var key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(entry, key))
|
|
16
|
+
__defProp(entry, key, {
|
|
17
|
+
get: __accessProp.bind(from, key),
|
|
18
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
19
|
+
});
|
|
20
|
+
}
|
|
16
21
|
__moduleCache.set(from, entry);
|
|
17
22
|
return entry;
|
|
18
23
|
};
|
|
24
|
+
var __moduleCache;
|
|
25
|
+
var __returnValue = (v) => v;
|
|
26
|
+
function __exportSetter(name, newValue) {
|
|
27
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
28
|
+
}
|
|
19
29
|
var __export = (target, all) => {
|
|
20
30
|
for (var name in all)
|
|
21
31
|
__defProp(target, name, {
|
|
22
32
|
get: all[name],
|
|
23
33
|
enumerable: true,
|
|
24
34
|
configurable: true,
|
|
25
|
-
set: (
|
|
35
|
+
set: __exportSetter.bind(all, name)
|
|
26
36
|
});
|
|
27
37
|
};
|
|
28
38
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
@@ -69,4 +79,4 @@ export {
|
|
|
69
79
|
createMockRoutedMessage
|
|
70
80
|
};
|
|
71
81
|
|
|
72
|
-
//# debugId=
|
|
82
|
+
//# debugId=F3DADC6218C5A2D464756E2164756E21
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"import type { ExtensionMessage, RoutedMessage } from \"@fairfox/polly/types\";\n\n/**\n * Test utilities for extension testing\n */\n\nexport function createMockRoutedMessage<T extends ExtensionMessage>(\n payload: T,\n overrides?: Partial<Omit<RoutedMessage<T>, \"payload\">>\n): RoutedMessage<T> {\n return {\n id: overrides?.id || `msg-${Date.now()}-${Math.random()}`,\n source: overrides?.source || \"background\",\n targets: overrides?.targets || [\"content\"],\n tabId: overrides?.tabId,\n timestamp: overrides?.timestamp || Date.now(),\n payload,\n };\n}\n\nexport function waitFor(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function waitForCondition(\n condition: () => boolean,\n timeout = 1000,\n interval = 10\n): Promise<void> {\n const startTime = Date.now();\n while (!condition()) {\n if (Date.now() - startTime > timeout) {\n throw new Error(\"Condition not met within timeout\");\n }\n await waitFor(interval);\n }\n}\n\nexport function expectType<T>(_value: T): void {\n // Type assertion helper for compile-time checks\n}\n\n/**\n * No-op function for mocks that don't need to do anything\n * Use this instead of empty arrow functions to satisfy linter\n */\n// biome-ignore lint/suspicious/noEmptyBlockStatements: intentional no-op for mocks\nexport function noOp(): void {}\n\n/**\n * Async no-op function for async mocks that don't need to do anything\n * Use this instead of empty async arrow functions to satisfy linter\n */\n// biome-ignore lint/suspicious/noEmptyBlockStatements: intentional no-op for mocks\nexport async function noOpAsync(): Promise<void> {}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMO,SAAS,uBAAmD,CACjE,SACA,WACkB;AAAA,EAClB,OAAO;AAAA,IACL,IAAI,WAAW,MAAM,OAAO,KAAK,IAAI,KAAK,KAAK,OAAO;AAAA,IACtD,QAAQ,WAAW,UAAU;AAAA,IAC7B,SAAS,WAAW,WAAW,CAAC,SAAS;AAAA,IACzC,OAAO,WAAW;AAAA,IAClB,WAAW,WAAW,aAAa,KAAK,IAAI;AAAA,IAC5C;AAAA,EACF;AAAA;AAGK,SAAS,OAAO,CAAC,IAA2B;AAAA,EACjD,OAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAAA;AAGzD,eAAsB,gBAAgB,CACpC,WACA,UAAU,MACV,WAAW,IACI;AAAA,EACf,MAAM,YAAY,KAAK,IAAI;AAAA,EAC3B,OAAO,CAAC,UAAU,GAAG;AAAA,IACnB,IAAI,KAAK,IAAI,IAAI,YAAY,SAAS;AAAA,MACpC,MAAM,IAAI,MAAM,kCAAkC;AAAA,IACpD;AAAA,IACA,MAAM,QAAQ,QAAQ;AAAA,EACxB;AAAA;AAGK,SAAS,UAAa,CAAC,QAAiB;AASxC,SAAS,IAAI,GAAS;AAO7B,eAAsB,SAAS,GAAkB;",
|
|
8
|
+
"debugId": "F3DADC6218C5A2D464756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
|
+
var __returnValue = (v) => v;
|
|
5
|
+
function __exportSetter(name, newValue) {
|
|
6
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
7
|
+
}
|
|
4
8
|
var __export = (target, all) => {
|
|
5
9
|
for (var name in all)
|
|
6
10
|
__defProp(target, name, {
|
|
7
11
|
get: all[name],
|
|
8
12
|
enumerable: true,
|
|
9
13
|
configurable: true,
|
|
10
|
-
set: (
|
|
14
|
+
set: __exportSetter.bind(all, name)
|
|
11
15
|
});
|
|
12
16
|
};
|
|
13
17
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
@@ -1362,13 +1366,25 @@ var init_tla = __esm(() => {
|
|
|
1362
1366
|
if (assignment.value !== null)
|
|
1363
1367
|
return true;
|
|
1364
1368
|
const fieldConfig = state[assignment.field];
|
|
1365
|
-
|
|
1369
|
+
if (!fieldConfig || typeof fieldConfig !== "object")
|
|
1370
|
+
return false;
|
|
1371
|
+
if ("abstract" in fieldConfig && fieldConfig.abstract)
|
|
1372
|
+
return true;
|
|
1373
|
+
if ("nullable" in fieldConfig && fieldConfig.nullable)
|
|
1374
|
+
return true;
|
|
1375
|
+
return !!(("values" in fieldConfig) && fieldConfig.values);
|
|
1366
1376
|
}
|
|
1367
1377
|
mapNullAssignment(assignment, state) {
|
|
1368
1378
|
if (assignment.value !== null)
|
|
1369
1379
|
return assignment;
|
|
1370
1380
|
const fieldConfig = state[assignment.field];
|
|
1371
|
-
if (fieldConfig
|
|
1381
|
+
if (!fieldConfig || typeof fieldConfig !== "object")
|
|
1382
|
+
return assignment;
|
|
1383
|
+
if ("abstract" in fieldConfig && fieldConfig.abstract)
|
|
1384
|
+
return assignment;
|
|
1385
|
+
if ("nullable" in fieldConfig && fieldConfig.nullable)
|
|
1386
|
+
return assignment;
|
|
1387
|
+
if ("values" in fieldConfig && fieldConfig.values) {
|
|
1372
1388
|
const nullValue = fieldConfig.values[fieldConfig.values.length - 1];
|
|
1373
1389
|
return { ...assignment, value: nullValue };
|
|
1374
1390
|
}
|
|
@@ -2069,6 +2085,9 @@ var init_tla = __esm(() => {
|
|
|
2069
2085
|
}
|
|
2070
2086
|
tryAbstractType(fieldConfig) {
|
|
2071
2087
|
if ("abstract" in fieldConfig && fieldConfig.abstract === true) {
|
|
2088
|
+
if ("nullable" in fieldConfig && fieldConfig.nullable === true) {
|
|
2089
|
+
return "Value \\union {NULL}";
|
|
2090
|
+
}
|
|
2072
2091
|
return "Value";
|
|
2073
2092
|
}
|
|
2074
2093
|
return null;
|
|
@@ -2236,6 +2255,9 @@ var init_tla = __esm(() => {
|
|
|
2236
2255
|
}
|
|
2237
2256
|
getInitialValue(fieldConfig) {
|
|
2238
2257
|
if ("abstract" in fieldConfig && fieldConfig.abstract === true) {
|
|
2258
|
+
if ("nullable" in fieldConfig && fieldConfig.nullable === true) {
|
|
2259
|
+
return "NULL";
|
|
2260
|
+
}
|
|
2239
2261
|
return '"v1"';
|
|
2240
2262
|
}
|
|
2241
2263
|
if (Array.isArray(fieldConfig)) {
|
|
@@ -2927,7 +2949,7 @@ class ConfigGenerator {
|
|
|
2927
2949
|
this.addHeader();
|
|
2928
2950
|
this.addImports();
|
|
2929
2951
|
this.addExport();
|
|
2930
|
-
this.addStateConfig(analysis.fields);
|
|
2952
|
+
this.addStateConfig(analysis.fields, analysis.resources);
|
|
2931
2953
|
this.addMessagesConfig();
|
|
2932
2954
|
this.addBehaviorConfig();
|
|
2933
2955
|
this.closeExport();
|
|
@@ -2993,7 +3015,7 @@ class ConfigGenerator {
|
|
|
2993
3015
|
this.indent--;
|
|
2994
3016
|
this.line("})");
|
|
2995
3017
|
}
|
|
2996
|
-
addStateConfig(fields) {
|
|
3018
|
+
addStateConfig(fields, resources) {
|
|
2997
3019
|
this.line("state: {");
|
|
2998
3020
|
this.indent++;
|
|
2999
3021
|
for (let i = 0;i < fields.length; i++) {
|
|
@@ -3005,6 +3027,18 @@ class ConfigGenerator {
|
|
|
3005
3027
|
}
|
|
3006
3028
|
this.addFieldConfig(field);
|
|
3007
3029
|
}
|
|
3030
|
+
if (resources && resources.length > 0) {
|
|
3031
|
+
if (fields.length > 0) {
|
|
3032
|
+
this.line("");
|
|
3033
|
+
}
|
|
3034
|
+
this.line("// ─── $resource async lifecycle fields (auto-generated) ───");
|
|
3035
|
+
for (const resource of resources) {
|
|
3036
|
+
this.line("");
|
|
3037
|
+
this.line(`// ${resource.name}: fetch lifecycle status`);
|
|
3038
|
+
this.line(`"${resource.name}_status": { type: "enum", values: ["idle", "loading", "success", "error"] },`);
|
|
3039
|
+
this.line(`"${resource.name}_error": { type: "boolean" },`);
|
|
3040
|
+
}
|
|
3041
|
+
}
|
|
3008
3042
|
this.indent--;
|
|
3009
3043
|
this.line("},");
|
|
3010
3044
|
this.line("");
|
|
@@ -3141,8 +3175,8 @@ class ConfigGenerator {
|
|
|
3141
3175
|
}
|
|
3142
3176
|
generateNumberFieldConfig(field) {
|
|
3143
3177
|
if (field.bounds?.min !== undefined && field.bounds?.max !== undefined) {
|
|
3144
|
-
const minStr = field.bounds.min
|
|
3145
|
-
const maxStr = field.bounds.max
|
|
3178
|
+
const minStr = field.bounds.min === null ? "/* CONFIGURE */" : field.bounds.min;
|
|
3179
|
+
const maxStr = field.bounds.max === null ? "/* CONFIGURE */" : field.bounds.max;
|
|
3146
3180
|
if (field.confidence === "high") {
|
|
3147
3181
|
return `{ min: ${minStr}, max: ${maxStr} }`;
|
|
3148
3182
|
}
|
|
@@ -4335,12 +4369,13 @@ class HandlerExtractor {
|
|
|
4335
4369
|
const stateConstraints = [];
|
|
4336
4370
|
const globalStateConstraints = [];
|
|
4337
4371
|
const verifiedStates = [];
|
|
4372
|
+
const resources = [];
|
|
4338
4373
|
this.warnings = [];
|
|
4339
4374
|
const allSourceFiles = this.project.getSourceFiles();
|
|
4340
4375
|
const entryPoints = allSourceFiles.filter((f) => this.isWithinPackage(f.getFilePath()));
|
|
4341
4376
|
this.debugLogSourceFiles(allSourceFiles, entryPoints);
|
|
4342
4377
|
for (const entryPoint of entryPoints) {
|
|
4343
|
-
this.analyzeFileAndImports(entryPoint, handlers, messageTypes, invalidMessageTypes, stateConstraints, globalStateConstraints, verifiedStates);
|
|
4378
|
+
this.analyzeFileAndImports(entryPoint, handlers, messageTypes, invalidMessageTypes, stateConstraints, globalStateConstraints, verifiedStates, resources);
|
|
4344
4379
|
}
|
|
4345
4380
|
if (verifiedStates.length > 0) {
|
|
4346
4381
|
if (process.env["POLLY_DEBUG"]) {
|
|
@@ -4372,10 +4407,11 @@ class HandlerExtractor {
|
|
|
4372
4407
|
stateConstraints,
|
|
4373
4408
|
globalStateConstraints,
|
|
4374
4409
|
verifiedStates,
|
|
4410
|
+
resources,
|
|
4375
4411
|
warnings: this.warnings
|
|
4376
4412
|
};
|
|
4377
4413
|
}
|
|
4378
|
-
analyzeFileAndImports(sourceFile, handlers, messageTypes, invalidMessageTypes, stateConstraints, globalStateConstraints, verifiedStates) {
|
|
4414
|
+
analyzeFileAndImports(sourceFile, handlers, messageTypes, invalidMessageTypes, stateConstraints, globalStateConstraints, verifiedStates, resources) {
|
|
4379
4415
|
const filePath = sourceFile.getFilePath();
|
|
4380
4416
|
if (this.analyzedFiles.has(filePath)) {
|
|
4381
4417
|
return;
|
|
@@ -4393,6 +4429,20 @@ class HandlerExtractor {
|
|
|
4393
4429
|
globalStateConstraints.push(...fileGlobalConstraints);
|
|
4394
4430
|
const fileVerifiedStates = this.extractVerifiedStatesFromFile(sourceFile);
|
|
4395
4431
|
verifiedStates.push(...fileVerifiedStates);
|
|
4432
|
+
const fileResources = this.extractResourcesFromFile(sourceFile, filePath);
|
|
4433
|
+
for (const resource of fileResources) {
|
|
4434
|
+
resources.push(resource);
|
|
4435
|
+
const context = this.inferContext(filePath);
|
|
4436
|
+
const syntheticHandlers = this.createResourceHandlers(resource, context);
|
|
4437
|
+
for (const handler of syntheticHandlers) {
|
|
4438
|
+
handlers.push(handler);
|
|
4439
|
+
if (this.isValidTLAIdentifier(handler.messageType)) {
|
|
4440
|
+
messageTypes.add(handler.messageType);
|
|
4441
|
+
} else {
|
|
4442
|
+
invalidMessageTypes.add(handler.messageType);
|
|
4443
|
+
}
|
|
4444
|
+
}
|
|
4445
|
+
}
|
|
4396
4446
|
const importDeclarations = sourceFile.getImportDeclarations();
|
|
4397
4447
|
for (const importDecl of importDeclarations) {
|
|
4398
4448
|
const importedFile = importDecl.getModuleSpecifierSourceFile();
|
|
@@ -4404,7 +4454,7 @@ class HandlerExtractor {
|
|
|
4404
4454
|
}
|
|
4405
4455
|
continue;
|
|
4406
4456
|
}
|
|
4407
|
-
this.analyzeFileAndImports(importedFile, handlers, messageTypes, invalidMessageTypes, stateConstraints, globalStateConstraints, verifiedStates);
|
|
4457
|
+
this.analyzeFileAndImports(importedFile, handlers, messageTypes, invalidMessageTypes, stateConstraints, globalStateConstraints, verifiedStates, resources);
|
|
4408
4458
|
} else if (process.env["POLLY_DEBUG"]) {
|
|
4409
4459
|
const specifier = importDecl.getModuleSpecifierValue();
|
|
4410
4460
|
if (!specifier.startsWith("node:") && !this.isNodeModuleImport(specifier)) {
|
|
@@ -6294,6 +6344,125 @@ class HandlerExtractor {
|
|
|
6294
6344
|
}
|
|
6295
6345
|
return name || funcName;
|
|
6296
6346
|
}
|
|
6347
|
+
extractResourcesFromFile(sourceFile, filePath) {
|
|
6348
|
+
const resources = [];
|
|
6349
|
+
sourceFile.forEachDescendant((node) => {
|
|
6350
|
+
if (!Node2.isCallExpression(node))
|
|
6351
|
+
return;
|
|
6352
|
+
const resource = this.extractResourcePattern(node, filePath);
|
|
6353
|
+
if (resource) {
|
|
6354
|
+
resources.push(resource);
|
|
6355
|
+
}
|
|
6356
|
+
});
|
|
6357
|
+
return resources;
|
|
6358
|
+
}
|
|
6359
|
+
extractResourcePattern(node, filePath) {
|
|
6360
|
+
const expression = node.getExpression();
|
|
6361
|
+
if (!Node2.isIdentifier(expression))
|
|
6362
|
+
return null;
|
|
6363
|
+
if (expression.getText() !== "$resource")
|
|
6364
|
+
return null;
|
|
6365
|
+
const args = node.getArguments();
|
|
6366
|
+
if (args.length < 2)
|
|
6367
|
+
return null;
|
|
6368
|
+
const nameArg = args[0];
|
|
6369
|
+
if (!nameArg || !Node2.isStringLiteral(nameArg))
|
|
6370
|
+
return null;
|
|
6371
|
+
const name = nameArg.getLiteralValue();
|
|
6372
|
+
const optionsArg = args[1];
|
|
6373
|
+
if (!optionsArg || !Node2.isObjectLiteralExpression(optionsArg))
|
|
6374
|
+
return null;
|
|
6375
|
+
const sourceSignals = this.extractResourceSourceReads(optionsArg);
|
|
6376
|
+
const variableName = this.getVariableNameFromParent(node) || name;
|
|
6377
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
6378
|
+
console.log(`[DEBUG] Found $resource: ${variableName} (name: "${name}") with source signals: [${sourceSignals.join(", ")}]`);
|
|
6379
|
+
}
|
|
6380
|
+
return {
|
|
6381
|
+
name,
|
|
6382
|
+
variableName,
|
|
6383
|
+
filePath,
|
|
6384
|
+
line: node.getStartLineNumber(),
|
|
6385
|
+
sourceSignals
|
|
6386
|
+
};
|
|
6387
|
+
}
|
|
6388
|
+
extractResourceSourceReads(optionsObj) {
|
|
6389
|
+
const signals = [];
|
|
6390
|
+
const sourceProp = optionsObj.getProperty("source");
|
|
6391
|
+
if (!sourceProp || !Node2.isPropertyAssignment(sourceProp))
|
|
6392
|
+
return signals;
|
|
6393
|
+
const sourceInit = sourceProp.getInitializer();
|
|
6394
|
+
if (!sourceInit)
|
|
6395
|
+
return signals;
|
|
6396
|
+
sourceInit.forEachDescendant((node) => {
|
|
6397
|
+
if (!Node2.isPropertyAccessExpression(node))
|
|
6398
|
+
return;
|
|
6399
|
+
const text = node.getText();
|
|
6400
|
+
const match = text.match(/^(\w+)\.value(?:\.(\w+))?$/);
|
|
6401
|
+
if (match) {
|
|
6402
|
+
const signalName = match[1];
|
|
6403
|
+
const fieldName = match[2];
|
|
6404
|
+
if (fieldName) {
|
|
6405
|
+
signals.push(`${signalName}_${fieldName}`);
|
|
6406
|
+
} else {
|
|
6407
|
+
signals.push(signalName);
|
|
6408
|
+
}
|
|
6409
|
+
}
|
|
6410
|
+
});
|
|
6411
|
+
return signals;
|
|
6412
|
+
}
|
|
6413
|
+
createResourceHandlers(resource, context) {
|
|
6414
|
+
const { name, filePath, line } = resource;
|
|
6415
|
+
const location = { file: filePath, line };
|
|
6416
|
+
const fetchStart = {
|
|
6417
|
+
messageType: `${name}_FetchStart`,
|
|
6418
|
+
node: context,
|
|
6419
|
+
assignments: [
|
|
6420
|
+
{ field: `${name}_status`, value: "loading" },
|
|
6421
|
+
{ field: `${name}_error`, value: false }
|
|
6422
|
+
],
|
|
6423
|
+
preconditions: [
|
|
6424
|
+
{
|
|
6425
|
+
expression: `${name}_status !== "loading"`,
|
|
6426
|
+
location: { line, column: 0 }
|
|
6427
|
+
}
|
|
6428
|
+
],
|
|
6429
|
+
postconditions: [],
|
|
6430
|
+
location
|
|
6431
|
+
};
|
|
6432
|
+
const fetchSuccess = {
|
|
6433
|
+
messageType: `${name}_FetchSuccess`,
|
|
6434
|
+
node: context,
|
|
6435
|
+
assignments: [
|
|
6436
|
+
{ field: `${name}_status`, value: "success" },
|
|
6437
|
+
{ field: `${name}_error`, value: false }
|
|
6438
|
+
],
|
|
6439
|
+
preconditions: [
|
|
6440
|
+
{
|
|
6441
|
+
expression: `${name}_status === "loading"`,
|
|
6442
|
+
location: { line, column: 0 }
|
|
6443
|
+
}
|
|
6444
|
+
],
|
|
6445
|
+
postconditions: [],
|
|
6446
|
+
location
|
|
6447
|
+
};
|
|
6448
|
+
const fetchError = {
|
|
6449
|
+
messageType: `${name}_FetchError`,
|
|
6450
|
+
node: context,
|
|
6451
|
+
assignments: [
|
|
6452
|
+
{ field: `${name}_status`, value: "error" },
|
|
6453
|
+
{ field: `${name}_error`, value: true }
|
|
6454
|
+
],
|
|
6455
|
+
preconditions: [
|
|
6456
|
+
{
|
|
6457
|
+
expression: `${name}_status === "loading"`,
|
|
6458
|
+
location: { line, column: 0 }
|
|
6459
|
+
}
|
|
6460
|
+
],
|
|
6461
|
+
postconditions: [],
|
|
6462
|
+
location
|
|
6463
|
+
};
|
|
6464
|
+
return [fetchStart, fetchSuccess, fetchError];
|
|
6465
|
+
}
|
|
6297
6466
|
}
|
|
6298
6467
|
|
|
6299
6468
|
// tools/analysis/src/extract/types.ts
|
|
@@ -6327,7 +6496,9 @@ class TypeExtractor {
|
|
|
6327
6496
|
fields,
|
|
6328
6497
|
handlers: completeHandlers,
|
|
6329
6498
|
stateConstraints: handlerAnalysis.stateConstraints,
|
|
6330
|
-
globalStateConstraints: handlerAnalysis.globalStateConstraints
|
|
6499
|
+
globalStateConstraints: handlerAnalysis.globalStateConstraints,
|
|
6500
|
+
verifiedStates: handlerAnalysis.verifiedStates,
|
|
6501
|
+
resources: handlerAnalysis.resources
|
|
6331
6502
|
};
|
|
6332
6503
|
}
|
|
6333
6504
|
extractHandlerAnalysis() {
|
|
@@ -6920,7 +7091,7 @@ function displayEstimate(estimate) {
|
|
|
6920
7091
|
console.log(` Field combinations: ${color(String(estimate.fieldProduct), COLORS.green)}`);
|
|
6921
7092
|
console.log(` Handlers: ${estimate.handlerCount}`);
|
|
6922
7093
|
console.log(` Max in-flight: ${estimate.maxInFlight}`);
|
|
6923
|
-
console.log(` Contexts: ${estimate.contextCount} (${estimate.contextCount - 1} tab${estimate.contextCount - 1
|
|
7094
|
+
console.log(` Contexts: ${estimate.contextCount} (${estimate.contextCount - 1} tab${estimate.contextCount - 1 === 1 ? "" : "s"} + background)`);
|
|
6924
7095
|
console.log(` Interleaving factor: ${estimate.interleavingFactor}`);
|
|
6925
7096
|
console.log();
|
|
6926
7097
|
console.log(` Estimated states: ${color(`~${estimate.estimatedStates.toLocaleString()}`, COLORS.green)}`);
|
|
@@ -7178,7 +7349,7 @@ function displayCompositionalReport(results, nonInterferenceValid) {
|
|
|
7178
7349
|
for (const r of results) {
|
|
7179
7350
|
const status = r.success ? color("✓", COLORS.green) : color("✗", COLORS.red);
|
|
7180
7351
|
const name = r.name.padEnd(20);
|
|
7181
|
-
const handlers = `${r.handlerCount} handler${r.handlerCount
|
|
7352
|
+
const handlers = `${r.handlerCount} handler${r.handlerCount === 1 ? "" : "s"}`;
|
|
7182
7353
|
const states = `${r.stateCount} states`;
|
|
7183
7354
|
const time = `${r.elapsed.toFixed(1)}s`;
|
|
7184
7355
|
console.log(` ${status} ${name} ${handlers.padEnd(14)} ${states.padEnd(14)} ${time}`);
|
|
@@ -7422,4 +7593,4 @@ main().catch((error) => {
|
|
|
7422
7593
|
process.exit(1);
|
|
7423
7594
|
});
|
|
7424
7595
|
|
|
7425
|
-
//# debugId=
|
|
7596
|
+
//# debugId=D76A624F754502DE64756E2164756E21
|