@mailwoman/core 2.2.0 → 4.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.
Files changed (62) hide show
  1. package/out/classification/Classification.d.ts +2 -2
  2. package/out/decoder/build-tree.d.ts +13 -4
  3. package/out/decoder/build-tree.d.ts.map +1 -1
  4. package/out/decoder/build-tree.js +36 -8
  5. package/out/decoder/build-tree.js.map +1 -1
  6. package/out/decoder/containment.d.ts +31 -2
  7. package/out/decoder/containment.d.ts.map +1 -1
  8. package/out/decoder/containment.js +36 -3
  9. package/out/decoder/containment.js.map +1 -1
  10. package/out/decoder/index.d.ts +1 -0
  11. package/out/decoder/index.d.ts.map +1 -1
  12. package/out/decoder/index.js +1 -0
  13. package/out/decoder/index.js.map +1 -1
  14. package/out/decoder/types.d.ts +21 -0
  15. package/out/decoder/types.d.ts.map +1 -1
  16. package/out/decoder/validate-tree.d.ts +39 -0
  17. package/out/decoder/validate-tree.d.ts.map +1 -0
  18. package/out/decoder/validate-tree.js +79 -0
  19. package/out/decoder/validate-tree.js.map +1 -0
  20. package/out/pipeline/index.d.ts +1 -1
  21. package/out/pipeline/index.d.ts.map +1 -1
  22. package/out/pipeline/runtime-pipeline.d.ts.map +1 -1
  23. package/out/pipeline/runtime-pipeline.js +68 -8
  24. package/out/pipeline/runtime-pipeline.js.map +1 -1
  25. package/out/pipeline/span-logit-aggregation.d.ts +3 -2
  26. package/out/pipeline/span-logit-aggregation.d.ts.map +1 -1
  27. package/out/pipeline/span-logit-aggregation.js +3 -2
  28. package/out/pipeline/span-logit-aggregation.js.map +1 -1
  29. package/out/pipeline/types.d.ts +40 -12
  30. package/out/pipeline/types.d.ts.map +1 -1
  31. package/out/resolver/resolve.js +50 -8
  32. package/out/resolver/resolve.js.map +1 -1
  33. package/out/resolver/types.d.ts +30 -0
  34. package/out/resolver/types.d.ts.map +1 -1
  35. package/out/resolver/types.js +2 -0
  36. package/out/resolver/types.js.map +1 -1
  37. package/out/resources/whosonfirst/PlacetypeDataSource.d.ts.map +1 -1
  38. package/out/resources/whosonfirst/PlacetypeDataSource.js +3 -1
  39. package/out/resources/whosonfirst/PlacetypeDataSource.js.map +1 -1
  40. package/out/resources/whosonfirst/placetypes/admin.d.ts +23 -1
  41. package/out/resources/whosonfirst/placetypes/admin.d.ts.map +1 -1
  42. package/out/resources/whosonfirst/placetypes/admin.js +14 -1
  43. package/out/resources/whosonfirst/placetypes/admin.js.map +1 -1
  44. package/out/resources/whosonfirst/placetypes/graph.d.ts +47 -0
  45. package/out/resources/whosonfirst/placetypes/graph.d.ts.map +1 -0
  46. package/out/resources/whosonfirst/placetypes/graph.js +0 -0
  47. package/out/resources/whosonfirst/placetypes/graph.js.map +1 -0
  48. package/out/resources/whosonfirst/placetypes/index.d.ts +2 -0
  49. package/out/resources/whosonfirst/placetypes/index.d.ts.map +1 -1
  50. package/out/resources/whosonfirst/placetypes/index.js +2 -0
  51. package/out/resources/whosonfirst/placetypes/index.js.map +1 -1
  52. package/out/resources/whosonfirst/placetypes/mermaid.d.ts +35 -3
  53. package/out/resources/whosonfirst/placetypes/mermaid.d.ts.map +1 -1
  54. package/out/resources/whosonfirst/placetypes/mermaid.js +87 -15
  55. package/out/resources/whosonfirst/placetypes/mermaid.js.map +1 -1
  56. package/out/resources/whosonfirst/placetypes/tree.d.ts +30 -0
  57. package/out/resources/whosonfirst/placetypes/tree.d.ts.map +1 -0
  58. package/out/resources/whosonfirst/placetypes/tree.js +28 -0
  59. package/out/resources/whosonfirst/placetypes/tree.js.map +1 -0
  60. package/out/solver/SolutionMatch.d.ts +1 -1
  61. package/out/solver/mask.d.ts +1 -1
  62. package/package.json +7 -1
@@ -10,7 +10,7 @@ export function parsePlacetypeSource(key) {
10
10
  const [, languageCode, nameKind] = (langPattern.exec(key) ?? []);
11
11
  return { languageCode, nameKind };
12
12
  }
13
- export function pluckPlacetypeSpec({ "wof:id": id, "wof:name": name, "wof:src": wof_src, "src:geom": geom_src, "wof:parent_id": parent_id, "wof:placetype": placetype, "wof:superseded_by": superseded_by, ...props }) {
13
+ export function pluckPlacetypeSpec({ "wof:id": id, "wof:name": name, "wof:src": wof_src, "src:geom": geom_src, "wof:parent_id": parent_id, "wof:placetype": placetype, "wof:superseded_by": superseded_by, "wof:supersedes": supersedes, "wof:country": country, "wof:concordances": concordances, "wof:population": wofPopulation, "wof:lastmodified": lastmodified, "geom:latitude": latitude, "geom:longitude": longitude, "gn:population": gnPopulation, "mz:is_current": mzIsCurrent, "edtf:deprecated": edtfDeprecated, "edtf:cessation": edtfCessation, ...props }) {
14
14
  const localizedPropMap = new Map();
15
15
  for (const [key, value] of Object.entries(props)) {
16
16
  if (!value)
@@ -33,6 +33,8 @@ export function pluckPlacetypeSpec({ "wof:id": id, "wof:name": name, "wof:src":
33
33
  const src = wof_src || geom_src || "unknown";
34
34
  if (!src)
35
35
  throw new Error(`No source found for placetype ${placetype} with ID ${id}`);
36
+ const population = typeof wofPopulation === "number" ? wofPopulation : typeof gnPopulation === "number" ? gnPopulation : undefined;
37
+ const isCurrent = mzIsCurrent === undefined ? undefined : mzIsCurrent !== 0 && mzIsCurrent !== "0";
36
38
  return {
37
39
  id,
38
40
  name,
@@ -40,6 +42,17 @@ export function pluckPlacetypeSpec({ "wof:id": id, "wof:name": name, "wof:src":
40
42
  parent_id,
41
43
  placetype,
42
44
  localizedPropMap,
45
+ country: country || undefined,
46
+ latitude: typeof latitude === "number" ? latitude : undefined,
47
+ longitude: typeof longitude === "number" ? longitude : undefined,
48
+ population,
49
+ concordances: concordances && Object.keys(concordances).length > 0 ? concordances : undefined,
50
+ isCurrent,
51
+ isDeprecated: !!edtfDeprecated,
52
+ isCeased: !!edtfCessation,
53
+ isSuperseded: !!(superseded_by && superseded_by.length > 0),
54
+ isSuperseding: !!(supersedes && supersedes.length > 0),
55
+ lastmodified: typeof lastmodified === "number" ? lastmodified : undefined,
43
56
  };
44
57
  }
45
58
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"admin.js","sourceRoot":"","sources":["../../../../resources/whosonfirst/placetypes/admin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACN,kBAAkB,EAElB,eAAe,EACf,oBAAoB,EACpB,qBAAqB,GACrB,MAAM,qCAAqC,CAAA;AAc5C,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,CAAU,CAAA;AAuB5F,MAAM,WAAW,GAAG,IAAI,MAAM,CAAC,2BAA2B,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;AAEpF,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC/C,MAAM,CAAC,EAAE,YAAY,EAAE,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,GAAa,CAAC,IAAI,EAAE,CAExE,CAAA;IAED,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAA;AAClC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,EAClC,QAAQ,EAAE,EAAE,EACZ,UAAU,EAAE,IAAI,EAChB,SAAS,EAAE,OAAO,EAClB,UAAU,EAAE,QAAQ,EACpB,eAAe,EAAE,SAAS,EAC1B,eAAe,EAAE,SAAS,EAC1B,mBAAmB,EAAE,aAAa,EAClC,GAAG,KAAK,EACO;IACf,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAkD,CAAA;IAElF,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAClD,IAAI,CAAC,KAAK;YAAE,SAAQ;QACpB,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,SAAQ;QAEjD,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAA;QAE5D,IAAI,CAAC,YAAY,IAAI,CAAC,QAAQ;YAAE,SAAQ;QAExC,IAAI,OAAO,GAAG,gBAAgB,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;QAEhD,IAAI,CAAC,OAAO,EAAE,CAAC;YACd,OAAO,GAAG,IAAI,GAAG,EAAE,CAAA;YACnB,gBAAgB,CAAC,GAAG,CAAC,YAAY,EAAE,OAAO,CAAC,CAAA;QAC5C,CAAC;QAED,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;QAE1D,IAAI,UAAU,EAAE,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QAClC,CAAC;IACF,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,IAAI,QAAQ,IAAI,SAAS,CAAA;IAE5C,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,SAAS,YAAY,EAAE,EAAE,CAAC,CAAA;IAErF,OAAO;QACN,EAAE;QACF,IAAI;QACJ,GAAG;QACH,SAAS;QACT,SAAS;QACT,gBAAgB;KAChB,CAAA;AACF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CAAC,QAAgB;IACzD,MAAM,CAAC,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,4BAA4B,CAAC,IAAI,EAAE,CAAA;IAE3E,IAAI,CAAC,YAAY;QAAE,OAAO,IAAI,CAAA;IAE9B,IAAI,oBAAoB,CAAC,YAAY,CAAC;QAAE,OAAO,YAAY,CAAA;IAC3D,IAAI,qBAAqB,CAAC,YAAY,CAAC;QAAE,OAAO,eAAe,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,IAAI,CAAA;IAEzF,OAAO,IAAI,CAAA;AACZ,CAAC"}
1
+ {"version":3,"file":"admin.js","sourceRoot":"","sources":["../../../../resources/whosonfirst/placetypes/admin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ */
6
+ import type { PlacetypeRole } from "./definition.js";
7
+ import { Placetype } from "./Placetype.js";
8
+ /**
9
+ * A single node in a placetype graph. One entry per unique placetype name.
10
+ */
11
+ export interface PlacetypeGraphNode {
12
+ name: string;
13
+ /** Brooklyn Integers ID. */
14
+ id: number;
15
+ role: PlacetypeRole;
16
+ }
17
+ /**
18
+ * A directed parent → child edge. Field names match d3-force / react-flow / cytoscape conventions
19
+ * so the graph drops straight into common viewers.
20
+ */
21
+ export interface PlacetypeGraphLink {
22
+ source: string;
23
+ target: string;
24
+ }
25
+ /**
26
+ * Node-link projection of the placetype DAG rooted at a given placetype. Each node and each
27
+ * (parent, child) edge appears exactly once — see {@linkcode generatePlacetypeGraph} for why this is
28
+ * the preferred shape when the root has many shared descendants (e.g. `planet`).
29
+ */
30
+ export interface PlacetypeGraph {
31
+ root: string;
32
+ nodes: PlacetypeGraphNode[];
33
+ links: PlacetypeGraphLink[];
34
+ }
35
+ /**
36
+ * Build a node-link graph of a placetype and its descendants, optionally filtered by role.
37
+ *
38
+ * Unlike {@linkcode generatePlacetypeTree}, this emits each node and each (parent, child) edge
39
+ * exactly once. WOF placetypes form a DAG with heavy descendant sharing (e.g. `installation` is a
40
+ * leaf reachable from many parents); projecting that DAG to a nested tree duplicates every shared
41
+ * subtree under every parent path and blows up exponentially for roots like `planet` (~165 MB for
42
+ * the full hierarchy). The graph shape stays O(nodes + edges) regardless.
43
+ *
44
+ * Output is well-suited for d3-force, react-flow, cytoscape, and any other HTML graph viewer.
45
+ */
46
+ export declare function generatePlacetypeGraph(placetype: Placetype, roles?: Iterable<PlacetypeRole> | null): PlacetypeGraph;
47
+ //# sourceMappingURL=graph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../../../resources/whosonfirst/placetypes/graph.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE1C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,4BAA4B;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,aAAa,CAAA;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACd;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,kBAAkB,EAAE,CAAA;IAC3B,KAAK,EAAE,kBAAkB,EAAE,CAAA;CAC3B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,IAAI,GAAG,cAAc,CAsCnH"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.js","sourceRoot":"","sources":["../../../../resources/whosonfirst/placetypes/graph.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAgC1C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,sBAAsB,CAAC,SAAoB,EAAE,KAAsC;IAClG,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAE7C,MAAM,KAAK,GAAG,IAAI,GAAG,EAA8B,CAAA;IACnD,MAAM,KAAK,GAAyB,EAAE,CAAA;IACtC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAA;IACnC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAA;IAEhC,MAAM,OAAO,GAAG,CAAC,CAAY,EAAQ,EAAE;QACtC,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAAE,OAAM;QAC7B,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;IAC5D,CAAC,CAAA;IAED,MAAM,IAAI,GAAG,CAAC,IAAe,EAAQ,EAAE;QACtC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAErB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;YAChD,OAAO,CAAC,KAAK,CAAC,CAAA;YAEd,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE,CAAA;YAC5C,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC7B,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;gBACtB,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;YACtD,CAAC;YAED,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;gBAAE,SAAQ;YACpC,IAAI,CAAC,KAAK,CAAC,CAAA;QACZ,CAAC;IACF,CAAC,CAAA;IAED,OAAO,CAAC,SAAS,CAAC,CAAA;IAClB,IAAI,CAAC,SAAS,CAAC,CAAA;IAEf,OAAO;QACN,IAAI,EAAE,SAAS,CAAC,IAAI;QACpB,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QACjC,KAAK;KACL,CAAA;AACF,CAAC"}
@@ -5,6 +5,8 @@
5
5
  */
6
6
  export * from "./admin.js";
7
7
  export * from "./definition.js";
8
+ export * from "./graph.js";
8
9
  export * from "./mermaid.js";
9
10
  export * from "./Placetype.js";
11
+ export * from "./tree.js";
10
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../resources/whosonfirst/placetypes/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../resources/whosonfirst/placetypes/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA"}
@@ -5,6 +5,8 @@
5
5
  */
6
6
  export * from "./admin.js";
7
7
  export * from "./definition.js";
8
+ export * from "./graph.js";
8
9
  export * from "./mermaid.js";
9
10
  export * from "./Placetype.js";
11
+ export * from "./tree.js";
10
12
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../resources/whosonfirst/placetypes/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../resources/whosonfirst/placetypes/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA"}
@@ -3,18 +3,50 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  */
6
- import type { PlacetypeRole } from "./definition.js";
6
+ import { type PlacetypeRole } from "./definition.js";
7
7
  import { Placetype } from "./Placetype.js";
8
8
  /**
9
- * Colors for placetype roles.
9
+ * Hand-tuned default colors for placetype roles. Used when no `interpolator` is passed to
10
+ * {@linkcode generateMermaidMarkup}. Each entry pairs a fill with a darker stroke and a text color
11
+ * chosen for contrast against the fill.
10
12
  */
11
13
  export declare const PlacetypeRoleColor: {
12
14
  readonly common: "#0066cc";
13
15
  readonly common_optional: "#00cc66";
14
16
  readonly optional: "#ffcc00";
15
17
  };
18
+ /**
19
+ * A color interpolator — compatible with d3-scale-chromatic's `interpolate*` functions (e.g.
20
+ * `interpolateViridis`, `interpolateTurbo`). Receives `t ∈ [0, 1]` and returns a CSS color string.
21
+ */
22
+ export type InterpolateColorCallback = (t: number) => string;
23
+ export interface GenerateMermaidMarkupOptions {
24
+ /** Restrict descendants to the given roles. Default: all roles. */
25
+ roles?: Iterable<PlacetypeRole>;
26
+ /**
27
+ * Edge color interpolator. Each edge is colored by its child node's depth from the root: `t =
28
+ * (childDepth - 1) / (maxDepth - 1)`. This traces a smooth gradient along any lineage path (e.g.
29
+ * `planet → continent → country → …`) and gives a visual cue for how deep an edge sits in the
30
+ * tree.
31
+ *
32
+ * Defaults to d3-scale-chromatic's `interpolateViridis` — perceptually uniform and
33
+ * colorblind-friendly. Node fills/strokes are _not_ affected; they always use the hand-tuned
34
+ * {@linkcode PlacetypeRoleColor} palette, which carries more semantic weight than a sampled
35
+ * gradient for only three categorical role values.
36
+ */
37
+ edgeInterpolator?: InterpolateColorCallback;
38
+ }
16
39
  /**
17
40
  * Generate a Mermaid flowchart markup for a placetype and its descendants.
41
+ *
42
+ * The walk is a recursive `findChildren` traversal — every emitted edge is a real direct-parent →
43
+ * direct-child relationship. WOF placetypes form a DAG (e.g. `borough` has both `country` and
44
+ * `macroregion` as parents), so a child can legitimately appear on multiple edges; the `visited`
45
+ * set prevents the subtree below it from being re-emitted.
46
+ *
47
+ * Edges are colored by depth from the root via
48
+ * {@linkcode GenerateMermaidMarkupOptions.edgeInterpolator} (default: viridis), so any lineage path
49
+ * traces a smooth gradient down the chart. Node fills always use the hand-tuned role palette.
18
50
  */
19
- export declare function generateMermaidMarkup(placetype: Placetype, roles?: Iterable<PlacetypeRole>): string;
51
+ export declare function generateMermaidMarkup(placetype: Placetype, options?: GenerateMermaidMarkupOptions): string;
20
52
  //# sourceMappingURL=mermaid.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mermaid.d.ts","sourceRoot":"","sources":["../../../../resources/whosonfirst/placetypes/mermaid.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE1C;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;;CAImB,CAAA;AAElD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,MAAM,CA8BnG"}
1
+ {"version":3,"file":"mermaid.d.ts","sourceRoot":"","sources":["../../../../resources/whosonfirst/placetypes/mermaid.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,KAAK,aAAa,EAAkB,MAAM,iBAAiB,CAAA;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAa1C;;;;GAIG;AACH,eAAO,MAAM,kBAAkB;;;;CAImB,CAAA;AAclD;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;AAE5D,MAAM,WAAW,4BAA4B;IAC5C,mEAAmE;IACnE,KAAK,CAAC,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAA;IAC/B;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,EAAE,wBAAwB,CAAA;CAC3C;AAuCD;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,GAAE,4BAAiC,GAAG,MAAM,CA+C9G"}
@@ -3,19 +3,81 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  */
6
+ import { rgb } from "d3-color";
7
+ import { interpolateViridis } from "d3-scale-chromatic";
8
+ import { PlacetypeRoles } from "./definition.js";
6
9
  import { Placetype } from "./Placetype.js";
7
10
  /**
8
- * Colors for placetype roles.
11
+ * Mermaid's `classDef` parser uses commas to separate style properties, so an `rgb(r, g, b)` value
12
+ * (which d3-scale-chromatic emits for several interpolators, e.g. `interpolateRainbow`,
13
+ * `interpolateTurbo`, `interpolateSinebow`) breaks the parse. Convert any d3-color-recognised input
14
+ * to hex before embedding. `d3-color` already handles hex/rgb/rgba/hsl/named inputs.
15
+ */
16
+ function toMermaidColor(input) {
17
+ const parsed = rgb(input);
18
+ return Number.isNaN(parsed.r) ? input : parsed.formatHex();
19
+ }
20
+ /**
21
+ * Hand-tuned default colors for placetype roles. Used when no `interpolator` is passed to
22
+ * {@linkcode generateMermaidMarkup}. Each entry pairs a fill with a darker stroke and a text color
23
+ * chosen for contrast against the fill.
9
24
  */
10
25
  export const PlacetypeRoleColor = {
11
26
  common: "#0066cc",
12
27
  common_optional: "#00cc66",
13
28
  optional: "#ffcc00",
14
29
  };
30
+ const PlacetypeRoleStroke = {
31
+ common: "#004d99",
32
+ common_optional: "#009933",
33
+ optional: "#cca300",
34
+ };
35
+ const PlacetypeRoleText = {
36
+ common: "white",
37
+ common_optional: "white",
38
+ optional: "black",
39
+ };
40
+ const HAND_TUNED_PALETTE = Object.fromEntries(PlacetypeRoles.map((role) => [
41
+ role,
42
+ { fill: PlacetypeRoleColor[role], stroke: PlacetypeRoleStroke[role], text: PlacetypeRoleText[role] },
43
+ ]));
44
+ /**
45
+ * Walk the (filtered) subtree once to determine the deepest reachable descendant. Mirrors the
46
+ * structure of the emit-walk in {@linkcode generateMermaidMarkup} so the depths it computes line up
47
+ * with the edges that will be emitted. Cycles in the DAG are guarded by the `visited` set.
48
+ */
49
+ function measureMaxDepth(root, roles) {
50
+ let maxDepth = 0;
51
+ const visited = new Set();
52
+ const walk = (node, depth) => {
53
+ for (const child of node.findChildren(roles)) {
54
+ const childDepth = depth + 1;
55
+ if (childDepth > maxDepth)
56
+ maxDepth = childDepth;
57
+ if (visited.has(child.name))
58
+ continue;
59
+ visited.add(child.name);
60
+ walk(child, childDepth);
61
+ }
62
+ };
63
+ walk(root, 0);
64
+ return maxDepth;
65
+ }
15
66
  /**
16
67
  * Generate a Mermaid flowchart markup for a placetype and its descendants.
68
+ *
69
+ * The walk is a recursive `findChildren` traversal — every emitted edge is a real direct-parent →
70
+ * direct-child relationship. WOF placetypes form a DAG (e.g. `borough` has both `country` and
71
+ * `macroregion` as parents), so a child can legitimately appear on multiple edges; the `visited`
72
+ * set prevents the subtree below it from being re-emitted.
73
+ *
74
+ * Edges are colored by depth from the root via
75
+ * {@linkcode GenerateMermaidMarkupOptions.edgeInterpolator} (default: viridis), so any lineage path
76
+ * traces a smooth gradient down the chart. Node fills always use the hand-tuned role palette.
17
77
  */
18
- export function generateMermaidMarkup(placetype, roles) {
78
+ export function generateMermaidMarkup(placetype, options = {}) {
79
+ const { roles, edgeInterpolator = interpolateViridis } = options;
80
+ const palette = HAND_TUNED_PALETTE;
19
81
  const lines = [
20
82
  "---",
21
83
  "config:",
@@ -24,21 +86,31 @@ export function generateMermaidMarkup(placetype, roles) {
24
86
  "---",
25
87
  "graph TD",
26
88
  " linkStyle default stroke-width: 5",
27
- ` classDef common fill:${PlacetypeRoleColor.common},stroke:#004d99,color:white,font-weight:bold`,
28
- ` classDef common_optional fill:${PlacetypeRoleColor.common_optional},stroke:#009933,color:white,font-weight:bold`,
29
- ` classDef optional fill:${PlacetypeRoleColor.optional},stroke:#cca300,color:black,font-weight:bold`,
89
+ ...PlacetypeRoles.map((role) => ` classDef ${role} fill:${palette[role].fill},stroke:${palette[role].stroke},color:${palette[role].text},font-weight:bold`),
90
+ // The root is never the target of an emitted edge, so declare it standalone so it picks
91
+ // up the role classDef and renders alongside the others.
92
+ ` ${placetype.name}:::${placetype.role}`,
30
93
  ];
31
- const descendants = placetype.findDescendants(roles);
32
- for (const [idx, descendant] of descendants.entries()) {
33
- lines.push(` ${placetype.name} --> ${descendant.name}:::${descendant.role}`);
34
- lines.push(` linkStyle ${idx} stroke:${PlacetypeRoleColor[descendant.role]}`);
35
- }
36
- for (const descendant of descendants) {
37
- const children = descendant.findChildren(roles);
38
- for (const child of children) {
39
- lines.push(` ${descendant.name} --> ${child.name}:::${child.role}`);
94
+ // Pre-compute max depth once so every edge's `t` is consistent across the second pass.
95
+ const maxDepth = measureMaxDepth(placetype, roles);
96
+ const visited = new Set();
97
+ let edgeIdx = 0;
98
+ const walk = (node, depth) => {
99
+ for (const child of node.findChildren(roles)) {
100
+ const childDepth = depth + 1;
101
+ // Single-level case: nothing to interpolate across, sample mid-gradient.
102
+ const t = maxDepth > 1 ? (childDepth - 1) / (maxDepth - 1) : 0.5;
103
+ const edgeColor = toMermaidColor(edgeInterpolator(t));
104
+ lines.push(` ${node.name} --> ${child.name}:::${child.role}`);
105
+ lines.push(` linkStyle ${edgeIdx} stroke:${edgeColor}`);
106
+ edgeIdx++;
107
+ if (visited.has(child.name))
108
+ continue;
109
+ visited.add(child.name);
110
+ walk(child, childDepth);
40
111
  }
41
- }
112
+ };
113
+ walk(placetype, 0);
42
114
  return lines.join("\n");
43
115
  }
44
116
  //# sourceMappingURL=mermaid.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mermaid.js","sourceRoot":"","sources":["../../../../resources/whosonfirst/placetypes/mermaid.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE1C;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG;IACjC,MAAM,EAAE,SAAS;IACjB,eAAe,EAAE,SAAS;IAC1B,QAAQ,EAAE,SAAS;CAC8B,CAAA;AAElD;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,SAAoB,EAAE,KAA+B;IAC1F,MAAM,KAAK,GAAa;QACvB,KAAK;QACL,SAAS;QACT,cAAc;QACd,0BAA0B;QAC1B,KAAK;QACL,UAAU;QACV,qCAAqC;QACrC,0BAA0B,kBAAkB,CAAC,MAAM,8CAA8C;QACjG,mCAAmC,kBAAkB,CAAC,eAAe,8CAA8C;QACnH,4BAA4B,kBAAkB,CAAC,QAAQ,8CAA8C;KACrG,CAAA;IAED,MAAM,WAAW,GAAG,SAAS,CAAC,eAAe,CAAC,KAAK,CAAC,CAAA;IAEpD,KAAK,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC;QACvD,KAAK,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,IAAI,QAAQ,UAAU,CAAC,IAAI,MAAM,UAAU,CAAC,IAAI,EAAE,CAAC,CAAA;QAC7E,KAAK,CAAC,IAAI,CAAC,eAAe,GAAG,WAAW,kBAAkB,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAC/E,CAAC;IAED,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACtC,MAAM,QAAQ,GAAG,UAAU,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;QAE/C,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,KAAK,UAAU,CAAC,IAAI,QAAQ,KAAK,CAAC,IAAI,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;QACrE,CAAC;IACF,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACxB,CAAC"}
1
+ {"version":3,"file":"mermaid.js","sourceRoot":"","sources":["../../../../resources/whosonfirst/placetypes/mermaid.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ */
6
+ import type { PlacetypeRole } from "./definition.js";
7
+ import { Placetype } from "./Placetype.js";
8
+ /**
9
+ * A node in the nested placetype tree produced by {@linkcode generatePlacetypeTree}.
10
+ *
11
+ * WOF placetypes form a DAG (a placetype can have multiple parents — `borough`, for example, is a
12
+ * direct child of both `country` and `macroregion`), so a tree projection rooted at a single
13
+ * placetype can list the same descendant under multiple branches. That repetition is expected.
14
+ */
15
+ export interface PlacetypeTreeNode {
16
+ name: string;
17
+ id: number;
18
+ role: PlacetypeRole;
19
+ children: PlacetypeTreeNode[];
20
+ }
21
+ /**
22
+ * Build a nested tree of a placetype and its descendants, optionally filtered by role.
23
+ *
24
+ * The traversal mirrors {@linkcode Placetype.findChildren} — direct children only at each level,
25
+ * recursively. The DAG-to-tree projection may repeat descendants under multiple parents; if you
26
+ * need each placetype to appear exactly once, use {@linkcode Placetype.findDescendants} for a flat
27
+ * de-duplicated set instead.
28
+ */
29
+ export declare function generatePlacetypeTree(placetype: Placetype, roles?: Iterable<PlacetypeRole> | null): PlacetypeTreeNode;
30
+ //# sourceMappingURL=tree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../../../../resources/whosonfirst/placetypes/tree.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE1C;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,aAAa,CAAA;IACnB,QAAQ,EAAE,iBAAiB,EAAE,CAAA;CAC7B;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,IAAI,GAAG,iBAAiB,CAIrH"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ */
6
+ import { Placetype } from "./Placetype.js";
7
+ /**
8
+ * Build a nested tree of a placetype and its descendants, optionally filtered by role.
9
+ *
10
+ * The traversal mirrors {@linkcode Placetype.findChildren} — direct children only at each level,
11
+ * recursively. The DAG-to-tree projection may repeat descendants under multiple parents; if you
12
+ * need each placetype to appear exactly once, use {@linkcode Placetype.findDescendants} for a flat
13
+ * de-duplicated set instead.
14
+ */
15
+ export function generatePlacetypeTree(placetype, roles) {
16
+ const roleSet = roles ? new Set(roles) : null;
17
+ return buildNode(placetype, roleSet);
18
+ }
19
+ function buildNode(placetype, roles) {
20
+ const children = placetype.findChildren(roles).map((child) => buildNode(child, roles));
21
+ return {
22
+ name: placetype.name,
23
+ id: placetype.id,
24
+ role: placetype.role,
25
+ children,
26
+ };
27
+ }
28
+ //# sourceMappingURL=tree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree.js","sourceRoot":"","sources":["../../../../resources/whosonfirst/placetypes/tree.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAgB1C;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,SAAoB,EAAE,KAAsC;IACjG,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAE7C,OAAO,SAAS,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;AACrC,CAAC;AAED,SAAS,SAAS,CAAC,SAAoB,EAAE,KAAgC;IACxE,MAAM,QAAQ,GAAG,SAAS,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAA;IAEtF,OAAO;QACN,IAAI,EAAE,SAAS,CAAC,IAAI;QACpB,EAAE,EAAE,SAAS,CAAC,EAAE;QAChB,IAAI,EAAE,SAAS,CAAC,IAAI;QACpB,QAAQ;KACR,CAAA;AACF,CAAC"}
@@ -32,7 +32,7 @@ export declare class SolutionMatch implements SerializedSolutionMatch {
32
32
  /**
33
33
  * The classification of the match.
34
34
  */
35
- get classification(): "adjacent" | "alpha" | "alphanumeric" | "area" | "chain" | "country" | "dependency" | "directional" | "end_token_single_character" | "end_token" | "given_name" | "house_number" | "intersection" | "level_designator" | "level" | "locality" | "middle_initial" | "multistreet" | "numeric" | "ordinal" | "person" | "personal_suffix" | "personal_title" | "place" | "postcode" | "punctuation" | "region" | "road_type" | "start_token" | "stop_word" | "street_name" | "street_prefix" | "street_proper_name" | "street_suffix" | "street" | "surname" | "toponym" | "unit_designator" | "unit" | "unknown" | "venue";
35
+ get classification(): "country" | "region" | "locality" | "postcode" | "house_number" | "street" | "street_prefix" | "street_suffix" | "unit" | "venue" | "adjacent" | "alpha" | "alphanumeric" | "area" | "chain" | "dependency" | "directional" | "end_token_single_character" | "end_token" | "given_name" | "intersection" | "level_designator" | "level" | "middle_initial" | "multistreet" | "numeric" | "ordinal" | "person" | "personal_suffix" | "personal_title" | "place" | "punctuation" | "road_type" | "start_token" | "stop_word" | "street_name" | "street_proper_name" | "surname" | "toponym" | "unit_designator" | "unknown";
36
36
  /**
37
37
  * The confidence of the match, from 0 to 1.
38
38
  *
@@ -9,7 +9,7 @@ type MaskCode = "V" | "N" | "S" | "P" | "L" | "U" | "A";
9
9
  /**
10
10
  * Mapping of classification labels to mask codes.
11
11
  */
12
- export declare const ClassificationMaskCodeMap: Map<"adjacent" | "alpha" | "alphanumeric" | "area" | "chain" | "country" | "dependency" | "directional" | "end_token_single_character" | "end_token" | "given_name" | "house_number" | "intersection" | "level_designator" | "level" | "locality" | "middle_initial" | "multistreet" | "numeric" | "ordinal" | "person" | "personal_suffix" | "personal_title" | "place" | "postcode" | "punctuation" | "region" | "road_type" | "start_token" | "stop_word" | "street_name" | "street_prefix" | "street_proper_name" | "street_suffix" | "street" | "surname" | "toponym" | "unit_designator" | "unit" | "unknown" | "venue" | "fallback", MaskCode>;
12
+ export declare const ClassificationMaskCodeMap: Map<"country" | "region" | "locality" | "postcode" | "house_number" | "street" | "street_prefix" | "street_suffix" | "unit" | "venue" | "adjacent" | "alpha" | "alphanumeric" | "area" | "chain" | "dependency" | "directional" | "end_token_single_character" | "end_token" | "given_name" | "intersection" | "level_designator" | "level" | "middle_initial" | "multistreet" | "numeric" | "ordinal" | "person" | "personal_suffix" | "personal_title" | "place" | "punctuation" | "road_type" | "start_token" | "stop_word" | "street_name" | "street_proper_name" | "surname" | "toponym" | "unit_designator" | "unknown" | "fallback", MaskCode>;
13
13
  /**
14
14
  * Mask which shows the areas covered by different types of classification
15
15
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mailwoman/core",
3
- "version": "2.2.0",
3
+ "version": "4.0.0",
4
4
  "description": "Mailwoman core: tokenization, classification primitives, solver, formatter, resources, filters, solvers, utils.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {
@@ -51,6 +51,8 @@
51
51
  "dependencies": {
52
52
  "axios": "^1.16.1",
53
53
  "axios-cache-interceptor": "^1.12.0",
54
+ "d3-color": "^3.1.0",
55
+ "d3-scale-chromatic": "^3.1.0",
54
56
  "http-status-codes": "^2.3.0",
55
57
  "json-colorizer": "^3.0.1",
56
58
  "kysely": "^0.29.2",
@@ -58,6 +60,10 @@
58
60
  "pino-pretty": "^13.1.3",
59
61
  "table": "^6.9.0"
60
62
  },
63
+ "devDependencies": {
64
+ "@types/d3-color": "^3.1.3",
65
+ "@types/d3-scale-chromatic": "^3.1.0"
66
+ },
61
67
  "files": [
62
68
  "out/**/*.js",
63
69
  "out/**/*.js.map",