@restormel/testing-core 0.1.0 → 0.1.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) Allotment Technology Ltd
3
+ Copyright (c) 2026 Adam Boon
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,9 +1,13 @@
1
- import type { JudgeRubric, StructuredCheck } from "./success-criteria.js";
1
+ import type { JudgeRubric, StructuredCheck, SuccessCriteria } from "./success-criteria.js";
2
2
  /**
3
3
  * One atomic expectation (for traces, reports, or normalised criteria).
4
4
  * Config YAML may use the flatter `SuccessCriteria` shape instead.
5
5
  */
6
- export type Assertion = UrlAssertion | DomAssertion | TextPresentAssertion | TextAbsentAssertion | StructuredAssertion | JudgeAssertion;
6
+ export type Assertion = AnyOfAssertion | UrlAssertion | DomAssertion | TextPresentAssertion | TextAbsentAssertion | StructuredAssertion | JudgeAssertion;
7
+ export interface AnyOfAssertion {
8
+ kind: "any_of";
9
+ branches: SuccessCriteria[];
10
+ }
7
11
  export interface UrlAssertion {
8
12
  kind: "url";
9
13
  patterns: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"assertion.d.ts","sourceRoot":"","sources":["../src/assertion.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE1E;;;GAGG;AACH,MAAM,MAAM,SAAS,GACjB,YAAY,GACZ,YAAY,GACZ,oBAAoB,GACpB,mBAAmB,GACnB,mBAAmB,GACnB,cAAc,CAAC;AAEnB,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,KAAK,CAAC;IACZ,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,KAAK,CAAC;IACZ,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,cAAc,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,aAAa,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,eAAe,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,WAAW,CAAC;CACrB"}
1
+ {"version":3,"file":"assertion.d.ts","sourceRoot":"","sources":["../src/assertion.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE3F;;;GAGG;AACH,MAAM,MAAM,SAAS,GACjB,cAAc,GACd,YAAY,GACZ,YAAY,GACZ,oBAAoB,GACpB,mBAAmB,GACnB,mBAAmB,GACnB,cAAc,CAAC;AAEnB,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,KAAK,CAAC;IACZ,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,KAAK,CAAC;IACZ,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,cAAc,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,aAAa,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,eAAe,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,WAAW,CAAC;CACrB"}
package/dist/goal.d.ts CHANGED
@@ -7,6 +7,11 @@ export interface TestGoal {
7
7
  type: GoalType;
8
8
  description: string;
9
9
  successCriteria: SuccessCriteria;
10
+ /**
11
+ * Path relative to environment `base_url` for the initial navigation (e.g. `/login`, `dashboard/`).
12
+ * Resolved with `new URL(startPath, baseUrl)`.
13
+ */
14
+ startPath?: string;
10
15
  preconditions?: HookRef[];
11
16
  cleanup?: HookRef[];
12
17
  exclusiveWith?: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"goal.d.ts","sourceRoot":"","sources":["../src/goal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,aAAa,GAAG,QAAQ,CAAC;AAE5D,iEAAiE;AACjE,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC;AAE7B,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,QAAQ,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,eAAe,CAAC;IACjC,aAAa,CAAC,EAAE,OAAO,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB"}
1
+ {"version":3,"file":"goal.d.ts","sourceRoot":"","sources":["../src/goal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,aAAa,GAAG,QAAQ,CAAC;AAE5D,iEAAiE;AACjE,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC;AAE7B,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,QAAQ,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,eAAe,CAAC;IACjC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB"}
package/dist/index.d.ts CHANGED
@@ -15,6 +15,8 @@ export type { CostEstimate, GoalRunRecord, KeysModelMeta, RunRecord, RunRequest,
15
15
  export type { JudgeRubric, StructuredCheck, SuccessCriteria } from "./success-criteria.js";
16
16
  export type { TestSuite } from "./suite.js";
17
17
  export type { Verdict } from "./verdict.js";
18
+ export { isPathContainedInRoot, resolvePathUnderRoot, sanitizePathSegment, } from "./safe-path.js";
19
+ export type { ResolvePathUnderRootResult } from "./safe-path.js";
18
20
  /** Doc-aligned alias for `RunRecord`. */
19
21
  export type TestRun = import("./run.js").RunRecord;
20
22
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAG,yBAAkC,CAAC;AAErE,OAAO,EACL,eAAe,EACf,QAAQ,EACR,WAAW,EACX,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAE7D,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EACV,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,GACb,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC7D,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjE,YAAY,EACV,WAAW,EACX,gBAAgB,EAChB,MAAM,EACN,SAAS,GACV,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,YAAY,EACZ,aAAa,EACb,aAAa,EACb,SAAS,EACT,UAAU,EACV,UAAU,EACV,gBAAgB,EAChB,UAAU,EACV,cAAc,GACf,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC3F,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,yCAAyC;AACzC,MAAM,MAAM,OAAO,GAAG,OAAO,UAAU,EAAE,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAG,yBAAkC,CAAC;AAErE,OAAO,EACL,eAAe,EACf,QAAQ,EACR,WAAW,EACX,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAE7D,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EACV,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,GACb,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC7D,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjE,YAAY,EACV,WAAW,EACX,gBAAgB,EAChB,MAAM,EACN,SAAS,GACV,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,YAAY,EACZ,aAAa,EACb,aAAa,EACb,SAAS,EACT,UAAU,EACV,UAAU,EACV,gBAAgB,EAChB,UAAU,EACV,cAAc,GACf,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC3F,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAEjE,yCAAyC;AACzC,MAAM,MAAM,OAAO,GAAG,OAAO,UAAU,EAAE,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -5,4 +5,5 @@ export const testingCorePackage = "@restormel/testing-core";
5
5
  export { isGoalRunRecord, isReport, isRunRecord, isTraceEvent, } from "./guards.js";
6
6
  export { isVerdict, VERDICTS } from "./verdict.js";
7
7
  export { successCriteriaToAssertions } from "./normalize.js";
8
+ export { isPathContainedInRoot, resolvePathUnderRoot, sanitizePathSegment, } from "./safe-path.js";
8
9
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,yBAAkC,CAAC;AAErE,OAAO,EACL,eAAe,EACf,QAAQ,EACR,WAAW,EACX,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,yBAAkC,CAAC;AAErE,OAAO,EACL,eAAe,EACf,QAAQ,EACR,WAAW,EACX,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAmC7D,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,gBAAgB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,6FAA6F;AAC7F,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,eAAe,GAAG,SAAS,EAAE,CA0BlF"}
1
+ {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,6FAA6F;AAC7F,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,eAAe,GAAG,SAAS,EAAE,CA8BlF"}
package/dist/normalize.js CHANGED
@@ -1,6 +1,10 @@
1
1
  /** Flattens repo-config `SuccessCriteria` into discrete assertions for runners or traces. */
2
2
  export function successCriteriaToAssertions(criteria) {
3
3
  const out = [];
4
+ if (criteria.anyOf !== undefined && criteria.anyOf.length > 0) {
5
+ out.push({ kind: "any_of", branches: [...criteria.anyOf] });
6
+ return out;
7
+ }
4
8
  if (criteria.urlMatches != null) {
5
9
  const patterns = Array.isArray(criteria.urlMatches)
6
10
  ? criteria.urlMatches
@@ -1 +1 @@
1
- {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"AAGA,6FAA6F;AAC7F,MAAM,UAAU,2BAA2B,CAAC,QAAyB;IACnE,MAAM,GAAG,GAAgB,EAAE,CAAC;IAC5B,IAAI,QAAQ,CAAC,UAAU,IAAI,IAAI,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;YACjD,CAAC,CAAC,QAAQ,CAAC,UAAU;YACrB,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC1B,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IACD,IAAI,QAAQ,CAAC,UAAU,IAAI,IAAI,IAAI,QAAQ,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,GAAG,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IACjE,CAAC;IACD,IAAI,QAAQ,CAAC,WAAW,IAAI,IAAI,IAAI,QAAQ,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,UAAU,EAAE,CAAC,GAAG,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,QAAQ,CAAC,UAAU,IAAI,IAAI,IAAI,QAAQ,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC,GAAG,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,gBAAgB,IAAI,EAAE,EAAE,CAAC;QACpD,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;IAC1C,CAAC;IACD,IAAI,QAAQ,CAAC,WAAW,IAAI,IAAI,EAAE,CAAC;QACjC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"AAGA,6FAA6F;AAC7F,MAAM,UAAU,2BAA2B,CAAC,QAAyB;IACnE,MAAM,GAAG,GAAgB,EAAE,CAAC;IAC5B,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9D,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC5D,OAAO,GAAG,CAAC;IACb,CAAC;IACD,IAAI,QAAQ,CAAC,UAAU,IAAI,IAAI,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;YACjD,CAAC,CAAC,QAAQ,CAAC,UAAU;YACrB,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC1B,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IACD,IAAI,QAAQ,CAAC,UAAU,IAAI,IAAI,IAAI,QAAQ,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,GAAG,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IACjE,CAAC;IACD,IAAI,QAAQ,CAAC,WAAW,IAAI,IAAI,IAAI,QAAQ,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,UAAU,EAAE,CAAC,GAAG,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,QAAQ,CAAC,UAAU,IAAI,IAAI,IAAI,QAAQ,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC,GAAG,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,gBAAgB,IAAI,EAAE,EAAE,CAAC;QACpD,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;IAC1C,CAAC;IACD,IAAI,QAAQ,CAAC,WAAW,IAAI,IAAI,EAAE,CAAC;QACjC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * True if `candidateAbs` is the same path or strictly inside `rootAbs` (no `..` escape).
3
+ * Both paths should be absolute (e.g. from `path.resolve`).
4
+ */
5
+ export declare function isPathContainedInRoot(rootAbs: string, candidateAbs: string): boolean;
6
+ export type ResolvePathUnderRootResult = {
7
+ ok: true;
8
+ path: string;
9
+ } | {
10
+ ok: false;
11
+ reason: string;
12
+ };
13
+ /**
14
+ * Resolve a user-supplied path against `root` and reject directory traversal outside `root`.
15
+ */
16
+ export declare function resolvePathUnderRoot(root: string, userPath: string): ResolvePathUnderRootResult;
17
+ /** Single path segment safe for directory names (goal ids, etc.). */
18
+ export declare function sanitizePathSegment(segment: string, maxLen?: number): string;
19
+ //# sourceMappingURL=safe-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-path.d.ts","sourceRoot":"","sources":["../src/safe-path.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAGpF;AAED,MAAM,MAAM,0BAA0B,GAClC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC1B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAElC;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,0BAA0B,CAO/F;AAED,qEAAqE;AACrE,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAM,GAAG,MAAM,CASzE"}
@@ -0,0 +1,34 @@
1
+ import { isAbsolute, relative, resolve } from "node:path";
2
+ /**
3
+ * True if `candidateAbs` is the same path or strictly inside `rootAbs` (no `..` escape).
4
+ * Both paths should be absolute (e.g. from `path.resolve`).
5
+ */
6
+ export function isPathContainedInRoot(rootAbs, candidateAbs) {
7
+ const rel = relative(rootAbs, candidateAbs);
8
+ return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
9
+ }
10
+ /**
11
+ * Resolve a user-supplied path against `root` and reject directory traversal outside `root`.
12
+ */
13
+ export function resolvePathUnderRoot(root, userPath) {
14
+ const rootAbs = resolve(root);
15
+ const candidateAbs = isAbsolute(userPath) ? resolve(userPath) : resolve(rootAbs, userPath);
16
+ if (!isPathContainedInRoot(rootAbs, candidateAbs)) {
17
+ return { ok: false, reason: `Path escapes allowed root (${rootAbs}): ${userPath}` };
18
+ }
19
+ return { ok: true, path: candidateAbs };
20
+ }
21
+ /** Single path segment safe for directory names (goal ids, etc.). */
22
+ export function sanitizePathSegment(segment, maxLen = 128) {
23
+ const s = segment.trim();
24
+ if (s.length === 0)
25
+ return "unnamed";
26
+ if (/^[a-zA-Z0-9._-]+$/.test(s) && s.length <= maxLen)
27
+ return s;
28
+ const folded = s
29
+ .replace(/[^a-zA-Z0-9._-]/g, "_")
30
+ .slice(0, maxLen)
31
+ .replace(/^_+|_+$/g, "");
32
+ return folded.length > 0 ? folded : "segment";
33
+ }
34
+ //# sourceMappingURL=safe-path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-path.js","sourceRoot":"","sources":["../src/safe-path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1D;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAe,EAAE,YAAoB;IACzE,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAC5C,OAAO,GAAG,KAAK,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AACnE,CAAC;AAMD;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY,EAAE,QAAgB;IACjE,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,YAAY,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC3F,IAAI,CAAC,qBAAqB,CAAC,OAAO,EAAE,YAAY,CAAC,EAAE,CAAC;QAClD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,8BAA8B,OAAO,MAAM,QAAQ,EAAE,EAAE,CAAC;IACtF,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;AAC1C,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,mBAAmB,CAAC,OAAe,EAAE,MAAM,GAAG,GAAG;IAC/D,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IACzB,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACrC,IAAI,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM;QAAE,OAAO,CAAC,CAAC;IAChE,MAAM,MAAM,GAAG,CAAC;SACb,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC;SAChC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC;SAChB,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC3B,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AAChD,CAAC"}
@@ -23,6 +23,11 @@ export interface JudgeRubric {
23
23
  * See `successCriteriaToAssertions` to normalise to `Assertion[]`.
24
24
  */
25
25
  export interface SuccessCriteria {
26
+ /**
27
+ * At least two alternative criteria bundles; the goal passes if **any** branch passes.
28
+ * When set, no other keys may appear at this level (use nested objects inside each branch).
29
+ */
30
+ anyOf?: SuccessCriteria[];
26
31
  urlMatches?: string | string[];
27
32
  domSignals?: string[];
28
33
  textPresent?: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"success-criteria.d.ts","sourceRoot":"","sources":["../src/success-criteria.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,MAAM,WAAW,eAAe;IAC9B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,qEAAqE;AACrE,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,qFAAqF;IACrF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;IACrC,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B"}
1
+ {"version":3,"file":"success-criteria.d.ts","sourceRoot":"","sources":["../src/success-criteria.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,MAAM,WAAW,eAAe;IAC9B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,qEAAqE;AACrE,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,qFAAqF;IACrF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,KAAK,CAAC,EAAE,eAAe,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;IACrC,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B"}
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@restormel/testing-core",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Contracts, run/verdict types, and shared primitives (scaffold).",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "https://github.com/Allotment-Technology-Ltd/restormel-testing.git",
9
- "directory": "packages/core"
8
+ "url": "https://github.com/Allotment-Technology-Ltd/restormel-keys.git",
9
+ "directory": "packages/testing-core"
10
10
  },
11
11
  "bugs": {
12
- "url": "https://github.com/Allotment-Technology-Ltd/restormel-testing/issues"
12
+ "url": "https://github.com/Allotment-Technology-Ltd/restormel-keys/issues"
13
13
  },
14
- "homepage": "https://github.com/Allotment-Technology-Ltd/restormel-testing/tree/main/packages/core#readme",
14
+ "homepage": "https://github.com/Allotment-Technology-Ltd/restormel-testing/tree/main/packages/testing-core#readme",
15
15
  "publishConfig": {
16
16
  "access": "public"
17
17
  },