deepline 0.2.53 → 0.2.55
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/bundling-sources/sdk/src/client.ts +17 -1
- package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +1 -1
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/sdk/src/types.ts +43 -1
- package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +30 -1
- package/dist/bundling-sources/shared_libs/play-runtime/cell-provenance.ts +231 -0
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +1094 -128
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +178 -9
- package/dist/bundling-sources/shared_libs/play-runtime/docflow-node-io.ts +634 -0
- package/dist/bundling-sources/shared_libs/play-runtime/docflow-observation.ts +64 -0
- package/dist/bundling-sources/shared_libs/play-runtime/dynamic-worker-version.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/execution-capabilities.ts +18 -0
- package/dist/bundling-sources/shared_libs/play-runtime/live-state-contract.ts +33 -0
- package/dist/bundling-sources/shared_libs/play-runtime/log-provenance.ts +251 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-node-scope.ts +160 -0
- package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +6 -0
- package/dist/bundling-sources/shared_libs/play-runtime/run-failure.ts +27 -0
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +43 -5
- package/dist/bundling-sources/shared_libs/play-runtime/run-snapshot-stream.ts +12 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/local-process.ts +26 -4
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-actions.ts +6 -1
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +83 -0
- package/dist/bundling-sources/shared_libs/play-runtime/worker-api-types.ts +3 -0
- package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +49 -1
- package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +375 -29
- package/dist/bundling-sources/shared_libs/plays/docflow-binding-owner.ts +636 -0
- package/dist/bundling-sources/shared_libs/plays/docflow-binding.ts +598 -0
- package/dist/bundling-sources/shared_libs/plays/docflow.ts +1645 -0
- package/dist/bundling-sources/shared_libs/plays/play-exports.ts +202 -0
- package/dist/bundling-sources/shared_libs/plays/static-pipeline.ts +16 -1
- package/dist/bundling-sources/shared_libs/plays/ts-ast.ts +48 -0
- package/dist/cli/index.js +994 -312
- package/dist/cli/index.mjs +994 -312
- package/dist/{compiler-manifest-Cj3--4ZJ.d.mts → compiler-manifest-Bl8kmLx9.d.mts} +118 -0
- package/dist/{compiler-manifest-Cj3--4ZJ.d.ts → compiler-manifest-Bl8kmLx9.d.ts} +118 -0
- package/dist/index.d.mts +47 -2
- package/dist/index.d.ts +47 -2
- package/dist/index.js +419 -59
- package/dist/index.mjs +419 -59
- package/dist/install-integrity.json +12 -2
- package/dist/plays/bundle-play-file.d.mts +2 -2
- package/dist/plays/bundle-play-file.d.ts +2 -2
- package/dist/plays/bundle-play-file.mjs +1361 -45
- package/package.json +1 -1
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
} from 'node:path';
|
|
15
15
|
import { builtinModules } from 'node:module';
|
|
16
16
|
import { Parser } from 'acorn';
|
|
17
|
-
import { tsPlugin } from 'acorn-typescript';
|
|
18
17
|
import { build, transformSync, type Message, type Plugin } from 'esbuild';
|
|
19
18
|
import {
|
|
20
19
|
PLAY_ARTIFACT_KINDS,
|
|
@@ -29,15 +28,39 @@ import type {
|
|
|
29
28
|
PlayRuntimeFeature,
|
|
30
29
|
} from '../artifact-types';
|
|
31
30
|
import { buildPlayContractCompatibility } from '../contracts';
|
|
31
|
+
import { parsePlayDocflowFile, type PlayDocflowBinding } from '../docflow';
|
|
32
|
+
import {
|
|
33
|
+
TypeScriptParser,
|
|
34
|
+
astArray,
|
|
35
|
+
astNodeBounds,
|
|
36
|
+
buildDocflowParentIndex,
|
|
37
|
+
docflowExpressionWrapsStepBuilder,
|
|
38
|
+
docflowOutputRoot,
|
|
39
|
+
findDocflowBoundStatement,
|
|
40
|
+
isAstNode,
|
|
41
|
+
resolveDocflowBinding,
|
|
42
|
+
sourceLineStarts,
|
|
43
|
+
type AstNode,
|
|
44
|
+
} from '../docflow-binding';
|
|
45
|
+
export {
|
|
46
|
+
collectDocflowBindingDrift,
|
|
47
|
+
resolveDocflowBindingLines,
|
|
48
|
+
resolveDocflowBindingSymbol,
|
|
49
|
+
type DocflowBindingDriftDetail,
|
|
50
|
+
type DocflowBindingResolution,
|
|
51
|
+
type DocflowSymbolResolution,
|
|
52
|
+
} from '../docflow-binding';
|
|
32
53
|
import type { ToolExecutionErrorSchemaVersion } from '../../tool-execution-error';
|
|
33
54
|
import type { PlaySandboxRuntimeDeclaration } from '../../play-runtime/sandbox-runtime-limits';
|
|
34
55
|
import { validatePlaySourceFilesHaveNoInlineSecrets } from '../secret-guardrails';
|
|
35
56
|
import { MAX_PLAY_BUNDLE_BYTES } from './limits';
|
|
36
57
|
import { PLAY_AUTHORING_CONTRACT_EDITION } from '../authoring-contract';
|
|
37
58
|
|
|
38
|
-
// The authored tool-error schema
|
|
39
|
-
// local bundle cached before
|
|
40
|
-
|
|
59
|
+
// The authored tool-error schema and the authored docflow block are both part
|
|
60
|
+
// of the artifact bytes. Do not reuse a local bundle cached before either
|
|
61
|
+
// compatibility selection or docflow instrumentation entered graph analysis.
|
|
62
|
+
// Keep this aligned with the app and SDK adapters' cache namespace.
|
|
63
|
+
const PLAY_BUNDLE_CACHE_VERSION = 33;
|
|
41
64
|
const PLAY_ARTIFACT_CACHE_DIR = join(
|
|
42
65
|
tmpdir(),
|
|
43
66
|
`deepline-play-artifacts-v${PLAY_BUNDLE_CACHE_VERSION}`,
|
|
@@ -515,11 +538,6 @@ export function extractDefinedPlayDescriptionForExport(
|
|
|
515
538
|
);
|
|
516
539
|
}
|
|
517
540
|
|
|
518
|
-
type AstNode = {
|
|
519
|
-
type: string;
|
|
520
|
-
[key: string]: unknown;
|
|
521
|
-
};
|
|
522
|
-
|
|
523
541
|
type PlayMetadataExtractionContext = {
|
|
524
542
|
declarations: Map<string, AstNode | null>;
|
|
525
543
|
namedExports: Map<string, string>;
|
|
@@ -535,16 +553,6 @@ type ExtractedPlayMetadata = {
|
|
|
535
553
|
toolErrorSchemaVersionUnknown: boolean;
|
|
536
554
|
};
|
|
537
555
|
|
|
538
|
-
const TypeScriptParser = Parser.extend(
|
|
539
|
-
tsPlugin({
|
|
540
|
-
allowSatisfies: true,
|
|
541
|
-
jsx: {
|
|
542
|
-
allowNamespaces: true,
|
|
543
|
-
allowNamespacedObjects: true,
|
|
544
|
-
},
|
|
545
|
-
}) as unknown as (BaseParser: typeof Parser) => typeof Parser,
|
|
546
|
-
);
|
|
547
|
-
|
|
548
556
|
function parsePlaySourceAst(sourceCode: string): AstNode | null {
|
|
549
557
|
try {
|
|
550
558
|
return TypeScriptParser.parse(sourceCode, {
|
|
@@ -580,14 +588,6 @@ function getIdentifierName(node: unknown): string | null {
|
|
|
580
588
|
: null;
|
|
581
589
|
}
|
|
582
590
|
|
|
583
|
-
function isAstNode(value: unknown): value is AstNode {
|
|
584
|
-
return value !== null && typeof value === 'object' && 'type' in value;
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
function astArray(value: unknown): AstNode[] {
|
|
588
|
-
return Array.isArray(value) ? value.filter(isAstNode) : [];
|
|
589
|
-
}
|
|
590
|
-
|
|
591
591
|
function memberExpressionPath(
|
|
592
592
|
node: AstNode | null | undefined,
|
|
593
593
|
): string[] | null {
|
|
@@ -1345,6 +1345,348 @@ function localSdkAliasPlugin(adapter: PlayBundlingAdapter): Plugin | null {
|
|
|
1345
1345
|
};
|
|
1346
1346
|
}
|
|
1347
1347
|
|
|
1348
|
+
function sourceLoaderForPath(path: string): 'ts' | 'tsx' | 'js' | 'jsx' {
|
|
1349
|
+
const extension = extname(path).toLowerCase();
|
|
1350
|
+
if (extension === '.tsx') return 'tsx';
|
|
1351
|
+
if (extension === '.jsx') return 'jsx';
|
|
1352
|
+
if (extension === '.js' || extension === '.mjs' || extension === '.cjs') {
|
|
1353
|
+
return 'js';
|
|
1354
|
+
}
|
|
1355
|
+
return 'ts';
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
function docflowContextIdentifierFromCall(call: AstNode): string | null {
|
|
1359
|
+
if (!isDefinePlayCallExpression(call)) return null;
|
|
1360
|
+
const args = astArray(call.arguments);
|
|
1361
|
+
const callback = args.find(
|
|
1362
|
+
(argument) =>
|
|
1363
|
+
argument.type === 'ArrowFunctionExpression' ||
|
|
1364
|
+
argument.type === 'FunctionExpression',
|
|
1365
|
+
);
|
|
1366
|
+
if (!callback) return null;
|
|
1367
|
+
return getIdentifierName(astArray(callback.params)[0]);
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
/**
|
|
1371
|
+
* Finds the context parameter for the definePlay call that owns one binding.
|
|
1372
|
+
* A file may export several plays with different parameter names, so a single
|
|
1373
|
+
* file-global context identifier is not safe for instrumentation.
|
|
1374
|
+
*/
|
|
1375
|
+
function findDocflowContextIdentifier(input: {
|
|
1376
|
+
ast: AstNode;
|
|
1377
|
+
statement: AstNode | null;
|
|
1378
|
+
bindingLine: number;
|
|
1379
|
+
lineStarts: readonly number[];
|
|
1380
|
+
parents: ReadonlyMap<AstNode, AstNode>;
|
|
1381
|
+
}): string | null {
|
|
1382
|
+
let owner: AstNode | null = input.statement;
|
|
1383
|
+
while (owner) {
|
|
1384
|
+
const contextName = docflowContextIdentifierFromCall(owner);
|
|
1385
|
+
if (contextName) return contextName;
|
|
1386
|
+
owner = input.parents.get(owner) ?? null;
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
// Positional instrumentation can survive an AST resolver abstention. In that
|
|
1390
|
+
// case, choose the smallest definePlay call containing the bound line.
|
|
1391
|
+
const lineStart = input.lineStarts[input.bindingLine - 1];
|
|
1392
|
+
const lineEnd =
|
|
1393
|
+
input.lineStarts[input.bindingLine] ?? Number.POSITIVE_INFINITY;
|
|
1394
|
+
if (lineStart === undefined) return null;
|
|
1395
|
+
let best: AstNode | null = null;
|
|
1396
|
+
const pending: unknown[] = [input.ast];
|
|
1397
|
+
while (pending.length > 0) {
|
|
1398
|
+
const value = pending.pop();
|
|
1399
|
+
if (!isAstNode(value)) continue;
|
|
1400
|
+
if (isDefinePlayCallExpression(value)) {
|
|
1401
|
+
const bounds = astNodeBounds(value);
|
|
1402
|
+
if (
|
|
1403
|
+
bounds &&
|
|
1404
|
+
bounds.start < lineEnd &&
|
|
1405
|
+
bounds.end > lineStart &&
|
|
1406
|
+
(!best ||
|
|
1407
|
+
bounds.end - bounds.start <
|
|
1408
|
+
(astNodeBounds(best)?.end ?? 0) - (astNodeBounds(best)?.start ?? 0))
|
|
1409
|
+
) {
|
|
1410
|
+
best = value;
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
for (const child of Object.values(value)) {
|
|
1414
|
+
if (Array.isArray(child)) pending.push(...child);
|
|
1415
|
+
else if (isAstNode(child)) pending.push(child);
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
return best ? docflowContextIdentifierFromCall(best) : null;
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
type DocflowInstrumentationReplacement = {
|
|
1422
|
+
start: number;
|
|
1423
|
+
end: number;
|
|
1424
|
+
value: string;
|
|
1425
|
+
};
|
|
1426
|
+
|
|
1427
|
+
function docflowInputCaptureSource(paths: readonly string[]): string {
|
|
1428
|
+
return `[${paths
|
|
1429
|
+
.map((path) => {
|
|
1430
|
+
const [root, ...properties] = path.split('.');
|
|
1431
|
+
return `{path:${JSON.stringify(path)},readRoot:()=>${root},properties:${JSON.stringify(properties)}}`;
|
|
1432
|
+
})
|
|
1433
|
+
.join(',')}]`;
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
/** The expression span a bound statement exposes for runtime observation. */
|
|
1437
|
+
function docflowObservationTarget(
|
|
1438
|
+
statement: ReturnType<typeof findDocflowBoundStatement>,
|
|
1439
|
+
): {
|
|
1440
|
+
start: number;
|
|
1441
|
+
end: number;
|
|
1442
|
+
awaitsResult: boolean;
|
|
1443
|
+
expression: AstNode;
|
|
1444
|
+
} | null {
|
|
1445
|
+
if (!statement) return null;
|
|
1446
|
+
let expression: AstNode | null = null;
|
|
1447
|
+
if (statement.type === 'VariableDeclaration') {
|
|
1448
|
+
const declarations = astArray(statement.declarations);
|
|
1449
|
+
if (declarations.length === 1 && isAstNode(declarations[0]!.init)) {
|
|
1450
|
+
expression = declarations[0]!.init;
|
|
1451
|
+
}
|
|
1452
|
+
} else if (
|
|
1453
|
+
statement.type === 'ReturnStatement' &&
|
|
1454
|
+
isAstNode(statement.argument)
|
|
1455
|
+
) {
|
|
1456
|
+
expression = statement.argument;
|
|
1457
|
+
} else if (
|
|
1458
|
+
statement.type === 'ExpressionStatement' &&
|
|
1459
|
+
isAstNode(statement.expression)
|
|
1460
|
+
) {
|
|
1461
|
+
expression = statement.expression;
|
|
1462
|
+
} else if (statement.type === 'IfStatement' && isAstNode(statement.test)) {
|
|
1463
|
+
expression = statement.test;
|
|
1464
|
+
}
|
|
1465
|
+
if (!expression) return null;
|
|
1466
|
+
const bounds = astNodeBounds(expression);
|
|
1467
|
+
if (!bounds) return null;
|
|
1468
|
+
return {
|
|
1469
|
+
...bounds,
|
|
1470
|
+
awaitsResult: expressionContainsTopLevelAwait(expression),
|
|
1471
|
+
expression,
|
|
1472
|
+
};
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
function docflowObservedExpression(input: {
|
|
1476
|
+
contextName: string;
|
|
1477
|
+
nodeId: string;
|
|
1478
|
+
inputs: readonly string[];
|
|
1479
|
+
outputs: readonly string[];
|
|
1480
|
+
expression: string;
|
|
1481
|
+
awaitsResult: boolean;
|
|
1482
|
+
}): string {
|
|
1483
|
+
const callback = input.awaitsResult
|
|
1484
|
+
? `async()=>(${input.expression})`
|
|
1485
|
+
: `()=>(${input.expression})`;
|
|
1486
|
+
const observation = `${input.contextName}.__deeplineObserveDocflowNode(${JSON.stringify(input.nodeId)},${docflowInputCaptureSource(input.inputs)},${JSON.stringify(input.outputs)},${callback})`;
|
|
1487
|
+
return input.awaitsResult ? `await ${observation}` : observation;
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
function expressionContainsTopLevelAwait(expression: AstNode): boolean {
|
|
1491
|
+
const pending: AstNode[] = [expression];
|
|
1492
|
+
while (pending.length > 0) {
|
|
1493
|
+
const node = pending.pop()!;
|
|
1494
|
+
if (node.type === 'AwaitExpression') return true;
|
|
1495
|
+
if (
|
|
1496
|
+
node !== expression &&
|
|
1497
|
+
(node.type === 'ArrowFunctionExpression' ||
|
|
1498
|
+
node.type === 'FunctionExpression' ||
|
|
1499
|
+
node.type === 'FunctionDeclaration')
|
|
1500
|
+
) {
|
|
1501
|
+
continue;
|
|
1502
|
+
}
|
|
1503
|
+
for (const child of Object.values(node)) {
|
|
1504
|
+
if (Array.isArray(child)) pending.push(...child.filter(isAstNode));
|
|
1505
|
+
else if (isAstNode(child)) pending.push(child);
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
return false;
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
/**
|
|
1512
|
+
* Instruments authored nodes at AST expression boundaries. Declarations,
|
|
1513
|
+
* expressions, decisions, and returns are wrapped so the runtime reports the
|
|
1514
|
+
* actual result or failure. Rewrites remain single-line so source mappings and
|
|
1515
|
+
* the executable program's block scope do not change.
|
|
1516
|
+
*/
|
|
1517
|
+
export function instrumentPlayDocflowRuntimeHits(sourceCode: string): string {
|
|
1518
|
+
// EVERY block's bindings, not just the export being bundled. Two exports'
|
|
1519
|
+
// statements are disjoint, so instrumenting both is correct for whichever one
|
|
1520
|
+
// runs, and the esbuild plugin never has to learn which export it is building.
|
|
1521
|
+
const parsed = parsePlayDocflowFile(sourceCode);
|
|
1522
|
+
if (parsed.blocks.length === 0 || parsed.errors.length > 0) return sourceCode;
|
|
1523
|
+
const ast = parsePlaySourceAst(sourceCode);
|
|
1524
|
+
if (!ast) return sourceCode;
|
|
1525
|
+
const lineStarts = sourceLineStarts(sourceCode);
|
|
1526
|
+
const replacements: DocflowInstrumentationReplacement[] = [];
|
|
1527
|
+
|
|
1528
|
+
// Several annotations may bind one statement — stacked above the dataset
|
|
1529
|
+
// call, or on a chained `.withColumn(...)` line INSIDE it, where the bound
|
|
1530
|
+
// target is an inner expression whose span overlaps (not equals) the
|
|
1531
|
+
// statement's. Overlapping text replacements corrupt the rewritten source,
|
|
1532
|
+
// so every set of overlapping spans collapses into ONE group at the
|
|
1533
|
+
// outermost span, emitted as a single nested observation.
|
|
1534
|
+
type ObservationTarget = {
|
|
1535
|
+
start: number;
|
|
1536
|
+
end: number;
|
|
1537
|
+
awaitsResult: boolean;
|
|
1538
|
+
contextName: string;
|
|
1539
|
+
binding: PlayDocflowBinding;
|
|
1540
|
+
};
|
|
1541
|
+
const targets: ObservationTarget[] = [];
|
|
1542
|
+
|
|
1543
|
+
// Build the parent index once so every binding's symbol resolution reuses it.
|
|
1544
|
+
const parents = buildDocflowParentIndex(ast);
|
|
1545
|
+
for (const binding of parsed.bindings) {
|
|
1546
|
+
// ADR 0016 rule 1: prefer the statement the `out:` symbol names; fall back
|
|
1547
|
+
// to positional resolution. Instrumentation and `plays check` share this
|
|
1548
|
+
// resolver, so the observed statement and the lint agree.
|
|
1549
|
+
const resolution = resolveDocflowBinding(ast, binding, lineStarts, parents);
|
|
1550
|
+
const contextName = findDocflowContextIdentifier({
|
|
1551
|
+
ast,
|
|
1552
|
+
statement: resolution.statement,
|
|
1553
|
+
bindingLine: binding.line,
|
|
1554
|
+
lineStarts,
|
|
1555
|
+
parents,
|
|
1556
|
+
});
|
|
1557
|
+
if (!contextName) continue;
|
|
1558
|
+
const target = docflowObservationTarget(resolution.statement);
|
|
1559
|
+
// A binding naming a `.step('<leg>', …)` leg of a waterfall is NOT
|
|
1560
|
+
// instrumented, and the omission is deliberate rather than a gap.
|
|
1561
|
+
//
|
|
1562
|
+
// A leg's enclosing statement is the whole `steps().step(…).step(…)` builder:
|
|
1563
|
+
// one expression, shared by every leg, which runs once and synchronously to
|
|
1564
|
+
// produce a program object. Wrapping it would report the BUILDER's
|
|
1565
|
+
// construction — instantly settled, with the program as its "output" — under
|
|
1566
|
+
// each leg's node id, and every leg in the cascade would observe the same
|
|
1567
|
+
// span. That is not partial truth, it is a false one, and the canvas would
|
|
1568
|
+
// render a row of completed steps before a single provider had been called.
|
|
1569
|
+
//
|
|
1570
|
+
// Observing the leg itself would mean a new rewrite shape wrapping each
|
|
1571
|
+
// step's RESOLVER, which runs per row inside a dataset — one observation row
|
|
1572
|
+
// per leg per row, against ADR 0016's bound that maps observe at the node
|
|
1573
|
+
// level because per-row truth already lives in sheets. So a waterfall region
|
|
1574
|
+
// is observation-free by construction: the canvas suppresses run state on leg
|
|
1575
|
+
// members and marks only the answering leg, read from the cascade's own
|
|
1576
|
+
// durable result.
|
|
1577
|
+
//
|
|
1578
|
+
// The test is the SHAPE of the observed expression, not how the binding
|
|
1579
|
+
// resolved: every shipped prebuilt builds its cascade in a module-level
|
|
1580
|
+
// helper, which the enclosing-`definePlay` symbol scope deliberately cannot
|
|
1581
|
+
// see, so those legs resolve positionally and would otherwise slip through.
|
|
1582
|
+
const observedRoot = docflowOutputRoot(binding);
|
|
1583
|
+
if (
|
|
1584
|
+
target &&
|
|
1585
|
+
observedRoot &&
|
|
1586
|
+
docflowExpressionWrapsStepBuilder(target.expression, observedRoot)
|
|
1587
|
+
) {
|
|
1588
|
+
continue;
|
|
1589
|
+
}
|
|
1590
|
+
if (target) {
|
|
1591
|
+
targets.push({ ...target, contextName, binding });
|
|
1592
|
+
continue;
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
const lineStart = lineStarts[binding.line - 1];
|
|
1596
|
+
if (lineStart !== undefined) {
|
|
1597
|
+
const indentationLength =
|
|
1598
|
+
/^\s*/.exec(sourceCode.slice(lineStart))?.[0].length ?? 0;
|
|
1599
|
+
replacements.push({
|
|
1600
|
+
start: lineStart + indentationLength,
|
|
1601
|
+
end: lineStart + indentationLength,
|
|
1602
|
+
value: `await ${contextName}.__deeplineDocflowHit(${JSON.stringify(binding.nodeId)}); `,
|
|
1603
|
+
});
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
// AST spans nest, so after sorting (container first: earliest start, then
|
|
1608
|
+
// longest) any overlapping target is contained by the open group. The sort
|
|
1609
|
+
// is stable, so same-span bindings keep their annotation order.
|
|
1610
|
+
targets.sort(
|
|
1611
|
+
(left, right) => left.start - right.start || right.end - left.end,
|
|
1612
|
+
);
|
|
1613
|
+
type ObservationGroup = {
|
|
1614
|
+
start: number;
|
|
1615
|
+
end: number;
|
|
1616
|
+
awaitsResult: boolean;
|
|
1617
|
+
contextName: string;
|
|
1618
|
+
bindings: PlayDocflowBinding[];
|
|
1619
|
+
};
|
|
1620
|
+
const groups: ObservationGroup[] = [];
|
|
1621
|
+
for (const target of targets) {
|
|
1622
|
+
const open = groups[groups.length - 1];
|
|
1623
|
+
if (open && target.start < open.end) {
|
|
1624
|
+
open.bindings.push(target.binding);
|
|
1625
|
+
} else {
|
|
1626
|
+
groups.push({
|
|
1627
|
+
start: target.start,
|
|
1628
|
+
end: target.end,
|
|
1629
|
+
awaitsResult: target.awaitsResult,
|
|
1630
|
+
contextName: target.contextName,
|
|
1631
|
+
bindings: [target.binding],
|
|
1632
|
+
});
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
for (const group of groups) {
|
|
1637
|
+
// Wrap in reverse order so the first-listed annotation observes outermost.
|
|
1638
|
+
let expression = sourceCode.slice(group.start, group.end);
|
|
1639
|
+
for (const binding of [...group.bindings].reverse()) {
|
|
1640
|
+
expression = docflowObservedExpression({
|
|
1641
|
+
contextName: group.contextName,
|
|
1642
|
+
nodeId: binding.nodeId,
|
|
1643
|
+
inputs: binding.inputs ?? [],
|
|
1644
|
+
outputs: binding.outputs ?? [],
|
|
1645
|
+
expression,
|
|
1646
|
+
awaitsResult: group.awaitsResult,
|
|
1647
|
+
});
|
|
1648
|
+
}
|
|
1649
|
+
replacements.push({
|
|
1650
|
+
start: group.start,
|
|
1651
|
+
end: group.end,
|
|
1652
|
+
value: expression,
|
|
1653
|
+
});
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
return replacements
|
|
1657
|
+
.sort((left, right) => right.start - left.start)
|
|
1658
|
+
.reduce(
|
|
1659
|
+
(source, replacement) =>
|
|
1660
|
+
`${source.slice(0, replacement.start)}${replacement.value}${source.slice(replacement.end)}`,
|
|
1661
|
+
sourceCode,
|
|
1662
|
+
);
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
function docflowRuntimeInstrumentationPlugin(
|
|
1666
|
+
customerSourceFilePaths: readonly string[],
|
|
1667
|
+
): Plugin {
|
|
1668
|
+
const customerSourceFiles = new Set(
|
|
1669
|
+
customerSourceFilePaths
|
|
1670
|
+
.filter((path) => extname(path).toLowerCase() !== '.json')
|
|
1671
|
+
.map((path) => resolve(path)),
|
|
1672
|
+
);
|
|
1673
|
+
return {
|
|
1674
|
+
name: 'deepline-docflow-runtime-instrumentation',
|
|
1675
|
+
setup(buildContext) {
|
|
1676
|
+
buildContext.onLoad({ filter: /./ }, (args) => {
|
|
1677
|
+
if (!customerSourceFiles.has(resolve(args.path))) return undefined;
|
|
1678
|
+
return {
|
|
1679
|
+
contents: instrumentPlayDocflowRuntimeHits(
|
|
1680
|
+
readFileSync(args.path, 'utf8'),
|
|
1681
|
+
),
|
|
1682
|
+
loader: sourceLoaderForPath(args.path),
|
|
1683
|
+
resolveDir: dirname(args.path),
|
|
1684
|
+
};
|
|
1685
|
+
});
|
|
1686
|
+
},
|
|
1687
|
+
};
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1348
1690
|
function buildImportedPlayProxyModule(playName: string): string {
|
|
1349
1691
|
const serializedName = JSON.stringify(playName);
|
|
1350
1692
|
return `
|
|
@@ -1793,13 +2135,17 @@ type EsbuildBundleOutput = {
|
|
|
1793
2135
|
|
|
1794
2136
|
async function runEsbuildForCjsNode(
|
|
1795
2137
|
entryFile: string,
|
|
1796
|
-
|
|
2138
|
+
customerSourceFilePaths: string[],
|
|
1797
2139
|
importedPlayDependencies: ImportedPlayDependency[],
|
|
1798
2140
|
adapter: PlayBundlingAdapter,
|
|
1799
2141
|
exportName: string,
|
|
1800
2142
|
): Promise<EsbuildBundleOutput | string[]> {
|
|
1801
2143
|
const sdkAliasPlugin = localSdkAliasPlugin(adapter);
|
|
1802
2144
|
const playProxyPlugin = importedPlayProxyPlugin(importedPlayDependencies);
|
|
2145
|
+
const docflowPlugin = docflowRuntimeInstrumentationPlugin([
|
|
2146
|
+
entryFile,
|
|
2147
|
+
...customerSourceFilePaths,
|
|
2148
|
+
]);
|
|
1803
2149
|
const namedExportShim =
|
|
1804
2150
|
exportName === 'default'
|
|
1805
2151
|
? null
|
|
@@ -1827,7 +2173,7 @@ async function runEsbuildForCjsNode(
|
|
|
1827
2173
|
sourcesContent: false,
|
|
1828
2174
|
logLevel: 'silent',
|
|
1829
2175
|
legalComments: 'none',
|
|
1830
|
-
plugins: [sdkAliasPlugin, playProxyPlugin].filter(
|
|
2176
|
+
plugins: [docflowPlugin, sdkAliasPlugin, playProxyPlugin].filter(
|
|
1831
2177
|
(plugin): plugin is Plugin => plugin != null,
|
|
1832
2178
|
),
|
|
1833
2179
|
});
|