@heal-dev/heal-playwright-tracer 1.0.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/LICENSE +661 -0
- package/README.md +245 -0
- package/dist/application/babel-playwright-tracer-plugin/index.d.ts +16 -0
- package/dist/application/babel-playwright-tracer-plugin/index.js +111 -0
- package/dist/application/heal-config/index.d.ts +8 -0
- package/dist/application/heal-config/index.js +22 -0
- package/dist/application/heal-config/registry.d.ts +37 -0
- package/dist/application/heal-config/registry.js +64 -0
- package/dist/application/heal-config/types.d.ts +73 -0
- package/dist/application/heal-config/types.js +7 -0
- package/dist/application/playwright-fixture/index.d.ts +14 -0
- package/dist/application/playwright-fixture/index.js +234 -0
- package/dist/application/trace-event-recorder-runtime/index.d.ts +15 -0
- package/dist/application/trace-event-recorder-runtime/index.js +68 -0
- package/dist/domain/code-hook-injector/service/meta-fields/enclosing-scope-labeler.d.ts +12 -0
- package/dist/domain/code-hook-injector/service/meta-fields/enclosing-scope-labeler.js +53 -0
- package/dist/domain/code-hook-injector/service/meta-fields/leading-comment-extractor.d.ts +14 -0
- package/dist/domain/code-hook-injector/service/meta-fields/leading-comment-extractor.js +20 -0
- package/dist/domain/code-hook-injector/service/meta-fields/relative-file-path.d.ts +6 -0
- package/dist/domain/code-hook-injector/service/meta-fields/relative-file-path.js +57 -0
- package/dist/domain/code-hook-injector/service/meta-fields/source-snippet-extractor.d.ts +12 -0
- package/dist/domain/code-hook-injector/service/meta-fields/source-snippet-extractor.js +28 -0
- package/dist/domain/code-hook-injector/service/playwright-import-rewriter.d.ts +10 -0
- package/dist/domain/code-hook-injector/service/playwright-import-rewriter.js +21 -0
- package/dist/domain/code-hook-injector/service/statement-analysis/cjs-artifact-detector.d.ts +14 -0
- package/dist/domain/code-hook-injector/service/statement-analysis/cjs-artifact-detector.js +30 -0
- package/dist/domain/code-hook-injector/service/statement-analysis/for-head-declaration-detector.d.ts +10 -0
- package/dist/domain/code-hook-injector/service/statement-analysis/for-head-declaration-detector.js +18 -0
- package/dist/domain/code-hook-injector/service/statement-analysis/leaf-statement-classifier.d.ts +15 -0
- package/dist/domain/code-hook-injector/service/statement-analysis/leaf-statement-classifier.js +66 -0
- package/dist/domain/code-hook-injector/service/statement-analysis/non-wrappable-statement.d.ts +11 -0
- package/dist/domain/code-hook-injector/service/statement-analysis/non-wrappable-statement.js +20 -0
- package/dist/domain/code-hook-injector/service/trace-hook/enter-meta-literal.d.ts +20 -0
- package/dist/domain/code-hook-injector/service/trace-hook/enter-meta-literal.js +34 -0
- package/dist/domain/code-hook-injector/service/trace-hook/global-trace-call.d.ts +10 -0
- package/dist/domain/code-hook-injector/service/trace-hook/global-trace-call.js +16 -0
- package/dist/domain/code-hook-injector/service/trace-hook/try-finally-wrapper.d.ts +18 -0
- package/dist/domain/code-hook-injector/service/trace-hook/try-finally-wrapper.js +44 -0
- package/dist/domain/code-hook-injector/service/trace-hook/variable-declaration-hoister.d.ts +20 -0
- package/dist/domain/code-hook-injector/service/trace-hook/variable-declaration-hoister.js +27 -0
- package/dist/domain/code-hook-injector/service/traced-file-matcher.d.ts +10 -0
- package/dist/domain/code-hook-injector/service/traced-file-matcher.js +26 -0
- package/dist/domain/trace-event-recorder/model/enter-meta.d.ts +24 -0
- package/dist/domain/trace-event-recorder/model/enter-meta.js +7 -0
- package/dist/domain/trace-event-recorder/model/global-names.d.ts +8 -0
- package/dist/domain/trace-event-recorder/model/global-names.js +20 -0
- package/dist/domain/trace-event-recorder/model/serialized-error.d.ts +16 -0
- package/dist/domain/trace-event-recorder/model/serialized-error.js +7 -0
- package/dist/domain/trace-event-recorder/model/statement-trace-schema.d.ts +171 -0
- package/dist/domain/trace-event-recorder/model/statement-trace-schema.js +33 -0
- package/dist/domain/trace-event-recorder/model/trace-schema.d.ts +114 -0
- package/dist/domain/trace-event-recorder/model/trace-schema.js +16 -0
- package/dist/domain/trace-event-recorder/port/clock.d.ts +9 -0
- package/dist/domain/trace-event-recorder/port/clock.js +7 -0
- package/dist/domain/trace-event-recorder/port/heal-trace-exporter.d.ts +11 -0
- package/dist/domain/trace-event-recorder/port/heal-trace-exporter.js +7 -0
- package/dist/domain/trace-event-recorder/port/system-info-provider.d.ts +18 -0
- package/dist/domain/trace-event-recorder/port/system-info-provider.js +7 -0
- package/dist/domain/trace-event-recorder/port/trace-event-consumer.d.ts +11 -0
- package/dist/domain/trace-event-recorder/port/trace-event-consumer.js +7 -0
- package/dist/domain/trace-event-recorder/service/active-enter-stack.d.ts +15 -0
- package/dist/domain/trace-event-recorder/service/active-enter-stack.js +34 -0
- package/dist/domain/trace-event-recorder/service/event-builders/enter-event-builder.d.ts +8 -0
- package/dist/domain/trace-event-recorder/service/event-builders/enter-event-builder.js +37 -0
- package/dist/domain/trace-event-recorder/service/event-builders/meta-event-builder.d.ts +7 -0
- package/dist/domain/trace-event-recorder/service/event-builders/meta-event-builder.js +19 -0
- package/dist/domain/trace-event-recorder/service/event-builders/ok-event-builder.d.ts +7 -0
- package/dist/domain/trace-event-recorder/service/event-builders/ok-event-builder.js +27 -0
- package/dist/domain/trace-event-recorder/service/event-builders/throw-event-builder.d.ts +7 -0
- package/dist/domain/trace-event-recorder/service/event-builders/throw-event-builder.js +23 -0
- package/dist/domain/trace-event-recorder/service/exporters/composite-heal-trace-exporter.d.ts +12 -0
- package/dist/domain/trace-event-recorder/service/exporters/composite-heal-trace-exporter.js +32 -0
- package/dist/domain/trace-event-recorder/service/index.d.ts +10 -0
- package/dist/domain/trace-event-recorder/service/index.js +15 -0
- package/dist/domain/trace-event-recorder/service/projectors/index.d.ts +6 -0
- package/dist/domain/trace-event-recorder/service/projectors/index.js +10 -0
- package/dist/domain/trace-event-recorder/service/projectors/statement-projector.d.ts +26 -0
- package/dist/domain/trace-event-recorder/service/projectors/statement-projector.js +183 -0
- package/dist/domain/trace-event-recorder/service/serializers/error-serializer.d.ts +8 -0
- package/dist/domain/trace-event-recorder/service/serializers/error-serializer.js +49 -0
- package/dist/domain/trace-event-recorder/service/serializers/variable-snapshot-serializer.d.ts +7 -0
- package/dist/domain/trace-event-recorder/service/serializers/variable-snapshot-serializer.js +102 -0
- package/dist/domain/trace-event-recorder/service/trace-event-recorder-state.d.ts +19 -0
- package/dist/domain/trace-event-recorder/service/trace-event-recorder-state.js +7 -0
- package/dist/domain/trace-event-recorder/service/trace-event-recorder.d.ts +56 -0
- package/dist/domain/trace-event-recorder/service/trace-event-recorder.js +80 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +43 -0
- package/dist/infrastructure/ndjson-exporter-adapter/index.d.ts +6 -0
- package/dist/infrastructure/ndjson-exporter-adapter/index.js +10 -0
- package/dist/infrastructure/ndjson-exporter-adapter/ndjson-exporter.d.ts +13 -0
- package/dist/infrastructure/ndjson-exporter-adapter/ndjson-exporter.js +77 -0
- package/dist/infrastructure/perf-hooks-clock-adapter/index.d.ts +6 -0
- package/dist/infrastructure/perf-hooks-clock-adapter/index.js +10 -0
- package/dist/infrastructure/perf-hooks-clock-adapter/perf-hooks-clock.d.ts +11 -0
- package/dist/infrastructure/perf-hooks-clock-adapter/perf-hooks-clock.js +22 -0
- package/dist/infrastructure/playwright-locator-screenshot-adapter/assertion-wrapper.d.ts +6 -0
- package/dist/infrastructure/playwright-locator-screenshot-adapter/assertion-wrapper.js +109 -0
- package/dist/infrastructure/playwright-locator-screenshot-adapter/index.d.ts +9 -0
- package/dist/infrastructure/playwright-locator-screenshot-adapter/index.js +21 -0
- package/dist/infrastructure/playwright-locator-screenshot-adapter/locator-patch.d.ts +11 -0
- package/dist/infrastructure/playwright-locator-screenshot-adapter/locator-patch.js +79 -0
- package/dist/infrastructure/playwright-locator-screenshot-adapter/overlay-helpers.d.ts +15 -0
- package/dist/infrastructure/playwright-locator-screenshot-adapter/overlay-helpers.js +33 -0
- package/dist/infrastructure/playwright-locator-screenshot-adapter/screenshot-capture-session.d.ts +26 -0
- package/dist/infrastructure/playwright-locator-screenshot-adapter/screenshot-capture-session.js +125 -0
- package/dist/infrastructure/playwright-step-tracking-adapter/index.d.ts +7 -0
- package/dist/infrastructure/playwright-step-tracking-adapter/index.js +10 -0
- package/dist/infrastructure/playwright-step-tracking-adapter/playwright-step-tracking-adapter.d.ts +14 -0
- package/dist/infrastructure/playwright-step-tracking-adapter/playwright-step-tracking-adapter.js +51 -0
- package/dist/infrastructure/playwright-test-context-adapter/heal-tag-prefix.d.ts +25 -0
- package/dist/infrastructure/playwright-test-context-adapter/heal-tag-prefix.js +28 -0
- package/dist/infrastructure/playwright-test-context-adapter/index.d.ts +8 -0
- package/dist/infrastructure/playwright-test-context-adapter/index.js +12 -0
- package/dist/infrastructure/playwright-test-context-adapter/playwright-test-context-adapter.d.ts +19 -0
- package/dist/infrastructure/playwright-test-context-adapter/playwright-test-context-adapter.js +43 -0
- package/dist/infrastructure/stdout-capture-adapter/index.d.ts +7 -0
- package/dist/infrastructure/stdout-capture-adapter/index.js +10 -0
- package/dist/infrastructure/stdout-capture-adapter/stdout-capture-session.d.ts +20 -0
- package/dist/infrastructure/stdout-capture-adapter/stdout-capture-session.js +47 -0
- package/dist/infrastructure/system-info-adapter/index.d.ts +6 -0
- package/dist/infrastructure/system-info-adapter/index.js +10 -0
- package/dist/infrastructure/system-info-adapter/system-info-adapter.d.ts +12 -0
- package/dist/infrastructure/system-info-adapter/system-info-adapter.js +83 -0
- package/package.json +95 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright: (c) Myia SAS 2026.
|
|
4
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
5
|
+
* Please see the LICENSE file at the root of this repository
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.reset = exports.expect = exports.test = void 0;
|
|
42
|
+
// Composition root for the heal-playwright-tracer auto-fixture.
|
|
43
|
+
//
|
|
44
|
+
// Each feature owns its own setup/cleanup; this file is the shopping
|
|
45
|
+
// list. Reading top-to-bottom tells you everything the tracer does to
|
|
46
|
+
// a test and in what order.
|
|
47
|
+
//
|
|
48
|
+
// Built-in features wired here (always-on, OSS):
|
|
49
|
+
// - runtime (side-effect import installs globalThis.__heal_enter/__heal_ok/__heal_throw)
|
|
50
|
+
// - step-tracking → new PlaywrightStepTrackingAdapter(hooks).patch(test)
|
|
51
|
+
// - test-context → testContextAdapter.capture(testInfo)
|
|
52
|
+
// - locator-screenshots → startLocatorScreenshotCapture(page, outDir)
|
|
53
|
+
// - test-stdout-capture → new StdoutCaptureSession()
|
|
54
|
+
// - NDJSON exporter → default trace output to `heal-data/heal-traces.ndjson`
|
|
55
|
+
//
|
|
56
|
+
// User-extensible features (wired via `configureTracer(...)` from the
|
|
57
|
+
// host `playwright.config.ts`):
|
|
58
|
+
// - exporters → each factory returns a `HealTraceExporter` composed
|
|
59
|
+
// into a tee alongside the default NDJSON exporter
|
|
60
|
+
// - lifecycles → each entry exposes `setup(ctx)` + `teardown()`;
|
|
61
|
+
// setups run in declaration order at test start,
|
|
62
|
+
// teardowns in reverse order in `finally` (LIFO)
|
|
63
|
+
// - onTestTeardown(fn) → runtime registration, drained before
|
|
64
|
+
// lifecycle teardowns so SDKs still see any globals
|
|
65
|
+
// a lifecycle installed
|
|
66
|
+
//
|
|
67
|
+
// Output shape (per test): `heal-data/heal-traces.ndjson` — one
|
|
68
|
+
// HealTraceRecord per line. See
|
|
69
|
+
// `../../domain/trace-event-recorder/model/statement-trace-schema.ts`
|
|
70
|
+
// for the contract.
|
|
71
|
+
//
|
|
72
|
+
// Env toggles:
|
|
73
|
+
// HEAL_TRACE_NDJSON default on; set to `0`/`false`/`off` to disable.
|
|
74
|
+
//
|
|
75
|
+
// Any backend integration (HTTP shipping, APM bindings,
|
|
76
|
+
// telemetry-session setup, …) lives in user code and plugs in via
|
|
77
|
+
// `configureTracer`. The fixture knows nothing about any specific
|
|
78
|
+
// backend.
|
|
79
|
+
const fs = __importStar(require("fs"));
|
|
80
|
+
const path = __importStar(require("path"));
|
|
81
|
+
const test_1 = require("@playwright/test");
|
|
82
|
+
// Side-effect: installs `globalThis.__heal_enter/__heal_ok/__heal_throw`.
|
|
83
|
+
const trace_event_recorder_runtime_1 = require("../trace-event-recorder-runtime");
|
|
84
|
+
Object.defineProperty(exports, "reset", { enumerable: true, get: function () { return trace_event_recorder_runtime_1.reset; } });
|
|
85
|
+
const playwright_locator_screenshot_adapter_1 = require("../../infrastructure/playwright-locator-screenshot-adapter");
|
|
86
|
+
const projectors_1 = require("../../domain/trace-event-recorder/service/projectors");
|
|
87
|
+
const ndjson_exporter_adapter_1 = require("../../infrastructure/ndjson-exporter-adapter");
|
|
88
|
+
const service_1 = require("../../domain/trace-event-recorder/service");
|
|
89
|
+
const playwright_step_tracking_adapter_1 = require("../../infrastructure/playwright-step-tracking-adapter");
|
|
90
|
+
const playwright_test_context_adapter_1 = require("../../infrastructure/playwright-test-context-adapter");
|
|
91
|
+
const playwright_locator_screenshot_adapter_2 = require("../../infrastructure/playwright-locator-screenshot-adapter");
|
|
92
|
+
const stdout_capture_adapter_1 = require("../../infrastructure/stdout-capture-adapter");
|
|
93
|
+
const heal_config_1 = require("../heal-config");
|
|
94
|
+
// Wrap `expect` so any assertion made against a Locator gets a
|
|
95
|
+
// highlight screenshot stamped onto the active statement, the same
|
|
96
|
+
// way locator actions do. Non-locator assertions fall through.
|
|
97
|
+
const expect = (0, playwright_locator_screenshot_adapter_1.wrapExpect)(test_1.expect);
|
|
98
|
+
exports.expect = expect;
|
|
99
|
+
// All artifacts this package produces live under this subdirectory of
|
|
100
|
+
// `testInfo.outputDir`, so they stay segregated from Playwright's own
|
|
101
|
+
// output (screenshot/trace/video attachments).
|
|
102
|
+
const HEAL_DATA_SUBDIR = 'heal-data';
|
|
103
|
+
const NDJSON_FILENAME = 'heal-traces.ndjson';
|
|
104
|
+
function envFlag(name, defaultOn) {
|
|
105
|
+
const raw = process.env[name];
|
|
106
|
+
if (raw == null || raw === '')
|
|
107
|
+
return defaultOn;
|
|
108
|
+
const v = raw.toLowerCase();
|
|
109
|
+
if (v === '0' || v === 'false' || v === 'off' || v === 'no')
|
|
110
|
+
return false;
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
function buildHealTraceExporter(healDataDir, ctx) {
|
|
114
|
+
const legs = [];
|
|
115
|
+
if (envFlag('HEAL_TRACE_NDJSON', true)) {
|
|
116
|
+
legs.push(new ndjson_exporter_adapter_1.NdjsonExporter(path.join(healDataDir, NDJSON_FILENAME)));
|
|
117
|
+
}
|
|
118
|
+
const { exporters = [] } = (0, heal_config_1.getTracerConfig)();
|
|
119
|
+
for (const factory of exporters) {
|
|
120
|
+
try {
|
|
121
|
+
legs.push(factory(ctx));
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
console.error('[heal-playwright-tracer] exporter factory failed:', err);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (legs.length === 0) {
|
|
128
|
+
// Neither leg active — return a no-op exporter so the projector
|
|
129
|
+
// still runs without doing anything user-visible.
|
|
130
|
+
return { write() { }, async close() { } };
|
|
131
|
+
}
|
|
132
|
+
return legs.length === 1 ? legs[0] : new service_1.CompositeHealTraceExporter(legs);
|
|
133
|
+
}
|
|
134
|
+
// Composition-root singletons — one per process.
|
|
135
|
+
const testContextAdapter = new playwright_test_context_adapter_1.PlaywrightTestContextAdapter({ setContext: trace_event_recorder_runtime_1.setContext });
|
|
136
|
+
const stepTrackingAdapter = new playwright_step_tracking_adapter_1.PlaywrightStepTrackingAdapter({ pushStep: trace_event_recorder_runtime_1.pushStep, popStep: trace_event_recorder_runtime_1.popStep });
|
|
137
|
+
exports.test = test_1.test.extend({
|
|
138
|
+
_traceAuto: [
|
|
139
|
+
async ({ page }, use, testInfo) => {
|
|
140
|
+
const captured = testContextAdapter.capture(testInfo);
|
|
141
|
+
const healDataDir = path.join(testInfo.outputDir, HEAL_DATA_SUBDIR);
|
|
142
|
+
fs.mkdirSync(healDataDir, { recursive: true });
|
|
143
|
+
const tracerCtx = {
|
|
144
|
+
testInfo,
|
|
145
|
+
healDataDir,
|
|
146
|
+
transport: {
|
|
147
|
+
testId: captured.testId,
|
|
148
|
+
attempt: captured.attempt,
|
|
149
|
+
rootDir: testInfo.outputDir,
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
// Fresh output pipeline per test: build a HealTraceExporter (default
|
|
153
|
+
// NDJSON leg + any user-configured exporters), wrap it in a
|
|
154
|
+
// projector, install on the recorder, then reset() — which
|
|
155
|
+
// clears projector state and emits the test-header record via
|
|
156
|
+
// the buildMetaEvent call inside the recorder.
|
|
157
|
+
const output = buildHealTraceExporter(healDataDir, tracerCtx);
|
|
158
|
+
const projector = new projectors_1.StatementProjector(output);
|
|
159
|
+
(0, trace_event_recorder_runtime_1.setExporter)(projector);
|
|
160
|
+
(0, trace_event_recorder_runtime_1.reset)();
|
|
161
|
+
// Defensive: clear any teardown hooks that leaked from a
|
|
162
|
+
// previous test that crashed before drain ran.
|
|
163
|
+
(0, heal_config_1.resetTeardownHooks)();
|
|
164
|
+
const stopScreenshots = (0, playwright_locator_screenshot_adapter_2.startLocatorScreenshotCapture)(page, healDataDir, trace_event_recorder_runtime_1.setCurrentStatementScreenshot);
|
|
165
|
+
const stdoutSession = new stdout_capture_adapter_1.StdoutCaptureSession();
|
|
166
|
+
// Instantiate user-configured lifecycles for this test. Each
|
|
167
|
+
// factory runs fresh per test so any closure state the factory
|
|
168
|
+
// declares is isolated between tests. Setup failures are
|
|
169
|
+
// isolated: a lifecycle whose `setup` throws is NOT pushed onto
|
|
170
|
+
// `activeLifecycles`, so its `teardown` will not run. Later
|
|
171
|
+
// lifecycles still get a chance to set up.
|
|
172
|
+
const activeLifecycles = [];
|
|
173
|
+
const { lifecycles = [] } = (0, heal_config_1.getTracerConfig)();
|
|
174
|
+
for (const factory of lifecycles) {
|
|
175
|
+
try {
|
|
176
|
+
const lc = factory();
|
|
177
|
+
await lc.setup(tracerCtx);
|
|
178
|
+
activeLifecycles.push(lc);
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
console.error('[heal-playwright-tracer] lifecycle setup failed:', err);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
try {
|
|
185
|
+
await use();
|
|
186
|
+
}
|
|
187
|
+
finally {
|
|
188
|
+
// Run any teardown hooks registered during the test. Runs
|
|
189
|
+
// BEFORE lifecycle teardowns so hooks that log via an SDK
|
|
190
|
+
// still see the per-test globals a lifecycle installed, and
|
|
191
|
+
// BEFORE stopping stdout capture so SDK teardown output lands
|
|
192
|
+
// in the ndjson's `test-result.stdout/stderr`.
|
|
193
|
+
await (0, heal_config_1.drainTeardownHooks)();
|
|
194
|
+
// Teardown in reverse order (LIFO): the last lifecycle to set
|
|
195
|
+
// up is the first to tear down, matching the mental model of
|
|
196
|
+
// nested `using` blocks.
|
|
197
|
+
for (let i = activeLifecycles.length - 1; i >= 0; i--) {
|
|
198
|
+
try {
|
|
199
|
+
await activeLifecycles[i].teardown();
|
|
200
|
+
}
|
|
201
|
+
catch (err) {
|
|
202
|
+
console.error('[heal-playwright-tracer] lifecycle teardown failed:', err);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
const capturedStdout = stdoutSession.stop();
|
|
206
|
+
stopScreenshots();
|
|
207
|
+
// Emit the final test-result record and close the output
|
|
208
|
+
// exporter chain (flushes NDJSON fd, awaits in-flight
|
|
209
|
+
// user-exporter I/O). The projector has its own `finalized`
|
|
210
|
+
// guard that silently swallows any stray events fired after
|
|
211
|
+
// this point, so we do NOT swap the recorder's exporter back
|
|
212
|
+
// to a no-op — it stays pointed at the (now-finalized)
|
|
213
|
+
// projector until the next test installs a fresh one.
|
|
214
|
+
//
|
|
215
|
+
// Playwright-native artifacts (trace.zip, videos) are NOT
|
|
216
|
+
// shipped from here — their attachments are populated by
|
|
217
|
+
// Playwright in a later phase. Users who need them can
|
|
218
|
+
// register a Playwright reporter in their `playwright.config`.
|
|
219
|
+
await projector.finalize({
|
|
220
|
+
status: testInfo.status ?? 'passed',
|
|
221
|
+
duration: testInfo.duration,
|
|
222
|
+
stdout: capturedStdout.stdout.length ? capturedStdout.stdout : undefined,
|
|
223
|
+
stderr: capturedStdout.stderr.length ? capturedStdout.stderr : undefined,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
{ auto: true },
|
|
228
|
+
],
|
|
229
|
+
});
|
|
230
|
+
// Thread test.step titles onto the runtime step stack. Must run AFTER
|
|
231
|
+
// base.extend because Playwright's extend creates a fresh `.step` on
|
|
232
|
+
// the new test object that doesn't inherit from base — patching `base`
|
|
233
|
+
// first would never reach the extended test.
|
|
234
|
+
stepTrackingAdapter.patch(exports.test);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright: (c) Myia SAS 2026.
|
|
3
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
4
|
+
* Please see the LICENSE file at the root of this repository
|
|
5
|
+
*/
|
|
6
|
+
import { SCHEMA_VERSION } from '../../domain/trace-event-recorder/service';
|
|
7
|
+
import type { TraceEventConsumer } from '../../domain/trace-event-recorder/port/trace-event-consumer';
|
|
8
|
+
export declare const reset: () => void;
|
|
9
|
+
export declare const setContext: (ctx: Record<string, unknown> | null) => void;
|
|
10
|
+
export declare const setPage: (page: unknown | null) => void;
|
|
11
|
+
export declare const pushStep: (name: string) => void;
|
|
12
|
+
export declare const popStep: () => void;
|
|
13
|
+
export declare const setCurrentStatementScreenshot: (filename: string) => void;
|
|
14
|
+
export declare const setExporter: (newExporter: TraceEventConsumer) => void;
|
|
15
|
+
export { SCHEMA_VERSION };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright: (c) Myia SAS 2026.
|
|
4
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
5
|
+
* Please see the LICENSE file at the root of this repository
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.SCHEMA_VERSION = exports.setExporter = exports.setCurrentStatementScreenshot = exports.popStep = exports.pushStep = exports.setPage = exports.setContext = exports.reset = void 0;
|
|
9
|
+
// Composition root for the process-wide trace-event-recorder singleton.
|
|
10
|
+
//
|
|
11
|
+
// `domain/.../factory.ts` exports the `TraceEventRecorder` class —
|
|
12
|
+
// a pure service that requires exporter + clock + staticContext. This
|
|
13
|
+
// file is the thin wrapper that:
|
|
14
|
+
//
|
|
15
|
+
// 1. Wires the default Clock (PerfHooksClock) and the default
|
|
16
|
+
// SystemInfoProvider (SystemInfoAdapter — reads pid/os/git).
|
|
17
|
+
// 2. Builds one trace-event-recorder wired to `BOOTSTRAP_EXPORTER`
|
|
18
|
+
// (a no-op that silently swallows any events fired before the
|
|
19
|
+
// fixture swaps in a real projector via `setExporter(...)` at
|
|
20
|
+
// the start of every test).
|
|
21
|
+
// 3. Installs `globalThis.__heal_enter/__heal_ok/__heal_throw` so the
|
|
22
|
+
// Babel-inserted calls find them at runtime.
|
|
23
|
+
// 4. Re-exports the public API (`reset`, `setContext`, `setPage`,
|
|
24
|
+
// `pushStep`, `popStep`, `setCurrentStatementScreenshot`,
|
|
25
|
+
// `setExporter`) for the fixture and infrastructure adapters to
|
|
26
|
+
// import. The singleton shape is the integration surface between
|
|
27
|
+
// the always-on domain recorder and the per-test fixture.
|
|
28
|
+
//
|
|
29
|
+
// Tests do NOT import this file — they import the domain factory
|
|
30
|
+
// directly and inject stubs + a fake clock.
|
|
31
|
+
const service_1 = require("../../domain/trace-event-recorder/service");
|
|
32
|
+
Object.defineProperty(exports, "SCHEMA_VERSION", { enumerable: true, get: function () { return service_1.SCHEMA_VERSION; } });
|
|
33
|
+
const perf_hooks_clock_adapter_1 = require("../../infrastructure/perf-hooks-clock-adapter");
|
|
34
|
+
const system_info_adapter_1 = require("../../infrastructure/system-info-adapter");
|
|
35
|
+
const global_names_1 = require("../../domain/trace-event-recorder/model/global-names");
|
|
36
|
+
// See the header comment: the recorder is constructed at module load
|
|
37
|
+
// and MUST have an exporter from that moment so any pre-fixture
|
|
38
|
+
// `__heal_enter` call doesn't crash. The fixture replaces this with
|
|
39
|
+
// the real per-test projector via `setExporter(...)`.
|
|
40
|
+
const BOOTSTRAP_EXPORTER = {
|
|
41
|
+
write() { },
|
|
42
|
+
clear() { },
|
|
43
|
+
};
|
|
44
|
+
const systemInfo = new system_info_adapter_1.SystemInfoAdapter().getStaticContext();
|
|
45
|
+
const staticContext = {
|
|
46
|
+
schemaVersion: service_1.SCHEMA_VERSION,
|
|
47
|
+
...systemInfo,
|
|
48
|
+
};
|
|
49
|
+
const traceEventRecorder = new service_1.TraceEventRecorder({
|
|
50
|
+
exporter: BOOTSTRAP_EXPORTER,
|
|
51
|
+
clock: new perf_hooks_clock_adapter_1.PerfHooksClock(),
|
|
52
|
+
staticContext,
|
|
53
|
+
});
|
|
54
|
+
// Global-name contract lives in `domain/.../model/global-names.ts`,
|
|
55
|
+
// shared with the Babel plugin that emits calls to these names. The
|
|
56
|
+
// factory's internal method names (`__enter`, `__ok`, `__throw`) are
|
|
57
|
+
// unchanged — they never leak into user-facing code.
|
|
58
|
+
const g = globalThis;
|
|
59
|
+
g[global_names_1.HEAL_ENTER] = traceEventRecorder.__enter;
|
|
60
|
+
g[global_names_1.HEAL_OK] = traceEventRecorder.__ok;
|
|
61
|
+
g[global_names_1.HEAL_THROW] = traceEventRecorder.__throw;
|
|
62
|
+
exports.reset = traceEventRecorder.reset;
|
|
63
|
+
exports.setContext = traceEventRecorder.setContext;
|
|
64
|
+
exports.setPage = traceEventRecorder.setPage;
|
|
65
|
+
exports.pushStep = traceEventRecorder.pushStep;
|
|
66
|
+
exports.popStep = traceEventRecorder.popStep;
|
|
67
|
+
exports.setCurrentStatementScreenshot = traceEventRecorder.setCurrentStatementScreenshot;
|
|
68
|
+
exports.setExporter = traceEventRecorder.setExporter;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright: (c) Myia SAS 2026.
|
|
3
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
4
|
+
* Please see the LICENSE file at the root of this repository
|
|
5
|
+
*/
|
|
6
|
+
import type * as BabelTypes from '@babel/types';
|
|
7
|
+
import type { NodePath } from '@babel/traverse';
|
|
8
|
+
type Types = typeof BabelTypes;
|
|
9
|
+
export declare const TEST_API_NAMES: RegExp;
|
|
10
|
+
export type EnclosingScopeLabeler = (nodePath: NodePath) => string;
|
|
11
|
+
export declare function createEnclosingScopeLabeler(t: Types): EnclosingScopeLabeler;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright: (c) Myia SAS 2026.
|
|
4
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
5
|
+
* Please see the LICENSE file at the root of this repository
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.TEST_API_NAMES = void 0;
|
|
9
|
+
exports.createEnclosingScopeLabeler = createEnclosingScopeLabeler;
|
|
10
|
+
exports.TEST_API_NAMES = /^(test|it|describe|step|beforeEach|afterEach|beforeAll|afterAll)$/;
|
|
11
|
+
function createEnclosingScopeLabeler(t) {
|
|
12
|
+
return function labelEnclosingScope(nodePath) {
|
|
13
|
+
let p = nodePath.parentPath;
|
|
14
|
+
while (p) {
|
|
15
|
+
if (p.isFunction()) {
|
|
16
|
+
// ObjectMethod and ClassMethod ARE function nodes (not wrapped
|
|
17
|
+
// by one), so we check them on the current path itself, not on
|
|
18
|
+
// its parent. Must come BEFORE the named-function branch since
|
|
19
|
+
// those methods can also have a `.key` we want to surface.
|
|
20
|
+
if (p.isObjectMethod() || p.isClassMethod()) {
|
|
21
|
+
const key = p.node.key;
|
|
22
|
+
if (key && t.isIdentifier(key))
|
|
23
|
+
return key.name;
|
|
24
|
+
}
|
|
25
|
+
const fnNode = p.node;
|
|
26
|
+
if ('id' in fnNode && fnNode.id && fnNode.id.name)
|
|
27
|
+
return fnNode.id.name;
|
|
28
|
+
const parent = p.parentPath;
|
|
29
|
+
if (parent && parent.isCallExpression()) {
|
|
30
|
+
const callee = parent.node.callee;
|
|
31
|
+
let calleeName = '';
|
|
32
|
+
if (t.isIdentifier(callee))
|
|
33
|
+
calleeName = callee.name;
|
|
34
|
+
else if (t.isMemberExpression(callee) && t.isIdentifier(callee.property))
|
|
35
|
+
calleeName = callee.property.name;
|
|
36
|
+
if (exports.TEST_API_NAMES.test(calleeName)) {
|
|
37
|
+
const titleNode = parent.node.arguments[0];
|
|
38
|
+
if (titleNode && t.isStringLiteral(titleNode)) {
|
|
39
|
+
return `${calleeName}: ${titleNode.value}`;
|
|
40
|
+
}
|
|
41
|
+
return `${calleeName}()`;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (parent && parent.isVariableDeclarator() && t.isIdentifier(parent.node.id)) {
|
|
45
|
+
return parent.node.id.name;
|
|
46
|
+
}
|
|
47
|
+
return '<anonymous>';
|
|
48
|
+
}
|
|
49
|
+
p = p.parentPath;
|
|
50
|
+
}
|
|
51
|
+
return '<module>';
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright: (c) Myia SAS 2026.
|
|
3
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
4
|
+
* Please see the LICENSE file at the root of this repository
|
|
5
|
+
*/
|
|
6
|
+
interface BabelComment {
|
|
7
|
+
type: 'CommentLine' | 'CommentBlock';
|
|
8
|
+
value: string;
|
|
9
|
+
}
|
|
10
|
+
interface NodeLike {
|
|
11
|
+
leadingComments?: BabelComment[] | null;
|
|
12
|
+
}
|
|
13
|
+
export declare function extractLeadingComment(node: NodeLike | null | undefined): string | null;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright: (c) Myia SAS 2026.
|
|
4
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
5
|
+
* Please see the LICENSE file at the root of this repository
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.extractLeadingComment = extractLeadingComment;
|
|
9
|
+
function extractLeadingComment(node) {
|
|
10
|
+
const comments = node?.leadingComments;
|
|
11
|
+
if (!comments || comments.length === 0)
|
|
12
|
+
return null;
|
|
13
|
+
return comments.map((c) => stripOneSpace(c.value)).join('\n');
|
|
14
|
+
}
|
|
15
|
+
// Strip at most one leading and one trailing space. Not `.trim()` —
|
|
16
|
+
// that would destroy intentional indentation in JSDoc-style blocks
|
|
17
|
+
// where inner lines are `' * foo'`.
|
|
18
|
+
function stripOneSpace(value) {
|
|
19
|
+
return value.replace(/^ /, '').replace(/ $/, '');
|
|
20
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright: (c) Myia SAS 2026.
|
|
4
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
5
|
+
* Please see the LICENSE file at the root of this repository
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.relFile = relFile;
|
|
42
|
+
// Computes the `meta.file` field: a repo-relative path when the
|
|
43
|
+
// absolute filename lives under the instrumenter's `rootDir` (or
|
|
44
|
+
// process.cwd() by default), or the absolute path otherwise.
|
|
45
|
+
//
|
|
46
|
+
// Relative paths make traces portable across machines; falling back
|
|
47
|
+
// to absolute when the file is outside the root avoids generating
|
|
48
|
+
// broken `..`-prefixed paths that can't be resolved on the consumer
|
|
49
|
+
// side. Missing filenames collapse to `<anonymous>` so downstream
|
|
50
|
+
// code never has to null-check.
|
|
51
|
+
const path = __importStar(require("path"));
|
|
52
|
+
function relFile(cwd, absFile) {
|
|
53
|
+
if (!absFile)
|
|
54
|
+
return '<anonymous>';
|
|
55
|
+
const rel = path.relative(cwd, absFile);
|
|
56
|
+
return rel && !rel.startsWith('..') ? rel : absFile;
|
|
57
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright: (c) Myia SAS 2026.
|
|
3
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
4
|
+
* Please see the LICENSE file at the root of this repository
|
|
5
|
+
*/
|
|
6
|
+
export declare const DEFAULT_MAX_SOURCE_LEN = 200;
|
|
7
|
+
interface NodeLike {
|
|
8
|
+
start?: number | null;
|
|
9
|
+
end?: number | null;
|
|
10
|
+
}
|
|
11
|
+
export declare function extractSource(code: string | undefined | null, node: NodeLike | null | undefined, maxLen?: number): string;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright: (c) Myia SAS 2026.
|
|
4
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
5
|
+
* Please see the LICENSE file at the root of this repository
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.DEFAULT_MAX_SOURCE_LEN = void 0;
|
|
9
|
+
exports.extractSource = extractSource;
|
|
10
|
+
// Extracts the raw source text for a node, collapsed and length-capped.
|
|
11
|
+
//
|
|
12
|
+
// Produces the `meta.source` field on every __enter event. Slicing
|
|
13
|
+
// the original file between `node.start` and `node.end` is cheap and
|
|
14
|
+
// avoids re-printing the AST; collapsing whitespace keeps multi-line
|
|
15
|
+
// statements readable on a single trace line; the 200-char cap keeps
|
|
16
|
+
// long expressions from blowing up the trace buffer.
|
|
17
|
+
exports.DEFAULT_MAX_SOURCE_LEN = 200;
|
|
18
|
+
function extractSource(code, node, maxLen = exports.DEFAULT_MAX_SOURCE_LEN) {
|
|
19
|
+
const src = code || '';
|
|
20
|
+
if (!node || node.start == null || node.end == null)
|
|
21
|
+
return '';
|
|
22
|
+
let snippet = src.slice(node.start, node.end);
|
|
23
|
+
snippet = snippet.replace(/\s+/g, ' ').trim();
|
|
24
|
+
if (snippet.length > maxLen) {
|
|
25
|
+
snippet = snippet.slice(0, maxLen - 1) + '…';
|
|
26
|
+
}
|
|
27
|
+
return snippet;
|
|
28
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright: (c) Myia SAS 2026.
|
|
3
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
4
|
+
* Please see the LICENSE file at the root of this repository
|
|
5
|
+
*/
|
|
6
|
+
import type * as BabelTypes from '@babel/types';
|
|
7
|
+
type Types = typeof BabelTypes;
|
|
8
|
+
export type PlaywrightImportRewriter = (program: BabelTypes.Program) => void;
|
|
9
|
+
export declare function createPlaywrightImportRewriter(t: Types): PlaywrightImportRewriter;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright: (c) Myia SAS 2026.
|
|
4
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
5
|
+
* Please see the LICENSE file at the root of this repository
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.createPlaywrightImportRewriter = createPlaywrightImportRewriter;
|
|
9
|
+
const PLAYWRIGHT_IMPORT_SOURCE = '@playwright/test';
|
|
10
|
+
const REPLACEMENT_SOURCE = '@heal-dev/heal-playwright-tracer';
|
|
11
|
+
function createPlaywrightImportRewriter(t) {
|
|
12
|
+
return function rewritePlaywrightImports(program) {
|
|
13
|
+
for (const node of program.body) {
|
|
14
|
+
if (t.isImportDeclaration(node) &&
|
|
15
|
+
node.source &&
|
|
16
|
+
node.source.value === PLAYWRIGHT_IMPORT_SOURCE) {
|
|
17
|
+
node.source = t.stringLiteral(REPLACEMENT_SOURCE);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright: (c) Myia SAS 2026.
|
|
3
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
4
|
+
* Please see the LICENSE file at the root of this repository
|
|
5
|
+
*/
|
|
6
|
+
import type * as BabelTypes from '@babel/types';
|
|
7
|
+
type Types = typeof BabelTypes;
|
|
8
|
+
type Node = BabelTypes.Node;
|
|
9
|
+
export interface CjsArtifactDetector {
|
|
10
|
+
isRequireLike: (node: Node | null | undefined) => boolean;
|
|
11
|
+
isGeneratedModuleStatement: (node: Node) => boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function createCjsArtifactDetector(t: Types): CjsArtifactDetector;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright: (c) Myia SAS 2026.
|
|
4
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
5
|
+
* Please see the LICENSE file at the root of this repository
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.createCjsArtifactDetector = createCjsArtifactDetector;
|
|
9
|
+
function createCjsArtifactDetector(t) {
|
|
10
|
+
const isRequireLike = (node) => {
|
|
11
|
+
if (!node || !t.isCallExpression(node))
|
|
12
|
+
return false;
|
|
13
|
+
const callee = node.callee;
|
|
14
|
+
if (!t.isIdentifier(callee))
|
|
15
|
+
return false;
|
|
16
|
+
if (callee.name === 'require')
|
|
17
|
+
return true;
|
|
18
|
+
if (/^_interop/.test(callee.name) && node.arguments.length > 0) {
|
|
19
|
+
return isRequireLike(node.arguments[0]);
|
|
20
|
+
}
|
|
21
|
+
return false;
|
|
22
|
+
};
|
|
23
|
+
const isGeneratedModuleStatement = (node) => {
|
|
24
|
+
if (t.isVariableDeclaration(node)) {
|
|
25
|
+
return node.declarations.every((d) => isRequireLike(d.init));
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
};
|
|
29
|
+
return { isRequireLike, isGeneratedModuleStatement };
|
|
30
|
+
}
|
package/dist/domain/code-hook-injector/service/statement-analysis/for-head-declaration-detector.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright: (c) Myia SAS 2026.
|
|
3
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
4
|
+
* Please see the LICENSE file at the root of this repository
|
|
5
|
+
*/
|
|
6
|
+
import type * as BabelTypes from '@babel/types';
|
|
7
|
+
type Types = typeof BabelTypes;
|
|
8
|
+
export type ForHeadDeclarationDetector = (declaration: BabelTypes.VariableDeclaration, parent: BabelTypes.Node) => boolean;
|
|
9
|
+
export declare function createForHeadDeclarationDetector(t: Types): ForHeadDeclarationDetector;
|
|
10
|
+
export {};
|
package/dist/domain/code-hook-injector/service/statement-analysis/for-head-declaration-detector.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright: (c) Myia SAS 2026.
|
|
4
|
+
* This file and its contents are licensed under the AGPLv3 License.
|
|
5
|
+
* Please see the LICENSE file at the root of this repository
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.createForHeadDeclarationDetector = createForHeadDeclarationDetector;
|
|
9
|
+
function createForHeadDeclarationDetector(t) {
|
|
10
|
+
return function isForHeadDeclaration(declaration, parent) {
|
|
11
|
+
if (t.isForStatement(parent) && parent.init === declaration)
|
|
12
|
+
return true;
|
|
13
|
+
if ((t.isForInStatement(parent) || t.isForOfStatement(parent)) && parent.left === declaration) {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
return false;
|
|
17
|
+
};
|
|
18
|
+
}
|