@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 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';
@@ -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"}
@@ -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
+ }
@@ -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;AAEzC,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"}
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
- const valuesPerLocale = field.locales.map((locale) => values
395
- .filter((value) => value.lang === locale)
396
- .map((value) => value.value));
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.0",
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",