@ontrails/warden 1.0.0-beta.43 → 1.0.0-beta.45
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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @ontrails/warden
|
|
2
2
|
|
|
3
|
+
## 1.0.0-beta.45
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`f1bd093`](https://github.com/outfitter-dev/trails/commit/f1bd09395fcf81db0bcb8657030288877c2e26e6): Recognize conditional, aliased, and parenthesized Result provenance while invalidating provenance after reassignment across the implementation-return and redundant-error-wrap rules.
|
|
8
|
+
|
|
9
|
+
## 1.0.0-beta.44
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [`b1fbe57`](https://github.com/outfitter-dev/trails/commit/b1fbe574e6f44d1fecb5e3a000270955c0a77b7b): Publish Bun-validated package tarballs through an npm trusted-publishing adapter
|
|
14
|
+
binding, add exact repository metadata for each public workspace package, and
|
|
15
|
+
correct the native Bun release descriptor to its pack-only runtime boundary.
|
|
16
|
+
|
|
3
17
|
## 1.0.0-beta.43
|
|
4
18
|
|
|
5
19
|
### Minor Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ontrails/warden",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.45",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/outfitter-dev/trails.git",
|
|
7
|
+
"directory": "packages/warden"
|
|
8
|
+
},
|
|
4
9
|
"bin": {
|
|
5
10
|
"warden": "./bin/warden.ts"
|
|
6
11
|
},
|
|
@@ -27,20 +32,20 @@
|
|
|
27
32
|
"clean": "rm -rf dist *.tsbuildinfo"
|
|
28
33
|
},
|
|
29
34
|
"dependencies": {
|
|
30
|
-
"@ontrails/adapter-kit": "^1.0.0-beta.
|
|
31
|
-
"@ontrails/cli": "^1.0.0-beta.
|
|
32
|
-
"@ontrails/config": "^1.0.0-beta.
|
|
33
|
-
"@ontrails/permits": "^1.0.0-beta.
|
|
34
|
-
"@ontrails/source": "^1.0.0-beta.
|
|
35
|
-
"@ontrails/store": "^1.0.0-beta.
|
|
35
|
+
"@ontrails/adapter-kit": "^1.0.0-beta.45",
|
|
36
|
+
"@ontrails/cli": "^1.0.0-beta.45",
|
|
37
|
+
"@ontrails/config": "^1.0.0-beta.45",
|
|
38
|
+
"@ontrails/permits": "^1.0.0-beta.45",
|
|
39
|
+
"@ontrails/source": "^1.0.0-beta.45",
|
|
40
|
+
"@ontrails/store": "^1.0.0-beta.45",
|
|
36
41
|
"oxc-resolver": "11.19.1",
|
|
37
42
|
"zod": "^4.3.5"
|
|
38
43
|
},
|
|
39
44
|
"devDependencies": {
|
|
40
|
-
"@ontrails/testing": "^1.0.0-beta.
|
|
45
|
+
"@ontrails/testing": "^1.0.0-beta.45"
|
|
41
46
|
},
|
|
42
47
|
"peerDependencies": {
|
|
43
|
-
"@ontrails/core": "^1.0.0-beta.
|
|
44
|
-
"@ontrails/topography": "^1.0.0-beta.
|
|
48
|
+
"@ontrails/core": "^1.0.0-beta.45",
|
|
49
|
+
"@ontrails/topography": "^1.0.0-beta.45"
|
|
45
50
|
}
|
|
46
51
|
}
|
|
@@ -25,8 +25,11 @@ import {
|
|
|
25
25
|
getNodeImported,
|
|
26
26
|
getNodeInit,
|
|
27
27
|
getNodeLocal,
|
|
28
|
+
getNodeLeft,
|
|
28
29
|
getNodeName,
|
|
30
|
+
getNodeOperator,
|
|
29
31
|
getNodeReturnType,
|
|
32
|
+
getNodeRight,
|
|
30
33
|
getNodeSource,
|
|
31
34
|
getNodeTypeAnnotation,
|
|
32
35
|
getNodeValue,
|
|
@@ -97,12 +100,15 @@ export type ScopedHelperMap = ReadonlyMap<
|
|
|
97
100
|
|
|
98
101
|
export type MutableScopedHelperMap = Map<ReadonlySet<string>, Set<string>>;
|
|
99
102
|
|
|
100
|
-
type ScopedResultVariableMap = ReadonlyMap<
|
|
103
|
+
export type ScopedResultVariableMap = ReadonlyMap<
|
|
101
104
|
ReadonlySet<string>,
|
|
102
105
|
ReadonlySet<string>
|
|
103
106
|
>;
|
|
104
107
|
|
|
105
|
-
type MutableScopedResultVariableMap = Map<
|
|
108
|
+
export type MutableScopedResultVariableMap = Map<
|
|
109
|
+
ReadonlySet<string>,
|
|
110
|
+
Set<string>
|
|
111
|
+
>;
|
|
106
112
|
|
|
107
113
|
export const findNearestBindingScope = (
|
|
108
114
|
name: string,
|
|
@@ -224,8 +230,8 @@ const unwrapReturnExpression = (node: AstNode): AstNode => {
|
|
|
224
230
|
return current;
|
|
225
231
|
};
|
|
226
232
|
|
|
227
|
-
/** Check
|
|
228
|
-
const
|
|
233
|
+
/** Check whether an expression has visible Result-producing provenance. */
|
|
234
|
+
export const isResultProducingExpression = (
|
|
229
235
|
argument: AstNode,
|
|
230
236
|
helperNames: ReadonlySet<string>,
|
|
231
237
|
resultVars: ScopedResultVariableMap,
|
|
@@ -240,7 +246,7 @@ const isAllowedReturnArgument = (
|
|
|
240
246
|
return (
|
|
241
247
|
consequent !== undefined &&
|
|
242
248
|
alternate !== undefined &&
|
|
243
|
-
|
|
249
|
+
isResultProducingExpression(
|
|
244
250
|
consequent,
|
|
245
251
|
helperNames,
|
|
246
252
|
resultVars,
|
|
@@ -248,7 +254,7 @@ const isAllowedReturnArgument = (
|
|
|
248
254
|
scopes,
|
|
249
255
|
scopedHelpers
|
|
250
256
|
) &&
|
|
251
|
-
|
|
257
|
+
isResultProducingExpression(
|
|
252
258
|
alternate,
|
|
253
259
|
helperNames,
|
|
254
260
|
resultVars,
|
|
@@ -369,6 +375,14 @@ const addScopedResultVariable = (
|
|
|
369
375
|
resultVars.set(scope, new Set([name]));
|
|
370
376
|
};
|
|
371
377
|
|
|
378
|
+
const clearScopedResultVariable = (
|
|
379
|
+
resultVars: MutableScopedResultVariableMap,
|
|
380
|
+
scope: ReadonlySet<string>,
|
|
381
|
+
name: string
|
|
382
|
+
): void => {
|
|
383
|
+
resultVars.get(scope)?.delete(name);
|
|
384
|
+
};
|
|
385
|
+
|
|
372
386
|
/** Record `const helper = (): Result<...> => ...` declarations for the current lexical scope. */
|
|
373
387
|
export const trackScopedResultHelperDeclaration = (
|
|
374
388
|
node: AstNode,
|
|
@@ -440,8 +454,14 @@ const trackResultVariable = (
|
|
|
440
454
|
}
|
|
441
455
|
if (
|
|
442
456
|
hasResultVariableAnnotation(id, sourceCode, resultTypeNames) ||
|
|
443
|
-
|
|
444
|
-
|
|
457
|
+
isResultProducingExpression(
|
|
458
|
+
init,
|
|
459
|
+
helperNames,
|
|
460
|
+
resultVars,
|
|
461
|
+
namespaceHelpers,
|
|
462
|
+
scopes,
|
|
463
|
+
scopedHelpers
|
|
464
|
+
)
|
|
445
465
|
) {
|
|
446
466
|
const bindingScope = findNearestBindingScope(name, scopes);
|
|
447
467
|
if (bindingScope) {
|
|
@@ -451,6 +471,63 @@ const trackResultVariable = (
|
|
|
451
471
|
}
|
|
452
472
|
};
|
|
453
473
|
|
|
474
|
+
export const collectDirectResultAssignments = (
|
|
475
|
+
body: AstNode
|
|
476
|
+
): ReadonlySet<AstNode> => {
|
|
477
|
+
const assignments = new Set<AstNode>();
|
|
478
|
+
for (const statement of getNodeBodyStatements(body)) {
|
|
479
|
+
if (statement.type !== 'ExpressionStatement') {
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
482
|
+
const expression = getNodeExpression(statement);
|
|
483
|
+
if (expression?.type === 'AssignmentExpression') {
|
|
484
|
+
assignments.add(expression);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
return assignments;
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
const trackResultAssignment = (
|
|
491
|
+
node: AstNode,
|
|
492
|
+
resultVars: MutableScopedResultVariableMap,
|
|
493
|
+
helperNames: ReadonlySet<string>,
|
|
494
|
+
namespaceHelpers: NamespaceHelperMap,
|
|
495
|
+
directAssignments: ReadonlySet<AstNode>,
|
|
496
|
+
scopes: readonly ReadonlySet<string>[],
|
|
497
|
+
scopedHelpers: ScopedHelperMap
|
|
498
|
+
): void => {
|
|
499
|
+
const left = getNodeLeft(node);
|
|
500
|
+
const name = identifierName(left);
|
|
501
|
+
if (!name) {
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
const bindingScope = findNearestBindingScope(name, scopes);
|
|
505
|
+
if (!bindingScope) {
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
const right = getNodeRight(node);
|
|
509
|
+
const resultRhs =
|
|
510
|
+
getNodeOperator(node) === '=' &&
|
|
511
|
+
right &&
|
|
512
|
+
isResultProducingExpression(
|
|
513
|
+
right,
|
|
514
|
+
helperNames,
|
|
515
|
+
resultVars,
|
|
516
|
+
namespaceHelpers,
|
|
517
|
+
scopes,
|
|
518
|
+
scopedHelpers
|
|
519
|
+
);
|
|
520
|
+
if (
|
|
521
|
+
resultRhs &&
|
|
522
|
+
(isScopedResultVariableBinding(name, scopes, resultVars) ||
|
|
523
|
+
directAssignments.has(node))
|
|
524
|
+
) {
|
|
525
|
+
addScopedResultVariable(resultVars, bindingScope, name);
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
clearScopedResultVariable(resultVars, bindingScope, name);
|
|
529
|
+
};
|
|
530
|
+
|
|
454
531
|
// ---------------------------------------------------------------------------
|
|
455
532
|
// Return statement checking
|
|
456
533
|
// ---------------------------------------------------------------------------
|
|
@@ -470,6 +547,7 @@ const checkReturnStatements = (
|
|
|
470
547
|
const resultVars: MutableScopedResultVariableMap = new Map();
|
|
471
548
|
const scopedHelpers: MutableScopedHelperMap = new Map();
|
|
472
549
|
const initialScopes = implScope.size > 0 ? [implScope] : [];
|
|
550
|
+
const directAssignments = collectDirectResultAssignments(blockBody);
|
|
473
551
|
|
|
474
552
|
walkWithScopes(
|
|
475
553
|
blockBody,
|
|
@@ -494,6 +572,18 @@ const checkReturnStatements = (
|
|
|
494
572
|
);
|
|
495
573
|
}
|
|
496
574
|
|
|
575
|
+
if (node.type === 'AssignmentExpression') {
|
|
576
|
+
trackResultAssignment(
|
|
577
|
+
node,
|
|
578
|
+
resultVars,
|
|
579
|
+
helperNames,
|
|
580
|
+
namespaceHelpers,
|
|
581
|
+
directAssignments,
|
|
582
|
+
currentScopes,
|
|
583
|
+
scopedHelpers
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
|
|
497
587
|
if (node.type !== 'ReturnStatement') {
|
|
498
588
|
return;
|
|
499
589
|
}
|
|
@@ -505,7 +595,7 @@ const checkReturnStatements = (
|
|
|
505
595
|
}
|
|
506
596
|
|
|
507
597
|
if (
|
|
508
|
-
|
|
598
|
+
isResultProducingExpression(
|
|
509
599
|
argument,
|
|
510
600
|
helperNames,
|
|
511
601
|
resultVars,
|
|
@@ -23,11 +23,11 @@ import {
|
|
|
23
23
|
import type { AstNode, AstParentContext } from '@ontrails/source';
|
|
24
24
|
import {
|
|
25
25
|
collectAllResultHelperNames,
|
|
26
|
+
collectDirectResultAssignments,
|
|
26
27
|
collectNamespaceHelperImports,
|
|
27
28
|
collectResultTypeNames,
|
|
28
29
|
findNearestBindingScope,
|
|
29
|
-
|
|
30
|
-
isResultExpression,
|
|
30
|
+
isResultProducingExpression,
|
|
31
31
|
trackScopedResultHelperDeclaration,
|
|
32
32
|
} from './implementation-returns-result.js';
|
|
33
33
|
import { isTestFile } from './scan.js';
|
|
@@ -82,16 +82,6 @@ const getErrorSourceVariable = (node: AstNode | null): string | null => {
|
|
|
82
82
|
return identifierName(member?.object);
|
|
83
83
|
};
|
|
84
84
|
|
|
85
|
-
const isResultProducingExpression = (
|
|
86
|
-
node: AstNode,
|
|
87
|
-
helperNames: ReadonlySet<string>,
|
|
88
|
-
namespaceHelpers: NamespaceHelperMap,
|
|
89
|
-
scopes: readonly ReadonlySet<string>[],
|
|
90
|
-
scopedHelpers: ScopedHelperMap
|
|
91
|
-
): boolean =>
|
|
92
|
-
isResultExpression(node) ||
|
|
93
|
-
isHelperCall(node, helperNames, namespaceHelpers, scopes, scopedHelpers);
|
|
94
|
-
|
|
95
85
|
type ResultProvenance = Map<ReadonlySet<string>, Set<string>>;
|
|
96
86
|
|
|
97
87
|
const markResultVariable = (
|
|
@@ -158,6 +148,7 @@ const trackVariableDeclarator = (
|
|
|
158
148
|
isResultProducingExpression(
|
|
159
149
|
init,
|
|
160
150
|
helperNames,
|
|
151
|
+
provenance,
|
|
161
152
|
namespaceHelpers,
|
|
162
153
|
scopes,
|
|
163
154
|
scopedHelpers
|
|
@@ -175,11 +166,10 @@ const trackAssignmentExpression = (
|
|
|
175
166
|
helperNames: ReadonlySet<string>,
|
|
176
167
|
namespaceHelpers: NamespaceHelperMap,
|
|
177
168
|
scopedHelpers: ScopedHelperMap,
|
|
169
|
+
directAssignments: ReadonlySet<AstNode>,
|
|
178
170
|
scopes: readonly ReadonlySet<string>[]
|
|
179
171
|
): void => {
|
|
180
172
|
const left = getNodeLeft(node);
|
|
181
|
-
const operator = getNodeOperator(node);
|
|
182
|
-
const right = getNodeRight(node);
|
|
183
173
|
const name = identifierName(left);
|
|
184
174
|
if (!name) {
|
|
185
175
|
return;
|
|
@@ -188,16 +178,22 @@ const trackAssignmentExpression = (
|
|
|
188
178
|
if (!scope) {
|
|
189
179
|
return;
|
|
190
180
|
}
|
|
191
|
-
|
|
192
|
-
|
|
181
|
+
const right = getNodeRight(node);
|
|
182
|
+
const resultRhs =
|
|
183
|
+
getNodeOperator(node) === '=' &&
|
|
193
184
|
right &&
|
|
194
185
|
isResultProducingExpression(
|
|
195
186
|
right,
|
|
196
187
|
helperNames,
|
|
188
|
+
provenance,
|
|
197
189
|
namespaceHelpers,
|
|
198
190
|
scopes,
|
|
199
191
|
scopedHelpers
|
|
200
|
-
)
|
|
192
|
+
);
|
|
193
|
+
if (
|
|
194
|
+
resultRhs &&
|
|
195
|
+
(hasResultProvenance(provenance, scope, name) ||
|
|
196
|
+
directAssignments.has(node))
|
|
201
197
|
) {
|
|
202
198
|
markResultVariable(provenance, scope, name);
|
|
203
199
|
return;
|
|
@@ -258,6 +254,7 @@ const checkFunctionBody = (
|
|
|
258
254
|
const scopedHelpers: MutableScopedHelperMap = new Map();
|
|
259
255
|
const implScope = collectScopeFrameBindings(owner);
|
|
260
256
|
const initialScopes = implScope.size > 0 ? [implScope] : [];
|
|
257
|
+
const directAssignments = collectDirectResultAssignments(body);
|
|
261
258
|
|
|
262
259
|
walkWithScopes(
|
|
263
260
|
body,
|
|
@@ -287,6 +284,7 @@ const checkFunctionBody = (
|
|
|
287
284
|
helperNames,
|
|
288
285
|
namespaceHelpers,
|
|
289
286
|
scopedHelpers,
|
|
287
|
+
directAssignments,
|
|
290
288
|
scopes
|
|
291
289
|
);
|
|
292
290
|
return;
|