@openparser/lineage 1.0.3 → 1.0.5
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 +8 -0
- package/dist/dotted-path.d.ts +21 -0
- package/dist/dotted-path.d.ts.map +1 -0
- package/dist/fields.d.ts +2 -18
- package/dist/fields.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +55 -8
- package/dist/profile/index.js +18 -4
- package/package.json +1 -1
- package/src/dotted-path.ts +78 -0
- package/src/fields.ts +10 -33
- package/src/index.ts +7 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @openparser/lineage
|
|
2
2
|
|
|
3
|
+
## 1.0.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- d46a558: Dotted field paths now round-trip keys containing periods and tildes without collisions, preventing review edits from targeting the wrong field.
|
|
8
|
+
|
|
9
|
+
## 1.0.4
|
|
10
|
+
|
|
3
11
|
## 1.0.3
|
|
4
12
|
|
|
5
13
|
## 1.0.2
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bijective JSON Pointer ↔ dotted UI path encoding.
|
|
3
|
+
*
|
|
4
|
+
* Segments are joined with `.`. Literal `.` and `~` inside a segment name are
|
|
5
|
+
* escaped after RFC 6901 tilde rules so a key containing `~2` (`~02`) never
|
|
6
|
+
* collides with an escaped dot (`~2`). `/` does not need dotted-layer escaping
|
|
7
|
+
* because `.` is the only segment separator.
|
|
8
|
+
*
|
|
9
|
+
* Ordinary keys without `.` or `~` round-trip unchanged (`vendor`, `items.0.amount`).
|
|
10
|
+
*/
|
|
11
|
+
/** Escape one dotted-path segment for joining with `.`. */
|
|
12
|
+
export declare function encodeDottedPathSegment(segment: string): string;
|
|
13
|
+
/** Decode one dotted-path segment produced by {@link encodeDottedPathSegment}. */
|
|
14
|
+
export declare function decodeDottedPathSegment(segment: string): string;
|
|
15
|
+
/** Split a dotted UI path into decoded segment names. */
|
|
16
|
+
export declare function parseDottedPathSegments(path: string): string[];
|
|
17
|
+
/** RFC 6901 pointer to bijective dotted UI path. */
|
|
18
|
+
export declare function dottedPathFromPointer(pointer: string): string;
|
|
19
|
+
/** Bijective dotted UI path back to an RFC 6901 pointer. */
|
|
20
|
+
export declare function pointerFromDottedPath(dottedPath: string): string;
|
|
21
|
+
//# sourceMappingURL=dotted-path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dotted-path.d.ts","sourceRoot":"","sources":["../src/dotted-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,2DAA2D;AAC3D,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,kFAAkF;AAClF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAsB/D;AAED,yDAAyD;AACzD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAE9D;AAaD,oDAAoD;AACpD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAQ7D;AAED,4DAA4D;AAC5D,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAGhE"}
|
package/dist/fields.d.ts
CHANGED
|
@@ -2,15 +2,13 @@ import type { JsonValue } from './common.js';
|
|
|
2
2
|
import type { ConfidenceAssertion, ConfidenceKind } from './confidence.js';
|
|
3
3
|
import type { LineageDocument } from './document.js';
|
|
4
4
|
import type { Entity } from './entity.js';
|
|
5
|
+
export { decodeDottedPathSegment, dottedPathFromPointer, encodeDottedPathSegment, parseDottedPathSegments, pointerFromDottedPath, } from './dotted-path.js';
|
|
5
6
|
/** How a field's confidence came about, or that none was asserted at all. */
|
|
6
7
|
export type ConfidenceOrigin = ConfidenceKind | 'not_reported';
|
|
7
8
|
export type LineageField = {
|
|
8
9
|
id: string;
|
|
9
10
|
pointer: string;
|
|
10
|
-
/**
|
|
11
|
-
* Display-only dotted rendering of `pointer`. Lossy: a property whose name
|
|
12
|
-
* contains a dot is indistinguishable from nesting. Use `pointer` as the key.
|
|
13
|
-
*/
|
|
11
|
+
/** Dotted UI rendering of `pointer`; bijective with {@link dottedPathFromPointer}. */
|
|
14
12
|
dottedPath: string;
|
|
15
13
|
value: JsonValue | undefined;
|
|
16
14
|
confidence: ConfidenceAssertion | undefined;
|
|
@@ -25,20 +23,6 @@ export type LineageFieldTrace = {
|
|
|
25
23
|
}>;
|
|
26
24
|
activities: string[];
|
|
27
25
|
};
|
|
28
|
-
/**
|
|
29
|
-
* RFC 6901 pointer to dotted display path, unescaping `~1` and `~0`.
|
|
30
|
-
*
|
|
31
|
-
* Display only. A property whose name contains a dot is indistinguishable from
|
|
32
|
-
* nesting, so never use the result as a key.
|
|
33
|
-
*/
|
|
34
|
-
export declare function dottedPathFromPointer(pointer: string): string;
|
|
35
|
-
/**
|
|
36
|
-
* Dotted display path back to an RFC 6901 pointer, escaping `~` and `/`.
|
|
37
|
-
*
|
|
38
|
-
* Only sound for paths `dottedPathFromPointer` could have produced: a property
|
|
39
|
-
* name containing a dot round-trips as nesting. Prefer carrying the pointer.
|
|
40
|
-
*/
|
|
41
|
-
export declare function pointerFromDottedPath(dottedPath: string): string;
|
|
42
26
|
/**
|
|
43
27
|
* The entity holding a field's current value at `pointer`.
|
|
44
28
|
*
|
package/dist/fields.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fields.d.ts","sourceRoot":"","sources":["../src/fields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACxE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"fields.d.ts","sourceRoot":"","sources":["../src/fields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACxE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGvC,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,uBAAuB,EACvB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AAEvB,6EAA6E;AAC7E,MAAM,MAAM,gBAAgB,GAAG,cAAc,GAAG,cAAc,CAAC;AAE/D,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,sFAAsF;IACtF,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,SAAS,GAAG,SAAS,CAAC;IAC7B,UAAU,EAAE,mBAAmB,GAAG,SAAS,CAAC;IAC5C,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,YAAY,CAAC;IACpB,QAAQ,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChD,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB,CAAC;AAcF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,eAAe,EACpB,OAAO,EAAE,MAAM,GACd;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAe5C;AAgBD;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,eAAe,GAAG,YAAY,EAAE,CAS3D;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAmB/F"}
|
package/dist/index.d.ts
CHANGED
|
@@ -14,7 +14,8 @@ export { LineageDocumentSchema, LineageDocumentShapeSchema, parseLineageDocument
|
|
|
14
14
|
export { AttributionSchema, DigestSchema, ENTITY_KINDS, EntityKindSchema, EntitySchema, LocatorSchema, SelectorSchema, type Attribution, type Digest, type Entity, type EntityKind, type Locator, type Selector, } from './entity.js';
|
|
15
15
|
export { LINEAGE_PROV_NAMESPACE, lineageIdToProvQualifiedName, toProvJson, type ProvJsonDocument, } from './prov.js';
|
|
16
16
|
export { RELATION_TYPES, RelationSchema, RelationTypeSchema, type Relation, type RelationType, } from './relation.js';
|
|
17
|
-
export {
|
|
17
|
+
export { decodeDottedPathSegment, dottedPathFromPointer, encodeDottedPathSegment, parseDottedPathSegments, pointerFromDottedPath, } from './dotted-path.js';
|
|
18
|
+
export { fieldEntityByPointer, fieldTrace, fields, type ConfidenceOrigin, type LineageField, type LineageFieldTrace, } from './fields.js';
|
|
18
19
|
export { activityLabel } from './labels.js';
|
|
19
20
|
export { entityAncestors, entityDescendants, topologicalEntityOrder } from './traverse.js';
|
|
20
21
|
export { LineageValidationError, validateLineageGraph } from './validate.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,oBAAoB,EACpB,WAAW,EACX,iBAAiB,EACjB,oBAAoB,EACpB,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,KAAK,EACV,KAAK,WAAW,EAChB,KAAK,cAAc,GACpB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,uBAAuB,EAAE,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE7E,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,eAAe,EACf,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,SAAS,GACf,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,gBAAgB,EAChB,yBAAyB,EACzB,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,gBAAgB,GACtB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,gBAAgB,EAChB,qBAAqB,EACrB,oBAAoB,EACpB,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,cAAc,GACpB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,oBAAoB,EACpB,wBAAwB,EACxB,KAAK,eAAe,GACrB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,MAAM,EACX,KAAK,MAAM,EACX,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,KAAK,QAAQ,GACd,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,sBAAsB,EACtB,4BAA4B,EAC5B,UAAU,EACV,KAAK,gBAAgB,GACtB,MAAM,QAAQ,CAAC;AAEhB,OAAO,EACL,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,KAAK,QAAQ,EACb,KAAK,YAAY,GAClB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,UAAU,EACV,MAAM,EACN,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,oBAAoB,EACpB,WAAW,EACX,iBAAiB,EACjB,oBAAoB,EACpB,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,KAAK,EACV,KAAK,WAAW,EAChB,KAAK,cAAc,GACpB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,uBAAuB,EAAE,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE7E,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,eAAe,EACf,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,SAAS,GACf,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,gBAAgB,EAChB,yBAAyB,EACzB,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,gBAAgB,GACtB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,gBAAgB,EAChB,qBAAqB,EACrB,oBAAoB,EACpB,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,cAAc,GACpB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,oBAAoB,EACpB,wBAAwB,EACxB,KAAK,eAAe,GACrB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,MAAM,EACX,KAAK,MAAM,EACX,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,KAAK,QAAQ,GACd,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,sBAAsB,EACtB,4BAA4B,EAC5B,UAAU,EACV,KAAK,gBAAgB,GACtB,MAAM,QAAQ,CAAC;AAEhB,OAAO,EACL,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,KAAK,QAAQ,EACb,KAAK,YAAY,GAClB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,uBAAuB,EACvB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,oBAAoB,EACpB,UAAU,EACV,MAAM,EACN,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,iBAAiB,GACvB,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAExF,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -663,6 +663,58 @@ function flattenAttrs(attrs) {
|
|
|
663
663
|
return out;
|
|
664
664
|
}
|
|
665
665
|
|
|
666
|
+
// src/dotted-path.ts
|
|
667
|
+
var DOTTED_SEGMENT_DOT = "~2";
|
|
668
|
+
var JSON_POINTER_ESCAPE = /~(?:0|1)/g;
|
|
669
|
+
var INVALID_JSON_POINTER_ESCAPE = /~(?![01])/;
|
|
670
|
+
var INVALID_DOTTED_PATH_ESCAPE = /~(?![02])/;
|
|
671
|
+
function encodeDottedPathSegment(segment) {
|
|
672
|
+
return segment.replaceAll("~", "~0").replaceAll(".", DOTTED_SEGMENT_DOT);
|
|
673
|
+
}
|
|
674
|
+
function decodeDottedPathSegment(segment) {
|
|
675
|
+
if (INVALID_DOTTED_PATH_ESCAPE.test(segment)) {
|
|
676
|
+
throw new Error(`Invalid dotted path escape in segment "${segment}"`);
|
|
677
|
+
}
|
|
678
|
+
let decoded = "";
|
|
679
|
+
for (let index = 0; index < segment.length; index += 1) {
|
|
680
|
+
if (segment[index] === "~" && index + 1 < segment.length) {
|
|
681
|
+
const code = segment[index + 1];
|
|
682
|
+
if (code === "0") {
|
|
683
|
+
decoded += "~";
|
|
684
|
+
index += 1;
|
|
685
|
+
continue;
|
|
686
|
+
}
|
|
687
|
+
if (code === "2") {
|
|
688
|
+
decoded += ".";
|
|
689
|
+
index += 1;
|
|
690
|
+
continue;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
decoded += segment[index];
|
|
694
|
+
}
|
|
695
|
+
return decoded;
|
|
696
|
+
}
|
|
697
|
+
function parseDottedPathSegments(path) {
|
|
698
|
+
return path.split(".").filter(Boolean).map(decodeDottedPathSegment);
|
|
699
|
+
}
|
|
700
|
+
function encodeJsonPointerSegment(segment) {
|
|
701
|
+
return segment.replaceAll("~", "~0").replaceAll("/", "~1");
|
|
702
|
+
}
|
|
703
|
+
function decodeJsonPointerSegment(segment) {
|
|
704
|
+
if (INVALID_JSON_POINTER_ESCAPE.test(segment)) {
|
|
705
|
+
throw new Error(`Invalid JSON Pointer escape in segment "${segment}"`);
|
|
706
|
+
}
|
|
707
|
+
return segment.replace(JSON_POINTER_ESCAPE, (escape) => escape === "~1" ? "/" : "~");
|
|
708
|
+
}
|
|
709
|
+
function dottedPathFromPointer(pointer) {
|
|
710
|
+
if (pointer === "" || pointer === "/") return "";
|
|
711
|
+
return pointer.slice(1).split("/").map(decodeJsonPointerSegment).map(encodeDottedPathSegment).join(".");
|
|
712
|
+
}
|
|
713
|
+
function pointerFromDottedPath(dottedPath) {
|
|
714
|
+
if (dottedPath === "") return "";
|
|
715
|
+
return `/${parseDottedPathSegments(dottedPath).map(encodeJsonPointerSegment).join("/")}`;
|
|
716
|
+
}
|
|
717
|
+
|
|
666
718
|
// src/traverse.ts
|
|
667
719
|
function buildForwardEdges(doc) {
|
|
668
720
|
const edges = /* @__PURE__ */ new Map();
|
|
@@ -746,14 +798,6 @@ function fieldConfidence(entity) {
|
|
|
746
798
|
if (!assertions || assertions.length === 0) return void 0;
|
|
747
799
|
return assertions.find((assertion) => assertion.scope === "extraction") ?? assertions[0];
|
|
748
800
|
}
|
|
749
|
-
function dottedPathFromPointer(pointer) {
|
|
750
|
-
if (pointer === "" || pointer === "/") return "";
|
|
751
|
-
return pointer.replace(/^\//, "").split("/").map((segment) => segment.replace(/~1/g, "/").replace(/~0/g, "~")).join(".");
|
|
752
|
-
}
|
|
753
|
-
function pointerFromDottedPath(dottedPath) {
|
|
754
|
-
if (dottedPath === "") return "";
|
|
755
|
-
return `/${dottedPath.split(".").map((segment) => segment.replaceAll("~", "~0").replaceAll("/", "~1")).join("/")}`;
|
|
756
|
-
}
|
|
757
801
|
function fieldEntityByPointer(doc, pointer) {
|
|
758
802
|
const matching = Object.entries(doc.entities).filter(([, entity]) => entity.path === pointer);
|
|
759
803
|
if (matching.length === 0) return void 0;
|
|
@@ -852,8 +896,10 @@ export {
|
|
|
852
896
|
TimestampSchema,
|
|
853
897
|
TransformationSchema,
|
|
854
898
|
activityLabel,
|
|
899
|
+
decodeDottedPathSegment,
|
|
855
900
|
derivationId,
|
|
856
901
|
dottedPathFromPointer,
|
|
902
|
+
encodeDottedPathSegment,
|
|
857
903
|
entityAncestors,
|
|
858
904
|
entityDescendants,
|
|
859
905
|
fieldEntityByPointer,
|
|
@@ -861,6 +907,7 @@ export {
|
|
|
861
907
|
fields,
|
|
862
908
|
jsonValuesEqual,
|
|
863
909
|
lineageIdToProvQualifiedName,
|
|
910
|
+
parseDottedPathSegments,
|
|
864
911
|
parseLineageDocument,
|
|
865
912
|
pointerFromDottedPath,
|
|
866
913
|
safeParseLineageDocument,
|
package/dist/profile/index.js
CHANGED
|
@@ -10,6 +10,24 @@ function activityLabel(activity) {
|
|
|
10
10
|
return activity.name ?? ACTIVITY_LABELS[activity.type] ?? activity.type;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
// src/dotted-path.ts
|
|
14
|
+
var DOTTED_SEGMENT_DOT = "~2";
|
|
15
|
+
var JSON_POINTER_ESCAPE = /~(?:0|1)/g;
|
|
16
|
+
var INVALID_JSON_POINTER_ESCAPE = /~(?![01])/;
|
|
17
|
+
function encodeDottedPathSegment(segment) {
|
|
18
|
+
return segment.replaceAll("~", "~0").replaceAll(".", DOTTED_SEGMENT_DOT);
|
|
19
|
+
}
|
|
20
|
+
function decodeJsonPointerSegment(segment) {
|
|
21
|
+
if (INVALID_JSON_POINTER_ESCAPE.test(segment)) {
|
|
22
|
+
throw new Error(`Invalid JSON Pointer escape in segment "${segment}"`);
|
|
23
|
+
}
|
|
24
|
+
return segment.replace(JSON_POINTER_ESCAPE, (escape) => escape === "~1" ? "/" : "~");
|
|
25
|
+
}
|
|
26
|
+
function dottedPathFromPointer(pointer) {
|
|
27
|
+
if (pointer === "" || pointer === "/") return "";
|
|
28
|
+
return pointer.slice(1).split("/").map(decodeJsonPointerSegment).map(encodeDottedPathSegment).join(".");
|
|
29
|
+
}
|
|
30
|
+
|
|
13
31
|
// src/traverse.ts
|
|
14
32
|
function buildReverseEdges(doc) {
|
|
15
33
|
const edges = /* @__PURE__ */ new Map();
|
|
@@ -50,10 +68,6 @@ function fieldConfidence(entity) {
|
|
|
50
68
|
if (!assertions || assertions.length === 0) return void 0;
|
|
51
69
|
return assertions.find((assertion) => assertion.scope === "extraction") ?? assertions[0];
|
|
52
70
|
}
|
|
53
|
-
function dottedPathFromPointer(pointer) {
|
|
54
|
-
if (pointer === "" || pointer === "/") return "";
|
|
55
|
-
return pointer.replace(/^\//, "").split("/").map((segment) => segment.replace(/~1/g, "/").replace(/~0/g, "~")).join(".");
|
|
56
|
-
}
|
|
57
71
|
function toField(id, entity) {
|
|
58
72
|
const pointer = fieldPointer(entity);
|
|
59
73
|
const confidence = fieldConfidence(entity);
|
package/package.json
CHANGED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bijective JSON Pointer ↔ dotted UI path encoding.
|
|
3
|
+
*
|
|
4
|
+
* Segments are joined with `.`. Literal `.` and `~` inside a segment name are
|
|
5
|
+
* escaped after RFC 6901 tilde rules so a key containing `~2` (`~02`) never
|
|
6
|
+
* collides with an escaped dot (`~2`). `/` does not need dotted-layer escaping
|
|
7
|
+
* because `.` is the only segment separator.
|
|
8
|
+
*
|
|
9
|
+
* Ordinary keys without `.` or `~` round-trip unchanged (`vendor`, `items.0.amount`).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const DOTTED_SEGMENT_DOT = '~2';
|
|
13
|
+
const JSON_POINTER_ESCAPE = /~(?:0|1)/g;
|
|
14
|
+
const INVALID_JSON_POINTER_ESCAPE = /~(?![01])/;
|
|
15
|
+
const INVALID_DOTTED_PATH_ESCAPE = /~(?![02])/;
|
|
16
|
+
|
|
17
|
+
/** Escape one dotted-path segment for joining with `.`. */
|
|
18
|
+
export function encodeDottedPathSegment(segment: string): string {
|
|
19
|
+
return segment.replaceAll('~', '~0').replaceAll('.', DOTTED_SEGMENT_DOT);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Decode one dotted-path segment produced by {@link encodeDottedPathSegment}. */
|
|
23
|
+
export function decodeDottedPathSegment(segment: string): string {
|
|
24
|
+
if (INVALID_DOTTED_PATH_ESCAPE.test(segment)) {
|
|
25
|
+
throw new Error(`Invalid dotted path escape in segment "${segment}"`);
|
|
26
|
+
}
|
|
27
|
+
let decoded = '';
|
|
28
|
+
for (let index = 0; index < segment.length; index += 1) {
|
|
29
|
+
if (segment[index] === '~' && index + 1 < segment.length) {
|
|
30
|
+
const code = segment[index + 1];
|
|
31
|
+
if (code === '0') {
|
|
32
|
+
decoded += '~';
|
|
33
|
+
index += 1;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (code === '2') {
|
|
37
|
+
decoded += '.';
|
|
38
|
+
index += 1;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
decoded += segment[index];
|
|
43
|
+
}
|
|
44
|
+
return decoded;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Split a dotted UI path into decoded segment names. */
|
|
48
|
+
export function parseDottedPathSegments(path: string): string[] {
|
|
49
|
+
return path.split('.').filter(Boolean).map(decodeDottedPathSegment);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function encodeJsonPointerSegment(segment: string): string {
|
|
53
|
+
return segment.replaceAll('~', '~0').replaceAll('/', '~1');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function decodeJsonPointerSegment(segment: string): string {
|
|
57
|
+
if (INVALID_JSON_POINTER_ESCAPE.test(segment)) {
|
|
58
|
+
throw new Error(`Invalid JSON Pointer escape in segment "${segment}"`);
|
|
59
|
+
}
|
|
60
|
+
return segment.replace(JSON_POINTER_ESCAPE, (escape) => (escape === '~1' ? '/' : '~'));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** RFC 6901 pointer to bijective dotted UI path. */
|
|
64
|
+
export function dottedPathFromPointer(pointer: string): string {
|
|
65
|
+
if (pointer === '' || pointer === '/') return '';
|
|
66
|
+
return pointer
|
|
67
|
+
.slice(1)
|
|
68
|
+
.split('/')
|
|
69
|
+
.map(decodeJsonPointerSegment)
|
|
70
|
+
.map(encodeDottedPathSegment)
|
|
71
|
+
.join('.');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Bijective dotted UI path back to an RFC 6901 pointer. */
|
|
75
|
+
export function pointerFromDottedPath(dottedPath: string): string {
|
|
76
|
+
if (dottedPath === '') return '';
|
|
77
|
+
return `/${parseDottedPathSegments(dottedPath).map(encodeJsonPointerSegment).join('/')}`;
|
|
78
|
+
}
|
package/src/fields.ts
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
import type { JsonValue } from './common';
|
|
2
2
|
import type { ConfidenceAssertion, ConfidenceKind } from './confidence';
|
|
3
3
|
import type { LineageDocument } from './document';
|
|
4
|
+
import { dottedPathFromPointer } from './dotted-path';
|
|
4
5
|
import type { Entity } from './entity';
|
|
5
6
|
import { entityAncestors } from './traverse';
|
|
6
7
|
|
|
8
|
+
export {
|
|
9
|
+
decodeDottedPathSegment,
|
|
10
|
+
dottedPathFromPointer,
|
|
11
|
+
encodeDottedPathSegment,
|
|
12
|
+
parseDottedPathSegments,
|
|
13
|
+
pointerFromDottedPath,
|
|
14
|
+
} from './dotted-path';
|
|
15
|
+
|
|
7
16
|
/** How a field's confidence came about, or that none was asserted at all. */
|
|
8
17
|
export type ConfidenceOrigin = ConfidenceKind | 'not_reported';
|
|
9
18
|
|
|
10
19
|
export type LineageField = {
|
|
11
20
|
id: string;
|
|
12
21
|
pointer: string;
|
|
13
|
-
/**
|
|
14
|
-
* Display-only dotted rendering of `pointer`. Lossy: a property whose name
|
|
15
|
-
* contains a dot is indistinguishable from nesting. Use `pointer` as the key.
|
|
16
|
-
*/
|
|
22
|
+
/** Dotted UI rendering of `pointer`; bijective with {@link dottedPathFromPointer}. */
|
|
17
23
|
dottedPath: string;
|
|
18
24
|
value: JsonValue | undefined;
|
|
19
25
|
confidence: ConfidenceAssertion | undefined;
|
|
@@ -39,35 +45,6 @@ function fieldConfidence(entity: Entity): ConfidenceAssertion | undefined {
|
|
|
39
45
|
return assertions.find((assertion) => assertion.scope === 'extraction') ?? assertions[0];
|
|
40
46
|
}
|
|
41
47
|
|
|
42
|
-
/**
|
|
43
|
-
* RFC 6901 pointer to dotted display path, unescaping `~1` and `~0`.
|
|
44
|
-
*
|
|
45
|
-
* Display only. A property whose name contains a dot is indistinguishable from
|
|
46
|
-
* nesting, so never use the result as a key.
|
|
47
|
-
*/
|
|
48
|
-
export function dottedPathFromPointer(pointer: string): string {
|
|
49
|
-
if (pointer === '' || pointer === '/') return '';
|
|
50
|
-
return pointer
|
|
51
|
-
.replace(/^\//, '')
|
|
52
|
-
.split('/')
|
|
53
|
-
.map((segment) => segment.replace(/~1/g, '/').replace(/~0/g, '~'))
|
|
54
|
-
.join('.');
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Dotted display path back to an RFC 6901 pointer, escaping `~` and `/`.
|
|
59
|
-
*
|
|
60
|
-
* Only sound for paths `dottedPathFromPointer` could have produced: a property
|
|
61
|
-
* name containing a dot round-trips as nesting. Prefer carrying the pointer.
|
|
62
|
-
*/
|
|
63
|
-
export function pointerFromDottedPath(dottedPath: string): string {
|
|
64
|
-
if (dottedPath === '') return '';
|
|
65
|
-
return `/${dottedPath
|
|
66
|
-
.split('.')
|
|
67
|
-
.map((segment) => segment.replaceAll('~', '~0').replaceAll('/', '~1'))
|
|
68
|
-
.join('/')}`;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
48
|
/**
|
|
72
49
|
* The entity holding a field's current value at `pointer`.
|
|
73
50
|
*
|
package/src/index.ts
CHANGED
|
@@ -106,11 +106,17 @@ export {
|
|
|
106
106
|
} from './relation';
|
|
107
107
|
|
|
108
108
|
export {
|
|
109
|
+
decodeDottedPathSegment,
|
|
109
110
|
dottedPathFromPointer,
|
|
111
|
+
encodeDottedPathSegment,
|
|
112
|
+
parseDottedPathSegments,
|
|
113
|
+
pointerFromDottedPath,
|
|
114
|
+
} from './dotted-path';
|
|
115
|
+
|
|
116
|
+
export {
|
|
110
117
|
fieldEntityByPointer,
|
|
111
118
|
fieldTrace,
|
|
112
119
|
fields,
|
|
113
|
-
pointerFromDottedPath,
|
|
114
120
|
type ConfidenceOrigin,
|
|
115
121
|
type LineageField,
|
|
116
122
|
type LineageFieldTrace,
|