@lde/search 0.28.0 → 0.28.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter.d.ts +1 -0
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +1 -0
- package/dist/language.d.ts +22 -0
- package/dist/language.d.ts.map +1 -0
- package/dist/language.js +54 -0
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +31 -3
- package/package.json +1 -1
package/dist/adapter.d.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
export { assertTypeInSchema, physicalFields, irAlias, displayFieldName, displayFieldPattern, displayLangOf, searchableFields, facetableFields, filterableFields, sortableFields, outputFields, isInternalField, isInlineReference, nestedReferenceType, nestedFieldName, localLookupTypeOf, identityFieldOf, identityFieldName, referenceFields, referenceTypeNamed, rootTypeNamed, inlineFramingDepth, fieldNamed, datasetField, ID_FIELD, AND_KEY, OR_KEY, labelFieldOf, labelFieldNameOf, labelSourceNameOf, labelTargetNameOf, documentKeyOf, DEFAULT_LABEL_FIELD, isRangeFacet, isAbsoluteIri, isoToUnixSeconds, unixSecondsToIso, } from './schema.js';
|
|
10
10
|
export type { PhysicalFields } from './schema.js';
|
|
11
11
|
export { physicalNameTokens } from './physical-name.js';
|
|
12
|
+
export { matchLanguage } from './language.js';
|
|
12
13
|
export { joinGraph, MAX_JOIN_DEPTH } from './join-graph.js';
|
|
13
14
|
export type { JoinGraph } from './join-graph.js';
|
|
14
15
|
export { filterOperatorFor, filterOperator, filterOn, isWelded, isUnsatisfiable, validateQuery, assertValidQuery, resolvePath, pageForOffset, } from './query.js';
|
package/dist/adapter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,OAAO,EACP,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAClB,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,OAAO,EACP,MAAM,EACN,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,EACb,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC5D,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,cAAc,EACd,UAAU,EACV,YAAY,EACZ,WAAW,GACZ,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,OAAO,EACP,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAClB,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,OAAO,EACP,MAAM,EACN,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,EACb,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC5D,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,cAAc,EACd,UAAU,EACV,YAAY,EACZ,WAAW,GACZ,MAAM,YAAY,CAAC"}
|
package/dist/adapter.js
CHANGED
|
@@ -8,5 +8,6 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export { assertTypeInSchema, physicalFields, irAlias, displayFieldName, displayFieldPattern, displayLangOf, searchableFields, facetableFields, filterableFields, sortableFields, outputFields, isInternalField, isInlineReference, nestedReferenceType, nestedFieldName, localLookupTypeOf, identityFieldOf, identityFieldName, referenceFields, referenceTypeNamed, rootTypeNamed, inlineFramingDepth, fieldNamed, datasetField, ID_FIELD, AND_KEY, OR_KEY, labelFieldOf, labelFieldNameOf, labelSourceNameOf, labelTargetNameOf, documentKeyOf, DEFAULT_LABEL_FIELD, isRangeFacet, isAbsoluteIri, isoToUnixSeconds, unixSecondsToIso, } from './schema.js';
|
|
10
10
|
export { physicalNameTokens } from './physical-name.js';
|
|
11
|
+
export { matchLanguage } from './language.js';
|
|
11
12
|
export { joinGraph, MAX_JOIN_DEPTH } from './join-graph.js';
|
|
12
13
|
export { filterOperatorFor, filterOperator, filterOn, isWelded, isUnsatisfiable, validateQuery, assertValidQuery, resolvePath, pageForOffset, } from './query.js';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The entries of `candidates` that language tag `tag` matches, best first, as
|
|
3
|
+
* the entries themselves (so a caller can index back into `candidates`).
|
|
4
|
+
*
|
|
5
|
+
* Tags are compared per BCP-47 subtag and case-insensitively, as language
|
|
6
|
+
* ranges (RFC 4647). A candidate matches when it shares the tag’s primary
|
|
7
|
+
* language, ranked:
|
|
8
|
+
*
|
|
9
|
+
* 1. the exact tag (`nl-NL` for `nl-NL`);
|
|
10
|
+
* 2. the tag’s truncations, most specific first – RFC 4647 lookup, so a
|
|
11
|
+
* request for `nl-NL` finds a declared `nl`;
|
|
12
|
+
* 3. the tags it is a prefix of, in `candidates` order – RFC 4647 basic
|
|
13
|
+
* filtering, so a range `nl` finds `nl-NL` and `nl-BE`;
|
|
14
|
+
* 4. the remaining tags of the same language, longest shared prefix first, so
|
|
15
|
+
* a request for `nl-NL` still finds `nl-BE` rather than another language.
|
|
16
|
+
*
|
|
17
|
+
* The exact match therefore still wins where a general and a specific tag sit
|
|
18
|
+
* side by side (`en` and `en-GB`). `und`, the untagged bucket, matches nothing
|
|
19
|
+
* but `und`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function matchLanguage(tag: string, candidates: readonly string[]): string[];
|
|
22
|
+
//# sourceMappingURL=language.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"language.d.ts","sourceRoot":"","sources":["../src/language.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,SAAS,MAAM,EAAE,GAC5B,MAAM,EAAE,CA4BV"}
|
package/dist/language.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The entries of `candidates` that language tag `tag` matches, best first, as
|
|
3
|
+
* the entries themselves (so a caller can index back into `candidates`).
|
|
4
|
+
*
|
|
5
|
+
* Tags are compared per BCP-47 subtag and case-insensitively, as language
|
|
6
|
+
* ranges (RFC 4647). A candidate matches when it shares the tag’s primary
|
|
7
|
+
* language, ranked:
|
|
8
|
+
*
|
|
9
|
+
* 1. the exact tag (`nl-NL` for `nl-NL`);
|
|
10
|
+
* 2. the tag’s truncations, most specific first – RFC 4647 lookup, so a
|
|
11
|
+
* request for `nl-NL` finds a declared `nl`;
|
|
12
|
+
* 3. the tags it is a prefix of, in `candidates` order – RFC 4647 basic
|
|
13
|
+
* filtering, so a range `nl` finds `nl-NL` and `nl-BE`;
|
|
14
|
+
* 4. the remaining tags of the same language, longest shared prefix first, so
|
|
15
|
+
* a request for `nl-NL` still finds `nl-BE` rather than another language.
|
|
16
|
+
*
|
|
17
|
+
* The exact match therefore still wins where a general and a specific tag sit
|
|
18
|
+
* side by side (`en` and `en-GB`). `und`, the untagged bucket, matches nothing
|
|
19
|
+
* but `und`.
|
|
20
|
+
*/
|
|
21
|
+
export function matchLanguage(tag, candidates) {
|
|
22
|
+
const subtags = tag.toLowerCase().split('-');
|
|
23
|
+
const ranked = [];
|
|
24
|
+
for (const candidate of candidates) {
|
|
25
|
+
const candidateSubtags = candidate.toLowerCase().split('-');
|
|
26
|
+
const shared = sharedPrefixLength(subtags, candidateSubtags);
|
|
27
|
+
const exact = shared === subtags.length && shared === candidateSubtags.length;
|
|
28
|
+
if (shared === 0 || (subtags[0] === 'und' && !exact)) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const kind = exact
|
|
32
|
+
? 0
|
|
33
|
+
: shared === candidateSubtags.length
|
|
34
|
+
? 1
|
|
35
|
+
: shared === subtags.length
|
|
36
|
+
? 2
|
|
37
|
+
: 3;
|
|
38
|
+
// Extensions keep candidate order; truncations and siblings rank by how
|
|
39
|
+
// much of the tag they share.
|
|
40
|
+
ranked.push({ candidate, kind, closeness: kind === 2 ? 0 : shared });
|
|
41
|
+
}
|
|
42
|
+
return ranked
|
|
43
|
+
.sort((left, right) => left.kind - right.kind || right.closeness - left.closeness)
|
|
44
|
+
.map(({ candidate }) => candidate);
|
|
45
|
+
}
|
|
46
|
+
function sharedPrefixLength(left, right) {
|
|
47
|
+
let length = 0;
|
|
48
|
+
while (length < left.length &&
|
|
49
|
+
length < right.length &&
|
|
50
|
+
left[length] === right[length]) {
|
|
51
|
+
length++;
|
|
52
|
+
}
|
|
53
|
+
return length;
|
|
54
|
+
}
|
package/dist/project.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAGzC,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAkBL,KAAK,eAAe,EAEpB,KAAK,QAAQ,EAEb,KAAK,YAAY,EACjB,KAAK,UAAU,EAEhB,MAAM,aAAa,CAAC;AAErB;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEpD,+DAA+D;AAC/D,MAAM,MAAM,cAAc,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,aAAa,CAAC;AAE5D;;;;;;;;;;GAUG;AACH,MAAM,WAAW,iBAAkB,SAAQ,OAAO,CAChD,QAAQ,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAC1C;IACC,4CAA4C;IAC5C,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAKD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,UAAU,EAChB,UAAU,EAAE,UAAU,EACtB,MAAM,CAAC,EAAE,YAAY,EACrB,OAAO,GAAE,iBAAyC,GACjD,cAAc,CAgBhB;AAwKD;;;;;;;;;;;;GAYG;AACH,wBAAuB,YAAY,CACjC,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,EACrB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,QAAQ,EACpB,OAAO,GAAE,iBAAyC,GACjD,aAAa,CAAC,cAAc,CAAC,CAc/B"}
|
package/dist/project.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { fold } from '@lde/text-normalization';
|
|
2
|
+
import { matchLanguage } from './language.js';
|
|
2
3
|
import { buildSubjectIndex, frameSubjects, } from './frame-by-type.js';
|
|
3
4
|
import { assertTypeInSchema, displayFieldName, documentKeyOf, fieldNamed, inheritedFacetKeys, inlineFramingDepth, irAlias, isAbsoluteIri, isInternalField, isInlineReference, isoToUnixSeconds, labelSourceNameOf, localLookupTypeOf, physicalFields, referenceTypeNamed, rootTypeNamed, } from './schema.js';
|
|
4
5
|
/** The context a projection runs with when its caller supplied none. */
|
|
@@ -391,9 +392,36 @@ function applyText(document, values, field) {
|
|
|
391
392
|
// here it simply indexes nothing.
|
|
392
393
|
if (field.searchable !== undefined || field.sortable === true) {
|
|
393
394
|
const names = physicalFields(field);
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
395
|
+
// A literal lands under the declared locale its tag best matches as a
|
|
396
|
+
// language range, so `nl-NL` titles are keyed under a declared `nl`; within
|
|
397
|
+
// a locale, the exact tag comes first.
|
|
398
|
+
const valuesPerLanguage = new Map();
|
|
399
|
+
for (const { lang, value } of values) {
|
|
400
|
+
const languageValues = valuesPerLanguage.get(lang);
|
|
401
|
+
if (languageValues === undefined) {
|
|
402
|
+
valuesPerLanguage.set(lang, [value]);
|
|
403
|
+
}
|
|
404
|
+
else {
|
|
405
|
+
languageValues.push(value);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
const languagesPerLocale = new Map();
|
|
409
|
+
for (const entry of valuesPerLanguage) {
|
|
410
|
+
const locale = matchLanguage(entry[0], field.locales)[0];
|
|
411
|
+
if (locale !== undefined) {
|
|
412
|
+
languagesPerLocale.set(locale, [
|
|
413
|
+
...(languagesPerLocale.get(locale) ?? []),
|
|
414
|
+
entry,
|
|
415
|
+
]);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
const valuesPerLocale = field.locales.map((locale) => {
|
|
419
|
+
const entries = languagesPerLocale.get(locale) ?? [];
|
|
420
|
+
const ranked = matchLanguage(locale, entries.map(([language]) => language));
|
|
421
|
+
return entries
|
|
422
|
+
.sort(([left], [right]) => ranked.indexOf(left) - ranked.indexOf(right))
|
|
423
|
+
.flatMap(([, languageValues]) => languageValues);
|
|
424
|
+
});
|
|
397
425
|
// What every locale’s sort key falls back to: the document’s first value
|
|
398
426
|
// in `locales` order, which is the declaration’s own statement of which
|
|
399
427
|
// language stands in for the others.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lde/search",
|
|
3
|
-
"version": "0.28.
|
|
3
|
+
"version": "0.28.1",
|
|
4
4
|
"description": "Engine- and domain-agnostic core for RDF-backed search: a unified declarative field model (SearchField/SearchType/SearchSchema), a neutral query IR, the SearchEngine port with logical result types, and a streaming CONSTRUCT-to-document projection. Bakes in no engine, protocol, or domain.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "git+https://github.com/ldelements/lde.git",
|