@mailwoman/kind-classifier 9.1.0 → 9.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 +2 -2
- package/{classify.ts → lib/classify.ts} +5 -5
- package/{index.ts → lib/index.ts} +10 -10
- package/{intent-markers.ts → lib/intent-markers.ts} +9 -7
- package/{intent-rules.ts → lib/intent-rules.ts} +7 -14
- package/{poi.ts → lib/poi.ts} +126 -15
- package/{rules.ts → lib/rules.ts} +28 -31
- package/lib/types.ts +17 -0
- package/out/classify.d.ts +2 -2
- package/out/classify.d.ts.map +1 -1
- package/out/classify.js +4 -4
- package/out/classify.js.map +1 -1
- package/out/index.d.ts +10 -10
- package/out/index.d.ts.map +1 -1
- package/out/index.js +6 -6
- package/out/index.js.map +1 -1
- package/out/intent-markers.d.ts +3 -3
- package/out/intent-markers.d.ts.map +1 -1
- package/out/intent-markers.js +8 -6
- package/out/intent-markers.js.map +1 -1
- package/out/intent-rules.d.ts +1 -1
- package/out/intent-rules.d.ts.map +1 -1
- package/out/intent-rules.js +6 -12
- package/out/intent-rules.js.map +1 -1
- package/out/poi.d.ts +65 -7
- package/out/poi.d.ts.map +1 -1
- package/out/poi.js +61 -10
- package/out/poi.js.map +1 -1
- package/out/rules.d.ts +12 -4
- package/out/rules.d.ts.map +1 -1
- package/out/rules.js +24 -30
- package/out/rules.js.map +1 -1
- package/out/types.d.ts +3 -25
- package/out/types.d.ts.map +1 -1
- package/out/types.js.map +1 -1
- package/package.json +74 -7
- package/types.ts +0 -34
package/README.md
CHANGED
|
@@ -46,7 +46,7 @@ scoreVague(shape: QueryShapeLike): number
|
|
|
46
46
|
## Pipeline position
|
|
47
47
|
|
|
48
48
|
```
|
|
49
|
-
locale-
|
|
49
|
+
locale-hint → kind-classifier → phrase-grouper → classifier → ...
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
## Design
|
|
@@ -59,7 +59,7 @@ locale-gate → kind-classifier → phrase-grouper → classifier → ...
|
|
|
59
59
|
## Related
|
|
60
60
|
|
|
61
61
|
- [`@mailwoman/query-shape`](../query-shape) — feeds structural data into this stage
|
|
62
|
-
- [`@mailwoman/locale-
|
|
62
|
+
- [`@mailwoman/locale-hint`](../locale-hint) — feeds locale context
|
|
63
63
|
- [`@mailwoman/phrase-grouper`](../phrase-grouper) — Stage 2.7, next in the pipeline
|
|
64
64
|
- [Staged Pipeline Contract](https://github.com/sister-software/mailwoman/blob/main/docs/engineering/reference/STAGES.mdx)
|
|
65
65
|
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
* inform the markers without moving the routing decision.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import { deriveIntentMarkers } from "
|
|
20
|
-
import { scoreBareToponym, scoreNearMe, scoreRoutePair } from "
|
|
21
|
-
import { createScorePOICategory, createScorePOIQuery, type POIPhraseLookup } from "
|
|
19
|
+
import { deriveIntentMarkers } from "#intent-markers"
|
|
20
|
+
import { scoreBareToponym, scoreNearMe, scoreRoutePair } from "#intent-rules"
|
|
21
|
+
import { createScorePOICategory, createScorePOIQuery, type POIPhraseLookup } from "#poi"
|
|
22
22
|
import {
|
|
23
23
|
scoreIntersection,
|
|
24
24
|
scoreLandmark,
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
scoreStructuredAddress,
|
|
29
29
|
scoreVague,
|
|
30
30
|
scoreVenueLandmark,
|
|
31
|
-
} from "
|
|
31
|
+
} from "#rules"
|
|
32
32
|
import type {
|
|
33
33
|
LocaleHint,
|
|
34
34
|
NormalizedInputLite,
|
|
@@ -36,7 +36,7 @@ import type {
|
|
|
36
36
|
QueryKind,
|
|
37
37
|
QueryKindResult,
|
|
38
38
|
QueryShapeLike,
|
|
39
|
-
} from "
|
|
39
|
+
} from "#types"
|
|
40
40
|
|
|
41
41
|
interface KindScorer {
|
|
42
42
|
kind: QueryKind
|
|
@@ -13,13 +13,13 @@
|
|
|
13
13
|
* See `docs/engineering/reference/STAGES.md` § Stage 2.5 for the contract.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
export { classifyKind, classifyKindSync, createKindClassifier } from "
|
|
17
|
-
export type { KindClassifierOpts } from "
|
|
18
|
-
export { deriveIntentMarkers } from "
|
|
19
|
-
export type { IntentMarkerContext } from "
|
|
20
|
-
export { nearMeSubject, scoreBareToponym, scoreNearMe, scoreRoutePair } from "
|
|
21
|
-
export { matchPOICategory, matchPOISubject } from "
|
|
22
|
-
export type { POIPhraseMatch, POIPhraseLookup, POISubjectMatch } from "
|
|
16
|
+
export { classifyKind, classifyKindSync, createKindClassifier } from "#classify"
|
|
17
|
+
export type { KindClassifierOpts } from "#classify"
|
|
18
|
+
export { deriveIntentMarkers } from "#intent-markers"
|
|
19
|
+
export type { IntentMarkerContext } from "#intent-markers"
|
|
20
|
+
export { nearMeSubject, scoreBareToponym, scoreNearMe, scoreRoutePair } from "#intent-rules"
|
|
21
|
+
export { matchPOICategory, matchPOISubject } from "#poi"
|
|
22
|
+
export type { POIPhraseMatch, POIPhraseLookup, POIQuerySpan, POISpatialRelation, POISubjectMatch } from "#poi"
|
|
23
23
|
|
|
24
24
|
export {
|
|
25
25
|
scoreIntersection,
|
|
@@ -30,9 +30,9 @@ export {
|
|
|
30
30
|
scoreStructuredAddress,
|
|
31
31
|
scoreVague,
|
|
32
32
|
scoreVenueLandmark,
|
|
33
|
-
} from "
|
|
33
|
+
} from "#rules"
|
|
34
34
|
|
|
35
|
-
export { QueryIntentCode } from "
|
|
35
|
+
export { QueryIntentCode } from "#types"
|
|
36
36
|
|
|
37
37
|
export type {
|
|
38
38
|
LocaleHint,
|
|
@@ -41,4 +41,4 @@ export type {
|
|
|
41
41
|
QueryKind,
|
|
42
42
|
QueryKindResult,
|
|
43
43
|
QueryShapeLike,
|
|
44
|
-
} from "
|
|
44
|
+
} from "#types"
|
|
@@ -9,15 +9,15 @@
|
|
|
9
9
|
* Three of the four intent kinds can raise their marker here, from the string alone. The fourth —
|
|
10
10
|
* `bare_toponym`'s `declared_ambiguity` — cannot: its trigger is the dominance margin of the
|
|
11
11
|
* RESOLVED candidate list, which does not exist yet at Stage 2.5. That one is raised by
|
|
12
|
-
* `mailwoman/query-intent.ts` after the resolve, against the measured 0.5-log10
|
|
12
|
+
* `mailwoman/query-intent.ts` after the resolve, against the measured 0.5-log10 threshold. The split is
|
|
13
13
|
* deliberate and it is why this module never emits `declared_ambiguity`: a marker that asserted
|
|
14
14
|
* ambiguity from the string alone would be declaring that every bare city name is ambiguous, which
|
|
15
15
|
* is false 89.1% of the time (the measured table behind `DECISIVE_MARGIN_LOG10`).
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import { nearMeSubject } from "
|
|
19
|
-
import { matchPOICategory, type POIPhraseLookup } from "
|
|
20
|
-
import type { NormalizedInputLite, QueryIntentMarker, QueryKind } from "
|
|
18
|
+
import { nearMeSubject } from "#intent-rules"
|
|
19
|
+
import { matchPOICategory, type POIPhraseLookup } from "#poi"
|
|
20
|
+
import type { NormalizedInputLite, QueryIntentMarker, QueryKind } from "#types"
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Context the marker builder needs beyond the scored kinds.
|
|
@@ -50,6 +50,8 @@ export function deriveIntentMarkers(
|
|
|
50
50
|
const markers: QueryIntentMarker[] = []
|
|
51
51
|
|
|
52
52
|
if (fired.has("route_pair")) {
|
|
53
|
+
// Whitespace-only split, not `wordsOf`: `route_pair` inputs are comma-free by construction (a comma
|
|
54
|
+
// disqualifies the kind), and the tokens are re-joined verbatim into the message.
|
|
53
55
|
const tokens = ctx.input.normalized.trim().split(/\s+/)
|
|
54
56
|
|
|
55
57
|
markers.push({
|
|
@@ -79,9 +81,9 @@ export function deriveIntentMarkers(
|
|
|
79
81
|
evidence: {
|
|
80
82
|
subject,
|
|
81
83
|
/**
|
|
82
|
-
*
|
|
83
|
-
* `lat`/`lon` location-bias params — `photon/` is the eventual consumer of this marker, and this string
|
|
84
|
-
* note that says where it plugs in.
|
|
84
|
+
* THE PLUG POINT, named but not wired (ROAD_TO_V9 §4.4 scopes v9 to classification). Photon's `/api` already
|
|
85
|
+
* accepts `lat`/`lon` location-bias params — `photon/` is the eventual consumer of this marker, and this string
|
|
86
|
+
* is the note that says where it plugs in.
|
|
85
87
|
*/
|
|
86
88
|
focusParameter: "photon:lat/lon",
|
|
87
89
|
},
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
* ending "near me" is not a locality and answering it as one is the bug.
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import { MAX_LOCALITY_ONLY_LENGTH,
|
|
27
|
-
import type { NormalizedInputLite, QueryShapeLike } from "
|
|
26
|
+
import { isDisqualifyingStreetSuffix, MAX_LOCALITY_ONLY_LENGTH, wordsOf } from "#rules"
|
|
27
|
+
import type { NormalizedInputLite, QueryShapeLike } from "#types"
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* `locality_only` scores 0.85. Both refinement kinds sit under it by a whole confidence step so no float-comparison
|
|
@@ -186,13 +186,6 @@ const DEICTIC_LOCATOR_TAIL =
|
|
|
186
186
|
const DEICTIC_ADVERB_TAIL =
|
|
187
187
|
/\b(?:nearby|near\s?by|close\s+by|around\s+here|in\s+my\s+(?:area|neighborhood|neighbourhood))\s*$/
|
|
188
188
|
|
|
189
|
-
/**
|
|
190
|
-
* Split on whitespace + commas, the way the other rules in this package do.
|
|
191
|
-
*/
|
|
192
|
-
function wordsOf(text: string): string[] {
|
|
193
|
-
return text.split(/[\s,]+/).filter(Boolean)
|
|
194
|
-
}
|
|
195
|
-
|
|
196
189
|
/**
|
|
197
190
|
* True when the input carries a deictic locator tail in EITHER form.
|
|
198
191
|
*/
|
|
@@ -201,12 +194,12 @@ function hasDeicticTail(lowercased: string): boolean {
|
|
|
201
194
|
}
|
|
202
195
|
|
|
203
196
|
/**
|
|
204
|
-
* The
|
|
197
|
+
* The conditions `bare_toponym` and `route_pair` share: no address grammar of any kind, one segment, alpha throughout.
|
|
205
198
|
*
|
|
206
199
|
* Returns the word list when the input clears them, `null` when it does not. Deliberately a SUPERSET of
|
|
207
|
-
* `scoreLocalityOnly`'s
|
|
208
|
-
* and can never fire where `locality_only` did not — the property `intent-rules.test.ts` asserts and
|
|
209
|
-
* ranking discipline above is enough to keep the top kind pinned.
|
|
200
|
+
* `scoreLocalityOnly`'s conditions (which admit two segments), so `bare_toponym` is a strict refinement of
|
|
201
|
+
* `locality_only` and can never fire where `locality_only` did not — the property `intent-rules.test.ts` asserts and
|
|
202
|
+
* the reason the ranking discipline above is enough to keep the top kind pinned.
|
|
210
203
|
*/
|
|
211
204
|
function bareNameWords(input: NormalizedInputLite, shape: QueryShapeLike): string[] | null {
|
|
212
205
|
const text = input.normalized.trim()
|
|
@@ -232,7 +225,7 @@ function bareNameWords(input: NormalizedInputLite, shape: QueryShapeLike): strin
|
|
|
232
225
|
if (!words.length || words.length > MAX_BARE_TOPONYM_WORDS) return null
|
|
233
226
|
|
|
234
227
|
for (const word of words) {
|
|
235
|
-
if (
|
|
228
|
+
if (isDisqualifyingStreetSuffix(word)) return null
|
|
236
229
|
}
|
|
237
230
|
|
|
238
231
|
return words
|
package/{poi.ts → lib/poi.ts}
RENAMED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* `poiQueryKind` flag (default-ON since 2026-07-20). Spec §3.1.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import type { NormalizedInputLite, QueryShapeLike } from "
|
|
12
|
+
import type { NormalizedInputLite, QueryShapeLike } from "#types"
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Comma-segment ceiling for a POI-led query. Past it the input is a venue plus a full address (`X, 350 5th Ave, New
|
|
@@ -22,22 +22,49 @@ const MAX_POI_SEGMENTS = 3
|
|
|
22
22
|
*/
|
|
23
23
|
export interface POIPhraseMatch {
|
|
24
24
|
/**
|
|
25
|
-
* The matched subject's identifier string. For `kind: "category"`, a `@mailwoman/poi-taxonomy` category id
|
|
26
|
-
* `kind: "brand"`, the
|
|
27
|
-
*
|
|
25
|
+
* The matched subject's identifier string. For `kind: "category"`, a `@mailwoman/poi-taxonomy` category id; for
|
|
26
|
+
* `kind: "brand"` or `kind: "name"`, the canonical display name. `matchPOISubject` treats it opaquely; the caller
|
|
27
|
+
* (`mailwoman`'s `poi-intent.ts`) interprets it per `kind`.
|
|
28
28
|
*/
|
|
29
29
|
categoryID: string
|
|
30
30
|
matchedPhrase: string
|
|
31
31
|
confidence: number
|
|
32
|
+
mechanism?: "exact" | "locale_normalized" | "typo"
|
|
33
|
+
inputPhrase?: string
|
|
32
34
|
/**
|
|
33
35
|
* Absent = "category" (the pre-brand shape) — optional so pre-7.3 POIPhraseLookup implementors stay
|
|
34
36
|
* source-compatible.
|
|
35
37
|
*/
|
|
36
|
-
kind?: "category" | "brand"
|
|
38
|
+
kind?: "category" | "brand" | "name"
|
|
37
39
|
/**
|
|
38
40
|
* Wikidata QID, when known. `kind: "brand"` only — absent when a brand resolved by name alone (no QID match).
|
|
39
41
|
*/
|
|
40
42
|
wikidata?: string
|
|
43
|
+
/**
|
|
44
|
+
* Whether this hit is one member of a set the caller must search TOGETHER, rather than one candidate in a preference
|
|
45
|
+
* list.
|
|
46
|
+
*
|
|
47
|
+
* A lookup returning several hits means two different things, and the difference decides whether narrowing to the
|
|
48
|
+
* first is an answer or an invented ordering. A phrase index returns the categories one typed phrase could name, the
|
|
49
|
+
* curated reading first (`credit union` → the `bank` rollup its synonym redirects to, then the standalone
|
|
50
|
+
* `credit_union` category), and the first entry IS the subject. An affordance rung returns every entity kind that
|
|
51
|
+
* affords ONE activity, in a stable enumeration that is not a preference, and taking the first picks a winner nobody
|
|
52
|
+
* authored.
|
|
53
|
+
*
|
|
54
|
+
* Set on every member of such a set. {@link matchPOISubject} then carries them all, the POI branch searches their
|
|
55
|
+
* union, and the candidate ordering the resolver already owns decides the answer. Absent — the committed lexicon's
|
|
56
|
+
* shape — keeps the first-hit reading unchanged.
|
|
57
|
+
*/
|
|
58
|
+
searchAsSet?: boolean
|
|
59
|
+
/**
|
|
60
|
+
* ISO 3166-1 alpha-2 countries the authority behind this hit scopes its claim to. Absent = the claim holds
|
|
61
|
+
* everywhere.
|
|
62
|
+
*
|
|
63
|
+
* A scope is a statement about ESTABLISHMENTS, so it is judged against the country of the place being searched, not
|
|
64
|
+
* the caller's locale: the locale is the lens the phrase is read through, and it says nothing about where the claim
|
|
65
|
+
* holds. `matchPOISubject` carries the value untouched; the POI intent stage binds it once the anchor has resolved.
|
|
66
|
+
*/
|
|
67
|
+
countryScope?: readonly string[]
|
|
41
68
|
}
|
|
42
69
|
|
|
43
70
|
/**
|
|
@@ -45,24 +72,54 @@ export interface POIPhraseMatch {
|
|
|
45
72
|
*/
|
|
46
73
|
export type POIPhraseLookup = (phrase: string, locale?: string) => ReadonlyArray<POIPhraseMatch>
|
|
47
74
|
|
|
75
|
+
export type POISpatialRelation = "comma" | "near" | "in" | "at" | "around" | "to"
|
|
76
|
+
|
|
77
|
+
export interface POIQuerySpan {
|
|
78
|
+
text: string
|
|
79
|
+
/**
|
|
80
|
+
* Half-open character offsets into the normalized input.
|
|
81
|
+
*/
|
|
82
|
+
start: number
|
|
83
|
+
end: number
|
|
84
|
+
}
|
|
85
|
+
|
|
48
86
|
/**
|
|
49
87
|
* Which lexicon this hit came from. Existing category lookups set `"category"` (backward-compatible default).
|
|
50
88
|
*/
|
|
51
89
|
export interface POISubjectMatch {
|
|
90
|
+
/**
|
|
91
|
+
* The hit the subject SCORES under — its kind and its confidence. Always `matches[0]`; the two are built together in
|
|
92
|
+
* one place so they cannot disagree.
|
|
93
|
+
*/
|
|
52
94
|
match: POIPhraseMatch
|
|
95
|
+
/**
|
|
96
|
+
* Every category the subject reaches, `match` first.
|
|
97
|
+
*
|
|
98
|
+
* One entry unless the lookup returned a {@link POIPhraseMatch.searchAsSet} set, in which case it holds the whole set
|
|
99
|
+
* and the POI branch searches their union. The order is the order the lookup returned and states no preference:
|
|
100
|
+
* nothing downstream may read position as rank.
|
|
101
|
+
*/
|
|
102
|
+
matches: POIPhraseMatch[]
|
|
53
103
|
/**
|
|
54
104
|
* The matched subject text as it appeared in the query.
|
|
55
105
|
*/
|
|
56
106
|
subject: string
|
|
107
|
+
subjectSpan: POIQuerySpan
|
|
108
|
+
/**
|
|
109
|
+
* The relation crossing from the subject span to the anchor span.
|
|
110
|
+
*/
|
|
111
|
+
relation?: POISpatialRelation
|
|
112
|
+
relationSpan?: POIQuerySpan
|
|
57
113
|
/**
|
|
58
114
|
* The anchor remainder after the separator; `""` when the whole input matched.
|
|
59
115
|
*/
|
|
60
116
|
remainder: string
|
|
117
|
+
anchorSpan?: POIQuerySpan
|
|
61
118
|
}
|
|
62
119
|
|
|
63
120
|
/**
|
|
64
|
-
* Anchor separator between subject and place: comma, or near/in/at/around — scanned left-to-right until a prefix
|
|
65
|
-
* the lexicon.
|
|
121
|
+
* Anchor separator between subject and place: comma, or near/in/at/around/to — scanned left-to-right until a prefix
|
|
122
|
+
* hits the lexicon.
|
|
66
123
|
*
|
|
67
124
|
* Linear by construction (no polynomial ReDoS): neither alternative places an unbounded whitespace quantifier _before_
|
|
68
125
|
* its required literal — the classic `\s*`/`\s+`-then-literal backtracking shape that CodeQL's `js/polynomial-redos`
|
|
@@ -78,18 +135,33 @@ export interface POISubjectMatch {
|
|
|
78
135
|
* lastIndex) identical, preserving the exact subsequent-match sequence. Verified: 0 divergences across 22.7k inputs
|
|
79
136
|
* (systematic + fuzzed adversarial whitespace + shared-whitespace anchor/comma chains).
|
|
80
137
|
*/
|
|
81
|
-
const ANCHOR_SEPARATOR = /,\s*|\s(
|
|
138
|
+
const ANCHOR_SEPARATOR = /,\s*|\s(near|in|at|around|to)\s+/gi
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Longest subject we accept, in tokens. Eight covers compound taxonomy phrases while bounding lexicon probes.
|
|
142
|
+
*/
|
|
143
|
+
const MAX_SUBJECT_TOKENS = 8
|
|
82
144
|
|
|
83
145
|
/**
|
|
84
|
-
*
|
|
146
|
+
* The categories one candidate subject reaches, from the hits the lookup returned for it.
|
|
147
|
+
*
|
|
148
|
+
* The whole array when the first hit declares {@link POIPhraseMatch.searchAsSet} — carried as the lookup returned it,
|
|
149
|
+
* never filtered, so a rung that flagged only some of its members loses nothing here and the inconsistency stays
|
|
150
|
+
* visible to whoever reads the set. Otherwise the first hit alone, which is the preference-list reading the committed
|
|
151
|
+
* phrase index has always had.
|
|
85
152
|
*/
|
|
86
|
-
|
|
153
|
+
function reachedMatches(hits: ReadonlyArray<POIPhraseMatch>): POIPhraseMatch[] {
|
|
154
|
+
return hits[0]!.searchAsSet ? [...hits] : [hits[0]!]
|
|
155
|
+
}
|
|
87
156
|
|
|
88
157
|
/**
|
|
89
158
|
* Match a POI subject: the whole input, or the text before the FIRST anchor separator WHOSE PREFIX HITS THE LEXICON (≤
|
|
90
|
-
*
|
|
159
|
+
* 8 tokens). Scans separator occurrences left-to-right — a lexicon phrase may itself contain a bare separator word
|
|
91
160
|
* (e.g. "walk in clinic"), so the first separator isn't necessarily the right split point. Returns null when the
|
|
92
161
|
* lexicon never fires — including comma-ridden full addresses whose leading segment isn't a lexicon phrase.
|
|
162
|
+
*
|
|
163
|
+
* The winning candidate's hits are carried per {@link reachedMatches}: the first hit, or the whole set when the lookup
|
|
164
|
+
* declared one.
|
|
93
165
|
*/
|
|
94
166
|
export function matchPOISubject(
|
|
95
167
|
text: string,
|
|
@@ -97,13 +169,22 @@ export function matchPOISubject(
|
|
|
97
169
|
lookup: POIPhraseLookup
|
|
98
170
|
): POISubjectMatch | null {
|
|
99
171
|
const trimmed = text.trim()
|
|
172
|
+
const inputStart = text.indexOf(trimmed)
|
|
100
173
|
|
|
101
174
|
if (!trimmed) return null
|
|
102
175
|
|
|
103
176
|
const whole = lookup(trimmed, locale)
|
|
104
177
|
|
|
105
178
|
if (whole.length) {
|
|
106
|
-
|
|
179
|
+
const matches = reachedMatches(whole)
|
|
180
|
+
|
|
181
|
+
return {
|
|
182
|
+
match: matches[0]!,
|
|
183
|
+
matches,
|
|
184
|
+
subject: trimmed,
|
|
185
|
+
subjectSpan: { text: trimmed, start: inputStart, end: inputStart + trimmed.length },
|
|
186
|
+
remainder: "",
|
|
187
|
+
}
|
|
107
188
|
}
|
|
108
189
|
|
|
109
190
|
for (const separator of trimmed.matchAll(ANCHOR_SEPARATOR)) {
|
|
@@ -111,7 +192,8 @@ export function matchPOISubject(
|
|
|
111
192
|
|
|
112
193
|
const subject = trimmed.slice(0, separator.index).trim()
|
|
113
194
|
|
|
114
|
-
// Subjects only grow as the scan moves right — once over budget, later splits are too.
|
|
195
|
+
// Subjects only grow as the scan moves right — once over budget, later splits are too. Whitespace-only
|
|
196
|
+
// split, not `wordsOf`: a comma inside a subject is real content here, not a separator to erase.
|
|
115
197
|
if (subject.split(/\s+/).length > MAX_SUBJECT_TOKENS) break
|
|
116
198
|
|
|
117
199
|
const hits = lookup(subject, locale)
|
|
@@ -120,7 +202,36 @@ export function matchPOISubject(
|
|
|
120
202
|
|
|
121
203
|
const remainder = trimmed.slice(separator.index + separator[0].length).trim()
|
|
122
204
|
|
|
123
|
-
|
|
205
|
+
if (!remainder) continue
|
|
206
|
+
|
|
207
|
+
const subjectOffset = trimmed.slice(0, separator.index).indexOf(subject)
|
|
208
|
+
const anchorOffset = trimmed.indexOf(remainder, separator.index + separator[0].length)
|
|
209
|
+
const relationText = separator[1] ?? ","
|
|
210
|
+
const relationOffset = separator[1] ? separator.index + separator[0].indexOf(separator[1]) : separator.index
|
|
211
|
+
const matches = reachedMatches(hits)
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
match: matches[0]!,
|
|
215
|
+
matches,
|
|
216
|
+
subject,
|
|
217
|
+
subjectSpan: {
|
|
218
|
+
text: subject,
|
|
219
|
+
start: inputStart + subjectOffset,
|
|
220
|
+
end: inputStart + subjectOffset + subject.length,
|
|
221
|
+
},
|
|
222
|
+
relation: relationText === "," ? "comma" : (relationText.toLowerCase() as POISpatialRelation),
|
|
223
|
+
relationSpan: {
|
|
224
|
+
text: relationText,
|
|
225
|
+
start: inputStart + relationOffset,
|
|
226
|
+
end: inputStart + relationOffset + relationText.length,
|
|
227
|
+
},
|
|
228
|
+
remainder,
|
|
229
|
+
anchorSpan: {
|
|
230
|
+
text: remainder,
|
|
231
|
+
start: inputStart + anchorOffset,
|
|
232
|
+
end: inputStart + anchorOffset + remainder.length,
|
|
233
|
+
},
|
|
234
|
+
}
|
|
124
235
|
}
|
|
125
236
|
|
|
126
237
|
return null
|
|
@@ -188,7 +299,7 @@ export function createScorePOICategory(
|
|
|
188
299
|
|
|
189
300
|
/**
|
|
190
301
|
* The whole-input category hit behind a `poi_category` verdict, for the marker's evidence. `null` when the input is not
|
|
191
|
-
* a bare category — same
|
|
302
|
+
* a bare category — same conditions as {@link createScorePOICategory}, so the two cannot disagree.
|
|
192
303
|
*/
|
|
193
304
|
export function matchPOICategory(
|
|
194
305
|
text: string,
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
* regex set per new locale, not 50K dictionary entries.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import
|
|
13
|
+
import { NAME_PRONE_US_SUFFIXES, US_STREET_SUFFIX_LOOKUP } from "@mailwoman/codex/us/street-suffix"
|
|
14
|
+
|
|
15
|
+
import type { NormalizedInputLite, QueryShapeLike } from "#types"
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* Longest input still plausible as a bare venue or landmark name. Beyond it the query is carrying an address as well,
|
|
@@ -128,34 +130,25 @@ export function scoreLandmark(input: NormalizedInputLite, _shape: QueryShapeLike
|
|
|
128
130
|
}
|
|
129
131
|
|
|
130
132
|
/**
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
+
* Split on whitespace + commas and drop empty words — the word grammar shared with `intent-rules.ts`. Dropping empties
|
|
134
|
+
* matters: a trailing comma or doubled separator otherwise yields an empty string that inflates the word count and
|
|
135
|
+
* falsifies every-word predicates like the proper-case check below.
|
|
133
136
|
*/
|
|
134
|
-
export
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
"pl",
|
|
150
|
-
"place",
|
|
151
|
-
"way",
|
|
152
|
-
"pkwy",
|
|
153
|
-
"parkway",
|
|
154
|
-
"hwy",
|
|
155
|
-
"highway",
|
|
156
|
-
"cir",
|
|
157
|
-
"circle",
|
|
158
|
-
])
|
|
137
|
+
export function wordsOf(text: string): string[] {
|
|
138
|
+
return text.split(/[\s,]+/).filter((word) => word.length > 0)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* True when a word is USPS street-suffix vocabulary that unambiguously signals an address — the full Pub-28 table via
|
|
143
|
+
* `@mailwoman/codex`, minus its curated name-prone canonicals (PARK, FIELD, HILL, LAKE, …). Those double as ordinary
|
|
144
|
+
* proper-name heads ("Wrigley Field", "Menlo Park"), and disqualifying on them would reject the very venue and place
|
|
145
|
+
* names the rules below exist to capture. Shared with `intent-rules.ts` so both rule sets read one definition.
|
|
146
|
+
*/
|
|
147
|
+
export function isDisqualifyingStreetSuffix(word: string): boolean {
|
|
148
|
+
const canonical = US_STREET_SUFFIX_LOOKUP.get(word.trim().toLowerCase())
|
|
149
|
+
|
|
150
|
+
return canonical !== undefined && !NAME_PRONE_US_SUFFIXES.has(canonical)
|
|
151
|
+
}
|
|
159
152
|
|
|
160
153
|
/**
|
|
161
154
|
* `landmark` rule (venue/named-place variant): short capitalized input with no street suffixes, no postcode hits, and
|
|
@@ -181,11 +174,11 @@ export function scoreVenueLandmark(input: NormalizedInputLite, shape: QueryShape
|
|
|
181
174
|
|
|
182
175
|
if (segCount > 2) return 0
|
|
183
176
|
|
|
184
|
-
// Reject if any word is
|
|
185
|
-
const words = text
|
|
177
|
+
// Reject if any word is an unambiguous street suffix.
|
|
178
|
+
const words = wordsOf(text)
|
|
186
179
|
|
|
187
180
|
for (const w of words) {
|
|
188
|
-
if (
|
|
181
|
+
if (isDisqualifyingStreetSuffix(w)) return 0
|
|
189
182
|
}
|
|
190
183
|
|
|
191
184
|
// Reject if the first token is a pure number (house-number-leading pattern).
|
|
@@ -228,6 +221,10 @@ const POSTCODE_FORMATS: ReadonlySet<string> = new Set([
|
|
|
228
221
|
"ca_postcode",
|
|
229
222
|
"jp_postcode",
|
|
230
223
|
"nl_postcode",
|
|
224
|
+
"cz_postcode",
|
|
225
|
+
"sk_postcode",
|
|
226
|
+
"se_postcode",
|
|
227
|
+
"gr_postcode",
|
|
231
228
|
])
|
|
232
229
|
|
|
233
230
|
/**
|
package/lib/types.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Re-exports of the canonical types from `@mailwoman/core/pipeline`.
|
|
9
|
+
*/
|
|
10
|
+
export type { LocaleHint, QueryIntentMarker, QueryKind, QueryKindResult } from "@mailwoman/core/pipeline"
|
|
11
|
+
export { QueryIntentCode } from "@mailwoman/core/pipeline"
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The minimal input shapes consumed by `classifyKind` come from `@mailwoman/query-shape` — one declaration shared by
|
|
15
|
+
* every Stage-2.x consumer. `QueryShapeLike` stays this package's public name for its narrow read-only view.
|
|
16
|
+
*/
|
|
17
|
+
export type { NormalizedInputLite, QueryShapeSegmentsView as QueryShapeLike } from "@mailwoman/query-shape"
|
package/out/classify.d.ts
CHANGED
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
* are scored below their structural incumbent precisely so they land in `alternatives`, where they
|
|
16
16
|
* inform the markers without moving the routing decision.
|
|
17
17
|
*/
|
|
18
|
-
import { type POIPhraseLookup } from "
|
|
19
|
-
import type { LocaleHint, NormalizedInputLite, QueryKindResult, QueryShapeLike } from "
|
|
18
|
+
import { type POIPhraseLookup } from "#poi";
|
|
19
|
+
import type { LocaleHint, NormalizedInputLite, QueryKindResult, QueryShapeLike } from "#types";
|
|
20
20
|
/**
|
|
21
21
|
* Classify the query shape into a `QueryKind`. Synchronous + pure — produces the same result for the same `(input,
|
|
22
22
|
* shape)` pair.
|
package/out/classify.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../classify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,EAA+C,KAAK,eAAe,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../lib/classify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,EAA+C,KAAK,eAAe,EAAE,MAAM,MAAM,CAAA;AAWxF,OAAO,KAAK,EACX,UAAU,EACV,mBAAmB,EAGnB,eAAe,EACf,cAAc,EACd,MAAM,QAAQ,CAAA;AAkEf;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,cAAc,GAAG,eAAe,CAMnG;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CACjC,KAAK,EAAE,mBAAmB,EAC1B,KAAK,EAAE,cAAc,EACrB,OAAO,CAAC,EAAE,UAAU,GAClB,OAAO,CAAC,eAAe,CAAC,CAE1B;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC;;;;OAIG;IACH,UAAU,CAAC,EAAE,eAAe,CAAA;CAC5B;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CACnC,IAAI,GAAE,kBAAuB,GAC3B,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,UAAU,KAAK,OAAO,CAAC,eAAe,CAAC,CA+BtG"}
|
package/out/classify.js
CHANGED
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
* are scored below their structural incumbent precisely so they land in `alternatives`, where they
|
|
16
16
|
* inform the markers without moving the routing decision.
|
|
17
17
|
*/
|
|
18
|
-
import { deriveIntentMarkers } from "
|
|
19
|
-
import { scoreBareToponym, scoreNearMe, scoreRoutePair } from "
|
|
20
|
-
import { createScorePOICategory, createScorePOIQuery } from "
|
|
21
|
-
import { scoreIntersection, scoreLandmark, scoreLocalityOnly, scorePoBox, scorePostcodeOnly, scoreStructuredAddress, scoreVague, scoreVenueLandmark, } from "
|
|
18
|
+
import { deriveIntentMarkers } from "#intent-markers";
|
|
19
|
+
import { scoreBareToponym, scoreNearMe, scoreRoutePair } from "#intent-rules";
|
|
20
|
+
import { createScorePOICategory, createScorePOIQuery } from "#poi";
|
|
21
|
+
import { scoreIntersection, scoreLandmark, scoreLocalityOnly, scorePoBox, scorePostcodeOnly, scoreStructuredAddress, scoreVague, scoreVenueLandmark, } from "#rules";
|
|
22
22
|
const SCORERS = [
|
|
23
23
|
{ kind: "po_box", score: scorePoBox },
|
|
24
24
|
{ kind: "landmark", score: (i, s) => Math.max(scoreLandmark(i, s), scoreVenueLandmark(i, s)) },
|
package/out/classify.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"classify.js","sourceRoot":"","sources":["../classify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"classify.js","sourceRoot":"","sources":["../lib/classify.ts"],"names":[],"mappings":"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"}
|
package/out/index.d.ts
CHANGED
|
@@ -12,14 +12,14 @@
|
|
|
12
12
|
*
|
|
13
13
|
* See `docs/engineering/reference/STAGES.md` § Stage 2.5 for the contract.
|
|
14
14
|
*/
|
|
15
|
-
export { classifyKind, classifyKindSync, createKindClassifier } from "
|
|
16
|
-
export type { KindClassifierOpts } from "
|
|
17
|
-
export { deriveIntentMarkers } from "
|
|
18
|
-
export type { IntentMarkerContext } from "
|
|
19
|
-
export { nearMeSubject, scoreBareToponym, scoreNearMe, scoreRoutePair } from "
|
|
20
|
-
export { matchPOICategory, matchPOISubject } from "
|
|
21
|
-
export type { POIPhraseMatch, POIPhraseLookup, POISubjectMatch } from "
|
|
22
|
-
export { scoreIntersection, scoreLandmark, scoreLocalityOnly, scorePoBox, scorePostcodeOnly, scoreStructuredAddress, scoreVague, scoreVenueLandmark, } from "
|
|
23
|
-
export { QueryIntentCode } from "
|
|
24
|
-
export type { LocaleHint, NormalizedInputLite, QueryIntentMarker, QueryKind, QueryKindResult, QueryShapeLike, } from "
|
|
15
|
+
export { classifyKind, classifyKindSync, createKindClassifier } from "#classify";
|
|
16
|
+
export type { KindClassifierOpts } from "#classify";
|
|
17
|
+
export { deriveIntentMarkers } from "#intent-markers";
|
|
18
|
+
export type { IntentMarkerContext } from "#intent-markers";
|
|
19
|
+
export { nearMeSubject, scoreBareToponym, scoreNearMe, scoreRoutePair } from "#intent-rules";
|
|
20
|
+
export { matchPOICategory, matchPOISubject } from "#poi";
|
|
21
|
+
export type { POIPhraseMatch, POIPhraseLookup, POIQuerySpan, POISpatialRelation, POISubjectMatch } from "#poi";
|
|
22
|
+
export { scoreIntersection, scoreLandmark, scoreLocalityOnly, scorePoBox, scorePostcodeOnly, scoreStructuredAddress, scoreVague, scoreVenueLandmark, } from "#rules";
|
|
23
|
+
export { QueryIntentCode } from "#types";
|
|
24
|
+
export type { LocaleHint, NormalizedInputLite, QueryIntentMarker, QueryKind, QueryKindResult, QueryShapeLike, } from "#types";
|
|
25
25
|
//# sourceMappingURL=index.d.ts.map
|
package/out/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAChF,YAAY,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AACrD,YAAY,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAC1D,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC5F,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,MAAM,CAAA;AACxD,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,YAAY,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,MAAM,CAAA;AAE9G,OAAO,EACN,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,iBAAiB,EACjB,sBAAsB,EACtB,UAAU,EACV,kBAAkB,GAClB,MAAM,QAAQ,CAAA;AAEf,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAA;AAExC,YAAY,EACX,UAAU,EACV,mBAAmB,EACnB,iBAAiB,EACjB,SAAS,EACT,eAAe,EACf,cAAc,GACd,MAAM,QAAQ,CAAA"}
|
package/out/index.js
CHANGED
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
*
|
|
13
13
|
* See `docs/engineering/reference/STAGES.md` § Stage 2.5 for the contract.
|
|
14
14
|
*/
|
|
15
|
-
export { classifyKind, classifyKindSync, createKindClassifier } from "
|
|
16
|
-
export { deriveIntentMarkers } from "
|
|
17
|
-
export { nearMeSubject, scoreBareToponym, scoreNearMe, scoreRoutePair } from "
|
|
18
|
-
export { matchPOICategory, matchPOISubject } from "
|
|
19
|
-
export { scoreIntersection, scoreLandmark, scoreLocalityOnly, scorePoBox, scorePostcodeOnly, scoreStructuredAddress, scoreVague, scoreVenueLandmark, } from "
|
|
20
|
-
export { QueryIntentCode } from "
|
|
15
|
+
export { classifyKind, classifyKindSync, createKindClassifier } from "#classify";
|
|
16
|
+
export { deriveIntentMarkers } from "#intent-markers";
|
|
17
|
+
export { nearMeSubject, scoreBareToponym, scoreNearMe, scoreRoutePair } from "#intent-rules";
|
|
18
|
+
export { matchPOICategory, matchPOISubject } from "#poi";
|
|
19
|
+
export { scoreIntersection, scoreLandmark, scoreLocalityOnly, scorePoBox, scorePostcodeOnly, scoreStructuredAddress, scoreVague, scoreVenueLandmark, } from "#rules";
|
|
20
|
+
export { QueryIntentCode } from "#types";
|
|
21
21
|
//# sourceMappingURL=index.js.map
|
package/out/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAEhF,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAErD,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC5F,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,MAAM,CAAA;AAGxD,OAAO,EACN,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,iBAAiB,EACjB,sBAAsB,EACtB,UAAU,EACV,kBAAkB,GAClB,MAAM,QAAQ,CAAA;AAEf,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAA"}
|