@instruments/taxonomy 0.2.0 → 0.3.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.
- package/README.md +16 -60
- package/dist/chunk-4ECRPD2I.js +7508 -0
- package/dist/{chunk-XLUE3IC2.js → chunk-FCMCKNQF.js} +11 -2
- package/dist/chunk-WIRA24HM.js +42 -0
- package/dist/crosswalks/designshop.d.ts +3 -11
- package/dist/crosswalks/designshop.js +125 -43
- package/dist/crosswalks/materialgraph.d.ts +41 -0
- package/dist/crosswalks/materialgraph.js +178 -0
- package/dist/crosswalks/miu.d.ts +2 -1
- package/dist/crosswalks/miu.js +9 -3
- package/dist/estate/index.d.ts +1 -1
- package/dist/estate/index.js +644 -551
- package/dist/index.d.ts +83 -6
- package/dist/index.js +103 -6104
- package/dist/mapping-pvHk5VjC.d.ts +31 -0
- package/dist/{match-BDI6Evro.d.ts → match-CWzTEuL-.d.ts} +37 -1
- package/dist/taste.d.ts +12 -1
- package/dist/taste.js +1 -1
- package/package.json +5 -1
- package/dist/chunk-C2ZPDTOU.js +0 -151
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { a as BundleMemberInput, M as MatchStrength } from './match-CWzTEuL-.js';
|
|
2
|
+
|
|
3
|
+
type CrosswalkMapping = {
|
|
4
|
+
status: "resolved";
|
|
5
|
+
assertions: readonly BundleMemberInput[];
|
|
6
|
+
match: MatchStrength;
|
|
7
|
+
note?: string;
|
|
8
|
+
} | {
|
|
9
|
+
status: "ambiguous";
|
|
10
|
+
alternatives: readonly (readonly BundleMemberInput[])[];
|
|
11
|
+
match: MatchStrength;
|
|
12
|
+
note?: string;
|
|
13
|
+
} | {
|
|
14
|
+
status: "declined";
|
|
15
|
+
reason: string;
|
|
16
|
+
};
|
|
17
|
+
/** A compound row: the source value is fully carried by the assertions together. */
|
|
18
|
+
declare const resolved: (...assertions: readonly string[]) => CrosswalkMapping;
|
|
19
|
+
/** One canonical term, interchangeable with the source value in retrieval. */
|
|
20
|
+
declare const constitutive: (assertion: string) => CrosswalkMapping;
|
|
21
|
+
/**
|
|
22
|
+
* A row that is not an identity. The strength says how it falls short and the note says why, both
|
|
23
|
+
* required: an approximation nobody had to justify is how a close match ships as an exact one.
|
|
24
|
+
*/
|
|
25
|
+
declare const approximates: (match: Exclude<MatchStrength, "exact">, note: string, ...assertions: readonly string[]) => CrosswalkMapping;
|
|
26
|
+
/** The source is known to mean one of these and never recorded which. `match` grades each reading. */
|
|
27
|
+
declare const ambiguous: (match: MatchStrength, ...assertions: readonly string[]) => CrosswalkMapping;
|
|
28
|
+
/** A curated refusal. Distinct from an absent row, which means nobody has looked. */
|
|
29
|
+
declare const declined: (reason: string) => CrosswalkMapping;
|
|
30
|
+
|
|
31
|
+
export { type CrosswalkMapping as C, ambiguous as a, approximates as b, constitutive as c, declined as d, resolved as r };
|
|
@@ -348,6 +348,42 @@ interface AlternativesMatch {
|
|
|
348
348
|
}
|
|
349
349
|
/** The strongest eligible reading wins; bundle identity makes ties deterministic. */
|
|
350
350
|
declare const matchAlternatives: (alternatives: CanonicalAlternatives, candidateAssertions: Iterable<string>) => AlternativesMatch;
|
|
351
|
+
/** How well a candidate answered the query. `exact` matched every member, accents included. */
|
|
352
|
+
type MatchTier = "exact" | "eligible" | "relaxed";
|
|
353
|
+
/** A subject to rank: an opaque id and the assertions annotating it. */
|
|
354
|
+
interface CandidateAnnotations {
|
|
355
|
+
id: string;
|
|
356
|
+
assertions: readonly string[];
|
|
357
|
+
}
|
|
358
|
+
interface RankedCandidate {
|
|
359
|
+
id: string;
|
|
360
|
+
tier: MatchTier;
|
|
361
|
+
match: BundleMatch;
|
|
362
|
+
}
|
|
363
|
+
interface BundleSearch {
|
|
364
|
+
/** The strongest tier present. Absent when no candidate carried even one member. */
|
|
365
|
+
tier?: MatchTier;
|
|
366
|
+
results: readonly RankedCandidate[];
|
|
367
|
+
/** True when nothing was eligible and the relaxed tier was served in its place. */
|
|
368
|
+
relaxed: boolean;
|
|
369
|
+
/**
|
|
370
|
+
* Constitutive members NO candidate in this corpus carries. Populated only when nothing was
|
|
371
|
+
* eligible, because that is when it is the answer: these are the conjuncts the corpus cannot
|
|
372
|
+
* satisfy, and naming them is what turns an empty result into a usable one.
|
|
373
|
+
*/
|
|
374
|
+
blocking: readonly string[];
|
|
375
|
+
}
|
|
376
|
+
interface SearchOptions {
|
|
377
|
+
/** Refuse the relaxed tier: return nothing rather than a labelled partial answer. */
|
|
378
|
+
strict?: boolean;
|
|
379
|
+
/** Truncate the ranked list. Applied after ordering, so it never changes which result is first. */
|
|
380
|
+
limit?: number;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Rank a corpus against a bundle under the published rule. Deterministic: the same corpus in any
|
|
384
|
+
* input order returns the same list.
|
|
385
|
+
*/
|
|
386
|
+
declare const searchBundle: (bundle: CanonicalBundle, candidates: Iterable<CandidateAnnotations>, options?: SearchOptions) => BundleSearch;
|
|
351
387
|
interface MatchTestCandidate {
|
|
352
388
|
assertions: readonly string[];
|
|
353
389
|
id: string;
|
|
@@ -364,4 +400,4 @@ interface MatchTestVector {
|
|
|
364
400
|
*/
|
|
365
401
|
declare const MATCH_TEST_VECTORS: readonly MatchTestVector[];
|
|
366
402
|
|
|
367
|
-
export { type AlternativeReason as A, type
|
|
403
|
+
export { type AlternativeReason as A, type BundleRole as B, type CanonicalAlternatives as C, DEFAULT_BUNDLE_ROLE as D, type ExternalMapping as E, matchBundle as F, searchBundle as G, type MatchStrength as M, type PeriodSpan as P, type RelationPredicate as R, type SearchOptions as S, type Term as T, type UsageBand as U, type BundleMemberInput as a, type AlternativesMatch as b, type BundleMatch as c, type BundleMember as d, type BundleSearch as e, type CandidateAnnotations as f, type CanonicalBundle as g, type ExternalScheme as h, MATCH_TEST_VECTORS as i, MATCH_WEIGHTS as j, type MatchTestCandidate as k, type MatchTestVector as l, type MatchTier as m, type RankedCandidate as n, type RelationRole as o, type SearchedWithout as p, type SourceBasis as q, type StyleKind as r, type TermProvenance as s, type TermRelation as t, type TermStatus as u, type TermUsage as v, type UsageWithheld as w, defineAlternatives as x, defineBundle as y, matchAlternatives as z };
|
package/dist/taste.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as CanonicalAlternatives,
|
|
1
|
+
import { C as CanonicalAlternatives, g as CanonicalBundle, M as MatchStrength } from './match-CWzTEuL-.js';
|
|
2
2
|
|
|
3
3
|
declare const TASTE_ASSERTION_CONTRACT_VERSION: "1.0.0";
|
|
4
4
|
declare const TAXONOMY_SNAPSHOT_VERSION: "2026-08-25";
|
|
@@ -124,10 +124,21 @@ interface CanonicalisationBase extends CanonicalisationInput {
|
|
|
124
124
|
interface ResolvedCanonicalisation extends CanonicalisationBase {
|
|
125
125
|
status: "resolved";
|
|
126
126
|
canonical: CanonicalBundle;
|
|
127
|
+
/**
|
|
128
|
+
* How strongly the canonical bundle stands for the source value, in SKOS's own vocabulary. A
|
|
129
|
+
* consumer may treat `exact` as an identity and must treat everything else as an approximation
|
|
130
|
+
* it has been told about. See `crosswalks/strength.ts` for the direction convention.
|
|
131
|
+
*/
|
|
132
|
+
match: MatchStrength;
|
|
133
|
+
/** Why the row is not exact. Present whenever `match` is not `exact`. */
|
|
134
|
+
note?: string;
|
|
127
135
|
}
|
|
128
136
|
interface AmbiguousCanonicalisation extends CanonicalisationBase {
|
|
129
137
|
status: "ambiguous";
|
|
130
138
|
alternatives: CanonicalAlternatives;
|
|
139
|
+
/** How strongly each alternative would stand for the source value, were it the right reading. */
|
|
140
|
+
match: MatchStrength;
|
|
141
|
+
note?: string;
|
|
131
142
|
}
|
|
132
143
|
interface UnresolvedCanonicalisation extends CanonicalisationBase {
|
|
133
144
|
status: "unresolved";
|
package/dist/taste.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@instruments/taxonomy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Canonical materials taxonomy for the Material Instruments ecosystem — governed dictionaries (material families, sectors, applications) and consumer crosswalks.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"repository": {
|
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
"types": "./dist/crosswalks/miu.d.ts",
|
|
23
23
|
"import": "./dist/crosswalks/miu.js"
|
|
24
24
|
},
|
|
25
|
+
"./crosswalks/materialgraph": {
|
|
26
|
+
"types": "./dist/crosswalks/materialgraph.d.ts",
|
|
27
|
+
"import": "./dist/crosswalks/materialgraph.js"
|
|
28
|
+
},
|
|
25
29
|
"./crosswalks/designshop": {
|
|
26
30
|
"types": "./dist/crosswalks/designshop.d.ts",
|
|
27
31
|
"import": "./dist/crosswalks/designshop.js"
|
package/dist/chunk-C2ZPDTOU.js
DELETED
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
// src/match.ts
|
|
2
|
-
var ROLE_WEIGHT = {
|
|
3
|
-
accent: 1,
|
|
4
|
-
constitutive: 2
|
|
5
|
-
};
|
|
6
|
-
var MATCH_WEIGHTS = ROLE_WEIGHT;
|
|
7
|
-
var DEFAULT_BUNDLE_ROLE = "accent";
|
|
8
|
-
var checkedAssertion = (assertion) => {
|
|
9
|
-
const normalized = assertion.trim();
|
|
10
|
-
if (normalized.length === 0) {
|
|
11
|
-
throw new Error("a canonical assertion cannot be empty");
|
|
12
|
-
}
|
|
13
|
-
return normalized;
|
|
14
|
-
};
|
|
15
|
-
var defineBundle = (inputs) => {
|
|
16
|
-
if (inputs.length === 0) {
|
|
17
|
-
throw new Error("a canonical bundle must contain at least one assertion");
|
|
18
|
-
}
|
|
19
|
-
const byAssertion = /* @__PURE__ */ new Map();
|
|
20
|
-
for (const input of inputs) {
|
|
21
|
-
const assertion = checkedAssertion(input.assertion);
|
|
22
|
-
const role = input.role ?? DEFAULT_BUNDLE_ROLE;
|
|
23
|
-
const previous = byAssertion.get(assertion);
|
|
24
|
-
byAssertion.set(assertion, previous === "constitutive" ? previous : role);
|
|
25
|
-
}
|
|
26
|
-
const members = [...byAssertion].map(([assertion, role]) => ({ assertion, role })).toSorted((a, b) => a.assertion.localeCompare(b.assertion) || a.role.localeCompare(b.role));
|
|
27
|
-
const serialization = members.map(({ assertion, role }) => `${role}:${assertion}`).join("|");
|
|
28
|
-
return {
|
|
29
|
-
id: `bundle:${encodeURIComponent(serialization)}`,
|
|
30
|
-
kind: "all-of",
|
|
31
|
-
members,
|
|
32
|
-
serialization
|
|
33
|
-
};
|
|
34
|
-
};
|
|
35
|
-
var defineAlternatives = (inputs, reason) => {
|
|
36
|
-
const bySerialization = /* @__PURE__ */ new Map();
|
|
37
|
-
for (const input of inputs) {
|
|
38
|
-
const bundle = "kind" in input ? input : defineBundle(input);
|
|
39
|
-
bySerialization.set(bundle.serialization, bundle);
|
|
40
|
-
}
|
|
41
|
-
const alternatives = [...bySerialization.values()].toSorted(
|
|
42
|
-
(a, b) => a.serialization.localeCompare(b.serialization)
|
|
43
|
-
);
|
|
44
|
-
if (alternatives.length < 2) {
|
|
45
|
-
throw new Error("canonical alternatives must contain at least two distinct bundles");
|
|
46
|
-
}
|
|
47
|
-
const serialization = alternatives.map(({ id }) => id).join("||");
|
|
48
|
-
return {
|
|
49
|
-
alternatives,
|
|
50
|
-
id: `alternatives:${encodeURIComponent(serialization)}`,
|
|
51
|
-
kind: "any-of",
|
|
52
|
-
reason,
|
|
53
|
-
serialization
|
|
54
|
-
};
|
|
55
|
-
};
|
|
56
|
-
var matchBundle = (bundle, candidateAssertions) => {
|
|
57
|
-
const candidate = new Set(candidateAssertions);
|
|
58
|
-
const matched = bundle.members.filter(({ assertion }) => candidate.has(assertion));
|
|
59
|
-
const missing = bundle.members.filter(({ assertion }) => !candidate.has(assertion));
|
|
60
|
-
const missingConstitutive = missing.filter(({ role }) => role === "constitutive").map(({ assertion }) => assertion);
|
|
61
|
-
const missingAccents = missing.filter(({ role }) => role === "accent").map(({ assertion }) => assertion);
|
|
62
|
-
const eligible = missingConstitutive.length === 0;
|
|
63
|
-
const availableWeight = bundle.members.reduce((sum, { role }) => sum + ROLE_WEIGHT[role], 0);
|
|
64
|
-
const matchedWeight = matched.reduce((sum, { role }) => sum + ROLE_WEIGHT[role], 0);
|
|
65
|
-
return {
|
|
66
|
-
eligible,
|
|
67
|
-
matched: matched.map(({ assertion }) => assertion),
|
|
68
|
-
missingAccents,
|
|
69
|
-
missingConstitutive,
|
|
70
|
-
score: eligible ? matchedWeight / availableWeight : 0
|
|
71
|
-
};
|
|
72
|
-
};
|
|
73
|
-
var matchAlternatives = (alternatives, candidateAssertions) => {
|
|
74
|
-
const assertions = [...candidateAssertions];
|
|
75
|
-
const ranked = alternatives.alternatives.map((alternative) => ({ alternative, match: matchBundle(alternative, assertions) })).toSorted(
|
|
76
|
-
(a, b) => Number(b.match.eligible) - Number(a.match.eligible) || b.match.score - a.match.score || a.alternative.id.localeCompare(b.alternative.id)
|
|
77
|
-
);
|
|
78
|
-
const [strongest] = ranked;
|
|
79
|
-
if (strongest === void 0) {
|
|
80
|
-
throw new Error("canonical alternatives contain no bundles");
|
|
81
|
-
}
|
|
82
|
-
return strongest;
|
|
83
|
-
};
|
|
84
|
-
var COTTAGE = "evokes(typology.cottage)";
|
|
85
|
-
var COTSWOLDS = "evokes(place.region.cotswolds)";
|
|
86
|
-
var SHELTERING = "mood.sheltering";
|
|
87
|
-
var GREEN = "palette.hue.green";
|
|
88
|
-
var RESTAURANT = "space.restaurant";
|
|
89
|
-
var INDUSTRIAL = "style.industrial";
|
|
90
|
-
var MOODY = "mood.moody";
|
|
91
|
-
var COOL = "palette.temperature.cool";
|
|
92
|
-
var MATCH_TEST_VECTORS = [
|
|
93
|
-
{
|
|
94
|
-
candidates: [
|
|
95
|
-
{
|
|
96
|
-
assertions: [COTTAGE, COTSWOLDS, SHELTERING, GREEN],
|
|
97
|
-
id: "residential-exact"
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
assertions: [COTTAGE, SHELTERING, GREEN],
|
|
101
|
-
id: "residential-near"
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
assertions: [COTSWOLDS, SHELTERING, GREEN],
|
|
105
|
-
id: "residential-wrong-building"
|
|
106
|
-
}
|
|
107
|
-
],
|
|
108
|
-
expectedEligibleOrder: ["residential-exact", "residential-near"],
|
|
109
|
-
id: "cotswolds-green-cosy-cottage",
|
|
110
|
-
query: defineBundle([
|
|
111
|
-
{ assertion: COTTAGE, role: "constitutive" },
|
|
112
|
-
{ assertion: COTSWOLDS },
|
|
113
|
-
{ assertion: SHELTERING },
|
|
114
|
-
{ assertion: GREEN }
|
|
115
|
-
])
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
candidates: [
|
|
119
|
-
{
|
|
120
|
-
assertions: [RESTAURANT, INDUSTRIAL, MOODY, COOL],
|
|
121
|
-
id: "commercial-exact"
|
|
122
|
-
},
|
|
123
|
-
{
|
|
124
|
-
assertions: [RESTAURANT, INDUSTRIAL, MOODY],
|
|
125
|
-
id: "commercial-near"
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
assertions: ["typology.restaurant", INDUSTRIAL, MOODY],
|
|
129
|
-
id: "commercial-wrong-scale"
|
|
130
|
-
}
|
|
131
|
-
],
|
|
132
|
-
expectedEligibleOrder: ["commercial-exact", "commercial-near"],
|
|
133
|
-
id: "moody-industrial-restaurant",
|
|
134
|
-
query: defineBundle([
|
|
135
|
-
{ assertion: RESTAURANT, role: "constitutive" },
|
|
136
|
-
{ assertion: INDUSTRIAL, role: "constitutive" },
|
|
137
|
-
{ assertion: MOODY },
|
|
138
|
-
{ assertion: COOL }
|
|
139
|
-
])
|
|
140
|
-
}
|
|
141
|
-
];
|
|
142
|
-
|
|
143
|
-
export {
|
|
144
|
-
MATCH_WEIGHTS,
|
|
145
|
-
DEFAULT_BUNDLE_ROLE,
|
|
146
|
-
defineBundle,
|
|
147
|
-
defineAlternatives,
|
|
148
|
-
matchBundle,
|
|
149
|
-
matchAlternatives,
|
|
150
|
-
MATCH_TEST_VECTORS
|
|
151
|
-
};
|