@digigov/text-search 1.2.0-85c27c19 → 1.2.0-aefd0709

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/cjs/hook/index.js CHANGED
@@ -32,19 +32,19 @@ __export(hook_exports, {
32
32
  });
33
33
  module.exports = __toCommonJS(hook_exports);
34
34
  var import_react = require("react");
35
- var import_search = __toESM(require("./search"));
35
+ var import_search = __toESM(require("@digigov/text-search/search"));
36
36
  function useSearch(documents, query, options) {
37
37
  const [loading, setLoading] = (0, import_react.useState)(false);
38
38
  const [data, setData] = (0, import_react.useState)(documents);
39
39
  const indexing = options?.indexing;
40
- const index = (0, import_react.useMemo)(() => new import_search.default(documents, indexing), [
41
- documents,
42
- indexing
43
- ]);
40
+ const index = (0, import_react.useMemo)(
41
+ () => new import_search.default(documents, indexing),
42
+ [documents, indexing]
43
+ );
44
44
  const search = (0, import_react.useCallback)(() => {
45
45
  if (query) {
46
46
  setLoading(true);
47
- index.searchAsync(documents, query).then((data2) => setData(data2)).finally(() => setLoading(false));
47
+ index.searchAsync(documents, query).then((data2) => setData(data2)).catch(() => setData([])).finally(() => setLoading(false));
48
48
  } else {
49
49
  setData(documents);
50
50
  }
package/cjs/hook.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/hook.ts"],
4
- "sourcesContent": ["import { useCallback, useMemo, useState } from 'react';\nimport SearchIndex from './search';\nimport { UseSearchOptions } from './types';\n\n/**\n * Hook for searching through a list of documents\n *\n * Returns a list of documents that match the search query.\n * If no query is provided, it returns the original list of documents.\n *\n * @param documents - The list of documents to search through\n * @param options - Options for configuring the search index\n * @param query - The search query\n *\n * @typeParam T - The type of the data in the documents list\n */\nexport default function useSearch<T extends Record<string, any>>(\n documents: T[],\n query?: string,\n options?: UseSearchOptions<T>\n) {\n const [loading, setLoading] = useState(false);\n const [data, setData] = useState(documents);\n\n const indexing = options?.indexing;\n\n const index = useMemo(() => new SearchIndex(documents, indexing), [\n documents,\n indexing,\n ]);\n\n const search = useCallback(() => {\n if (query) {\n setLoading(true);\n index\n .searchAsync(documents, query)\n .then((data) => setData(data))\n .finally(() => setLoading(false));\n } else {\n setData(documents);\n }\n }, [query, index, documents]);\n\n const reset = useCallback(() => {\n setData(documents);\n setLoading(false);\n }, [documents]);\n\n return { data, loading, search, reset };\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA+C;AAC/C,oBAAwB;AAeT,SAAR,UACL,WACA,OACA,SACA;AACA,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAS,KAAK;AAC5C,QAAM,CAAC,MAAM,OAAO,QAAI,uBAAS,SAAS;AAE1C,QAAM,WAAW,SAAS;AAE1B,QAAM,YAAQ,sBAAQ,MAAM,IAAI,cAAAA,QAAY,WAAW,QAAQ,GAAG;AAAA,IAChE;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,aAAS,0BAAY,MAAM;AAC/B,QAAI,OAAO;AACT,iBAAW,IAAI;AACf,YACG,YAAY,WAAW,KAAK,EAC5B,KAAK,CAACC,UAAS,QAAQA,KAAI,CAAC,EAC5B,QAAQ,MAAM,WAAW,KAAK,CAAC;AAAA,IACpC,OAAO;AACL,cAAQ,SAAS;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,OAAO,OAAO,SAAS,CAAC;AAE5B,QAAM,YAAQ,0BAAY,MAAM;AAC9B,YAAQ,SAAS;AACjB,eAAW,KAAK;AAAA,EAClB,GAAG,CAAC,SAAS,CAAC;AAEd,SAAO,EAAE,MAAM,SAAS,QAAQ,MAAM;AACxC;",
4
+ "sourcesContent": ["import { useCallback, useMemo, useState } from 'react';\nimport SearchIndex from '@digigov/text-search/search';\nimport { UseSearchOptions } from '@digigov/text-search/types';\n\n/**\n * Hook for searching through a list of documents\n *\n * Returns a list of documents that match the search query.\n * If no query is provided, it returns the original list of documents.\n *\n * @param documents - The list of documents to search through\n * @param options - Options for configuring the search index\n * @param query - The search query\n *\n * @typeParam T - The type of the data in the documents list\n */\nexport default function useSearch<T extends Record<string, any>>(\n documents: T[],\n query?: string,\n options?: UseSearchOptions<T>\n) {\n const [loading, setLoading] = useState(false);\n const [data, setData] = useState(documents);\n\n const indexing = options?.indexing;\n\n const index = useMemo(\n () => new SearchIndex(documents, indexing),\n [documents, indexing]\n );\n\n const search = useCallback(() => {\n if (query) {\n setLoading(true);\n index\n .searchAsync(documents, query)\n .then((data) => setData(data))\n .catch(() => setData([]))\n .finally(() => setLoading(false));\n } else {\n setData(documents);\n }\n }, [query, index, documents]);\n\n const reset = useCallback(() => {\n setData(documents);\n setLoading(false);\n }, [documents]);\n\n return { data, loading, search, reset };\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA+C;AAC/C,oBAAwB;AAeT,SAAR,UACL,WACA,OACA,SACA;AACA,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAS,KAAK;AAC5C,QAAM,CAAC,MAAM,OAAO,QAAI,uBAAS,SAAS;AAE1C,QAAM,WAAW,SAAS;AAE1B,QAAM,YAAQ;AAAA,IACZ,MAAM,IAAI,cAAAA,QAAY,WAAW,QAAQ;AAAA,IACzC,CAAC,WAAW,QAAQ;AAAA,EACtB;AAEA,QAAM,aAAS,0BAAY,MAAM;AAC/B,QAAI,OAAO;AACT,iBAAW,IAAI;AACf,YACG,YAAY,WAAW,KAAK,EAC5B,KAAK,CAACC,UAAS,QAAQA,KAAI,CAAC,EAC5B,MAAM,MAAM,QAAQ,CAAC,CAAC,CAAC,EACvB,QAAQ,MAAM,WAAW,KAAK,CAAC;AAAA,IACpC,OAAO;AACL,cAAQ,SAAS;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,OAAO,OAAO,SAAS,CAAC;AAE5B,QAAM,YAAQ,0BAAY,MAAM;AAC9B,YAAQ,SAAS;AACjB,eAAW,KAAK;AAAA,EAClB,GAAG,CAAC,SAAS,CAAC;AAEd,SAAO,EAAE,MAAM,SAAS,QAAQ,MAAM;AACxC;",
6
6
  "names": ["SearchIndex", "data"]
7
7
  }
package/cjs/index.js CHANGED
@@ -32,11 +32,11 @@ __export(src_exports, {
32
32
  default: () => src_default
33
33
  });
34
34
  module.exports = __toCommonJS(src_exports);
35
- var import_hook = __toESM(require("./hook"));
36
- __reExport(src_exports, require("./search"), module.exports);
35
+ var import_hook = __toESM(require("@digigov/text-search/hook"));
36
+ __reExport(src_exports, require("@digigov/text-search/search"), module.exports);
37
37
  var src_default = import_hook.default;
38
38
  // Annotate the CommonJS export names for ESM import in node:
39
39
  0 && (module.exports = {
40
- ...require("./search")
40
+ ...require("@digigov/text-search/search")
41
41
  });
42
42
  //# sourceMappingURL=index.js.map
package/cjs/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.ts"],
4
- "sourcesContent": ["import useSearch from './hook';\n\nexport default useSearch;\nexport * from './search';\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAsB;AAGtB,wBAAc,qBAHd;AAEA,IAAO,cAAQ,YAAAA;",
4
+ "sourcesContent": ["import useSearch from '@digigov/text-search/hook';\n\nexport default useSearch;\nexport * from '@digigov/text-search/search';\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAsB;AAGtB,wBAAc,wCAHd;AAEA,IAAO,cAAQ,YAAAA;",
6
6
  "names": ["useSearch"]
7
7
  }
@@ -21,6 +21,6 @@ __export(search_exports, {
21
21
  default: () => search_default
22
22
  });
23
23
  module.exports = __toCommonJS(search_exports);
24
- var import_search_index = require("./search-index");
24
+ var import_search_index = require("@digigov/text-search/search/search-index");
25
25
  var search_default = import_search_index.SearchIndex;
26
26
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/search/index.ts"],
4
- "sourcesContent": ["import { SearchIndex } from './search-index';\n\nexport default SearchIndex;\n"],
4
+ "sourcesContent": ["import { SearchIndex } from '@digigov/text-search/search/search-index';\n\nexport default SearchIndex;\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAA4B;AAE5B,IAAO,iBAAQ;",
6
6
  "names": []
7
7
  }
@@ -21,15 +21,18 @@ __export(encoder_exports, {
21
21
  encodeGreek: () => encodeGreek
22
22
  });
23
23
  module.exports = __toCommonJS(encoder_exports);
24
- var import_normalization_map = require("./normalization-map");
25
- const whitespaceRegex = /[\p{Z}\p{S}\p{P}\p{C}]+/u;
26
- const diacriticsRegex = /[\u0300-\u036f]/g;
24
+ var import_normalization_map = require("@digigov/text-search/search/lang/gr/normalization-map");
25
+ const whitespaceRegex = new RegExp("[p{Z}p{S}p{P}p{C}]+", "u");
26
+ const diacriticsRegex = new RegExp("[\u0300-\u036F]", "g");
27
27
  const greekCharsRegex = new RegExp(
28
28
  Object.keys(import_normalization_map.greekToGreeklishMap).join("|"),
29
29
  "igu"
30
30
  );
31
31
  function encodeGreek(str) {
32
- return ("" + str).toLowerCase().normalize("NFD").replace(diacriticsRegex, "").replace(greekCharsRegex, (match) => import_normalization_map.greekToGreeklishMap[match]).split(whitespaceRegex);
32
+ return ("" + str).toLowerCase().normalize("NFD").replace(diacriticsRegex, "").replace(
33
+ greekCharsRegex,
34
+ (match) => match in import_normalization_map.greekToGreeklishMap ? import_normalization_map.greekToGreeklishMap[match] : match
35
+ ).split(whitespaceRegex);
33
36
  }
34
37
  // Annotate the CommonJS export names for ESM import in node:
35
38
  0 && (module.exports = {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/search/lang/gr/encoder.ts"],
4
- "sourcesContent": ["import { greekToGreeklishMap } from './normalization-map';\n\nconst whitespaceRegex = /[\\p{Z}\\p{S}\\p{P}\\p{C}]+/u;\nconst diacriticsRegex = /[\\u0300-\\u036f]/g;\nconst greekCharsRegex = new RegExp(\n Object.keys(greekToGreeklishMap).join('|'),\n 'igu'\n);\n\n/**\n * Encode a string containing greek characters to greeklish\n *\n * This function is used to encode and tokenize a string containing greek characters.\n * It replaces greek characters with their latin counterparts, while also removing\n * any diacritics.\n *\n * @param str - The string to encode\n * @returns An array of encoded words\n */\nexport function encodeGreek(str: string) {\n return ('' + str)\n .toLowerCase()\n .normalize('NFD')\n .replace(diacriticsRegex, '')\n .replace(greekCharsRegex, (match) => (greekToGreeklishMap as any)[match])\n .split(whitespaceRegex);\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+BAAoC;AAEpC,MAAM,kBAAkB;AACxB,MAAM,kBAAkB;AACxB,MAAM,kBAAkB,IAAI;AAAA,EAC1B,OAAO,KAAK,4CAAmB,EAAE,KAAK,GAAG;AAAA,EACzC;AACF;AAYO,SAAS,YAAY,KAAa;AACvC,UAAQ,KAAK,KACV,YAAY,EACZ,UAAU,KAAK,EACf,QAAQ,iBAAiB,EAAE,EAC3B,QAAQ,iBAAiB,CAAC,UAAW,6CAA4B,KAAK,CAAC,EACvE,MAAM,eAAe;AAC1B;",
4
+ "sourcesContent": ["import { greekToGreeklishMap } from '@digigov/text-search/search/lang/gr/normalization-map';\n\nconst whitespaceRegex = new RegExp('[p{Z}p{S}p{P}p{C}]+', 'u');\nconst diacriticsRegex = new RegExp('[\\u0300-\\u036f]', 'g');\nconst greekCharsRegex = new RegExp(\n Object.keys(greekToGreeklishMap).join('|'),\n 'igu'\n);\n\n/**\n * Encode a string containing greek characters to greeklish\n *\n * This function is used to encode and tokenize a string containing greek characters.\n * It replaces greek characters with their latin counterparts, while also removing\n * any diacritics.\n *\n * @param str - The string to encode\n * @returns An array of encoded words\n */\nexport function encodeGreek(str: string) {\n return ('' + str)\n .toLowerCase()\n .normalize('NFD')\n .replace(diacriticsRegex, '')\n .replace(greekCharsRegex, (match) =>\n match in greekToGreeklishMap\n ? greekToGreeklishMap[match as keyof typeof greekToGreeklishMap]\n : match\n )\n .split(whitespaceRegex);\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+BAAoC;AAEpC,MAAM,kBAAkB,IAAI,OAAO,uBAAuB,GAAG;AAC7D,MAAM,kBAAkB,IAAI,OAAO,mBAAmB,GAAG;AACzD,MAAM,kBAAkB,IAAI;AAAA,EAC1B,OAAO,KAAK,4CAAmB,EAAE,KAAK,GAAG;AAAA,EACzC;AACF;AAYO,SAAS,YAAY,KAAa;AACvC,UAAQ,KAAK,KACV,YAAY,EACZ,UAAU,KAAK,EACf,QAAQ,iBAAiB,EAAE,EAC3B;AAAA,IAAQ;AAAA,IAAiB,CAAC,UACzB,SAAS,+CACL,6CAAoB,KAAyC,IAC7D;AAAA,EACN,EACC,MAAM,eAAe;AAC1B;",
6
6
  "names": []
7
7
  }
@@ -22,8 +22,8 @@ __export(search_index_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(search_index_exports);
24
24
  var import_flexsearch = require("flexsearch");
25
- var import_encoder = require("./lang/gr/encoder");
26
- var import_utils = require("./utils");
25
+ var import_encoder = require("@digigov/text-search/search/lang/gr/encoder");
26
+ var import_utils = require("@digigov/text-search/search/utils");
27
27
  class SearchIndex {
28
28
  constructor(items, options) {
29
29
  this.idKey = "id";
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/search/search-index.ts"],
4
- "sourcesContent": ["import { Document } from 'flexsearch';\nimport type { SearchIndexOptions } from '../types';\nimport { encodeGreek } from './lang/gr/encoder';\nimport { findItemsByIds, getAllItemKeys, getResultIds } from './utils';\n\n/**\n * Wrapper class around third party index and search library\n *\n * @typeParam T - The type of the data that will be indexed\n */\nexport class SearchIndex<T extends Record<string, any>> {\n /**\n * Instance of the third party library's index\n */\n private index: Document<T>;\n private idKey: string;\n\n constructor(items: T[], options?: SearchIndexOptions<T>) {\n this.idKey = 'id';\n if (options && options.idKey) {\n this.idKey = options.idKey.replace('.', ':');\n } else if (!(items[0] && 'id' in items[0])) {\n items = items.map((item, index) => ({ ...item, id: index }));\n }\n\n let fields: string[] = [];\n if (options && options.fields) {\n fields = options.fields;\n } else if (items[0]) {\n fields = getAllItemKeys(items[0]);\n }\n fields = fields\n .filter((field) => field !== this.idKey)\n .map((field) => field.replace('.', ':'));\n\n this.index = new Document<T>({\n document: {\n id: this.idKey,\n index: fields,\n },\n tokenize: 'forward',\n worker: options?.enableWorker,\n encode: encodeGreek,\n });\n\n this.addAll(items);\n }\n\n /**\n * Add an item to the index\n *\n * @param item - The item to add to the index\n */\n public add(item: T) {\n this.index.add(item);\n return this;\n }\n\n /**\n * Add multiple items to the index\n *\n * @param items - The list of items to add to the index\n */\n public addAll(items: T[]) {\n items.forEach((item) => this.index.add(item));\n return this;\n }\n\n /**\n * Search the index for the given term\n *\n * @param documents - The list of documents to search\n * @param searchTerm - The term to search for\n * @returns The list of items that match the search term\n */\n public search(documents: T[], searchTerm: string) {\n const res = this.index.search(searchTerm);\n const ids = getResultIds(res);\n return findItemsByIds(\n documents,\n ids,\n this.idKey as Extract<keyof T, string>\n );\n }\n\n /**\n * Asynchronously search the index for the given term\n *\n * @param documents - The list of documents to search\n * @param searchTerm - The term to search for\n * @returns The list of items that match the search term\n */\n public async searchAsync(documents: T[], searchTerm: string) {\n return this.index\n .searchAsync(searchTerm)\n .then((res) => {\n return getResultIds(res);\n })\n .then((res) =>\n findItemsByIds(documents, res, this.idKey as Extract<keyof T, string>)\n );\n }\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAAyB;AAEzB,qBAA4B;AAC5B,mBAA6D;AAOtD,MAAM,YAA2C;AAAA,EAOtD,YAAY,OAAY,SAAiC;AACvD,SAAK,QAAQ;AACb,QAAI,WAAW,QAAQ,OAAO;AAC5B,WAAK,QAAQ,QAAQ,MAAM,QAAQ,KAAK,GAAG;AAAA,IAC7C,WAAW,EAAE,MAAM,CAAC,KAAK,QAAQ,MAAM,CAAC,IAAI;AAC1C,cAAQ,MAAM,IAAI,CAAC,MAAM,WAAW,EAAE,GAAG,MAAM,IAAI,MAAM,EAAE;AAAA,IAC7D;AAEA,QAAI,SAAmB,CAAC;AACxB,QAAI,WAAW,QAAQ,QAAQ;AAC7B,eAAS,QAAQ;AAAA,IACnB,WAAW,MAAM,CAAC,GAAG;AACnB,mBAAS,6BAAe,MAAM,CAAC,CAAC;AAAA,IAClC;AACA,aAAS,OACN,OAAO,CAAC,UAAU,UAAU,KAAK,KAAK,EACtC,IAAI,CAAC,UAAU,MAAM,QAAQ,KAAK,GAAG,CAAC;AAEzC,SAAK,QAAQ,IAAI,2BAAY;AAAA,MAC3B,UAAU;AAAA,QACR,IAAI,KAAK;AAAA,QACT,OAAO;AAAA,MACT;AAAA,MACA,UAAU;AAAA,MACV,QAAQ,SAAS;AAAA,MACjB,QAAQ;AAAA,IACV,CAAC;AAED,SAAK,OAAO,KAAK;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,IAAI,MAAS;AAClB,SAAK,MAAM,IAAI,IAAI;AACnB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,OAAO,OAAY;AACxB,UAAM,QAAQ,CAAC,SAAS,KAAK,MAAM,IAAI,IAAI,CAAC;AAC5C,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,OAAO,WAAgB,YAAoB;AAChD,UAAM,MAAM,KAAK,MAAM,OAAO,UAAU;AACxC,UAAM,UAAM,2BAAa,GAAG;AAC5B,eAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,KAAK;AAAA,IACP;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAa,YAAY,WAAgB,YAAoB;AAC3D,WAAO,KAAK,MACT,YAAY,UAAU,EACtB,KAAK,CAAC,QAAQ;AACb,iBAAO,2BAAa,GAAG;AAAA,IACzB,CAAC,EACA;AAAA,MAAK,CAAC,YACL,6BAAe,WAAW,KAAK,KAAK,KAAiC;AAAA,IACvE;AAAA,EACJ;AACF;",
4
+ "sourcesContent": ["import { Document } from 'flexsearch';\nimport { encodeGreek } from '@digigov/text-search/search/lang/gr/encoder';\nimport {\n findItemsByIds,\n getAllItemKeys,\n getResultIds,\n} from '@digigov/text-search/search/utils';\nimport type { SearchIndexOptions } from '@digigov/text-search/types';\n\n/**\n * Wrapper class around third party index and search library\n *\n * @typeParam T - The type of the data that will be indexed\n */\nexport class SearchIndex<T extends Record<string, any>> {\n /**\n * Instance of the third party library's index\n */\n private index: Document<T>;\n private idKey: string;\n\n constructor(items: T[], options?: SearchIndexOptions<T>) {\n this.idKey = 'id';\n if (options && options.idKey) {\n this.idKey = options.idKey.replace('.', ':');\n } else if (!(items[0] && 'id' in items[0])) {\n items = items.map((item, index) => ({ ...item, id: index }));\n }\n\n let fields: string[] = [];\n if (options && options.fields) {\n fields = options.fields;\n } else if (items[0]) {\n fields = getAllItemKeys(items[0]);\n }\n fields = fields\n .filter((field) => field !== this.idKey)\n .map((field) => field.replace('.', ':'));\n\n this.index = new Document<T>({\n document: {\n id: this.idKey,\n index: fields,\n },\n tokenize: 'forward',\n worker: options?.enableWorker,\n encode: encodeGreek,\n });\n\n this.addAll(items);\n }\n\n /**\n * Add an item to the index\n *\n * @param item - The item to add to the index\n */\n public add(item: T) {\n this.index.add(item);\n return this;\n }\n\n /**\n * Add multiple items to the index\n *\n * @param items - The list of items to add to the index\n */\n public addAll(items: T[]) {\n items.forEach((item) => this.index.add(item));\n return this;\n }\n\n /**\n * Search the index for the given term\n *\n * @param documents - The list of documents to search\n * @param searchTerm - The term to search for\n * @returns The list of items that match the search term\n */\n public search(documents: T[], searchTerm: string) {\n const res = this.index.search(searchTerm);\n const ids = getResultIds(res);\n return findItemsByIds(\n documents,\n ids,\n this.idKey as Extract<keyof T, string>\n );\n }\n\n /**\n * Asynchronously search the index for the given term\n *\n * @param documents - The list of documents to search\n * @param searchTerm - The term to search for\n * @returns The list of items that match the search term\n */\n public async searchAsync(documents: T[], searchTerm: string) {\n return this.index\n .searchAsync(searchTerm)\n .then((res) => {\n return getResultIds(res);\n })\n .then((res) =>\n findItemsByIds(documents, res, this.idKey as Extract<keyof T, string>)\n );\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAAyB;AACzB,qBAA4B;AAC5B,mBAIO;AAQA,MAAM,YAA2C;AAAA,EAOtD,YAAY,OAAY,SAAiC;AACvD,SAAK,QAAQ;AACb,QAAI,WAAW,QAAQ,OAAO;AAC5B,WAAK,QAAQ,QAAQ,MAAM,QAAQ,KAAK,GAAG;AAAA,IAC7C,WAAW,EAAE,MAAM,CAAC,KAAK,QAAQ,MAAM,CAAC,IAAI;AAC1C,cAAQ,MAAM,IAAI,CAAC,MAAM,WAAW,EAAE,GAAG,MAAM,IAAI,MAAM,EAAE;AAAA,IAC7D;AAEA,QAAI,SAAmB,CAAC;AACxB,QAAI,WAAW,QAAQ,QAAQ;AAC7B,eAAS,QAAQ;AAAA,IACnB,WAAW,MAAM,CAAC,GAAG;AACnB,mBAAS,6BAAe,MAAM,CAAC,CAAC;AAAA,IAClC;AACA,aAAS,OACN,OAAO,CAAC,UAAU,UAAU,KAAK,KAAK,EACtC,IAAI,CAAC,UAAU,MAAM,QAAQ,KAAK,GAAG,CAAC;AAEzC,SAAK,QAAQ,IAAI,2BAAY;AAAA,MAC3B,UAAU;AAAA,QACR,IAAI,KAAK;AAAA,QACT,OAAO;AAAA,MACT;AAAA,MACA,UAAU;AAAA,MACV,QAAQ,SAAS;AAAA,MACjB,QAAQ;AAAA,IACV,CAAC;AAED,SAAK,OAAO,KAAK;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,IAAI,MAAS;AAClB,SAAK,MAAM,IAAI,IAAI;AACnB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,OAAO,OAAY;AACxB,UAAM,QAAQ,CAAC,SAAS,KAAK,MAAM,IAAI,IAAI,CAAC;AAC5C,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,OAAO,WAAgB,YAAoB;AAChD,UAAM,MAAM,KAAK,MAAM,OAAO,UAAU;AACxC,UAAM,UAAM,2BAAa,GAAG;AAC5B,eAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,KAAK;AAAA,IACP;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAa,YAAY,WAAgB,YAAoB;AAC3D,WAAO,KAAK,MACT,YAAY,UAAU,EACtB,KAAK,CAAC,QAAQ;AACb,iBAAO,2BAAa,GAAG;AAAA,IACzB,CAAC,EACA;AAAA,MAAK,CAAC,YACL,6BAAe,WAAW,KAAK,KAAK,KAAiC;AAAA,IACvE;AAAA,EACJ;AACF;",
6
6
  "names": []
7
7
  }
@@ -39,7 +39,7 @@ function getValueFromNestedKey(object, nestedKey) {
39
39
  const keys = nestedKey.split(":");
40
40
  let result = object;
41
41
  for (const keySegment of keys) {
42
- if (result.hasOwnProperty(keySegment)) {
42
+ if (Object.prototype.hasOwnProperty.call(result, keySegment)) {
43
43
  result = result[keySegment];
44
44
  }
45
45
  }
@@ -48,7 +48,7 @@ function getValueFromNestedKey(object, nestedKey) {
48
48
  function getAllItemKeys(object, parentKey = "") {
49
49
  let keys = [];
50
50
  for (const key in object) {
51
- if (object.hasOwnProperty(key)) {
51
+ if (Object.prototype.hasOwnProperty.call(object, key)) {
52
52
  const currentKey = parentKey ? `${parentKey}.${key}` : key;
53
53
  if (typeof object[key] === "object" && object[key] !== null) {
54
54
  keys = keys.concat(getAllItemKeys(object[key], currentKey));
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/search/utils.ts"],
4
- "sourcesContent": ["import { SimpleDocumentSearchResultSetUnit } from 'flexsearch';\n\n/**\n * Extracts the unique item IDs from the result set\n *\n * @param result - The result set to extract the IDs from\n */\nexport function getResultIds(result: SimpleDocumentSearchResultSetUnit[]) {\n const set = new Set<number | string>();\n result.forEach((item) => {\n item.result.forEach((id) => set.add(id));\n });\n return Array.from(set);\n}\n\n/**\n * Get the items from the list that match the given IDs\n *\n * @param items - The list of items to search through\n * @param ids - The list of IDs to search for\n * @param idKey - The key to use to find the IDs in the items\n */\nexport function findItemsByIds<T extends Record<string, any>>(\n items: T[],\n ids: (string | number)[],\n idKey: Extract<keyof T, string>\n) {\n return items.filter(\n (item) => item && ids.includes(getValueFromNestedKey(item, idKey))\n );\n}\n\nfunction getValueFromNestedKey(object: Record<string, any>, nestedKey: string) {\n const keys = nestedKey.split(':');\n\n let result = object;\n for (const keySegment of keys) {\n if (result.hasOwnProperty(keySegment)) {\n result = result[keySegment];\n }\n }\n return (result as unknown) as string;\n}\n\n/**\n * Recursively get all the keys from an object\n *\n * The keys are returned in the format `parentKey.childKey` for nested objects\n * and `key` for top level objects (objects that are not nested inside another object).\n *\n * @param object - The item to get the keys from\n * @param parentKey - The parent key to which the current key should be appended\n */\nexport function getAllItemKeys(\n object: Record<string, any>,\n parentKey: string = ''\n): string[] {\n let keys: string[] = [];\n for (const key in object) {\n if (object.hasOwnProperty(key)) {\n const currentKey = parentKey ? `${parentKey}.${key}` : key;\n\n if (typeof object[key] === 'object' && object[key] !== null) {\n keys = keys.concat(getAllItemKeys(object[key], currentKey));\n } else {\n keys.push(currentKey);\n }\n }\n }\n\n return keys;\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOO,SAAS,aAAa,QAA6C;AACxE,QAAM,MAAM,oBAAI,IAAqB;AACrC,SAAO,QAAQ,CAAC,SAAS;AACvB,SAAK,OAAO,QAAQ,CAAC,OAAO,IAAI,IAAI,EAAE,CAAC;AAAA,EACzC,CAAC;AACD,SAAO,MAAM,KAAK,GAAG;AACvB;AASO,SAAS,eACd,OACA,KACA,OACA;AACA,SAAO,MAAM;AAAA,IACX,CAAC,SAAS,QAAQ,IAAI,SAAS,sBAAsB,MAAM,KAAK,CAAC;AAAA,EACnE;AACF;AAEA,SAAS,sBAAsB,QAA6B,WAAmB;AAC7E,QAAM,OAAO,UAAU,MAAM,GAAG;AAEhC,MAAI,SAAS;AACb,aAAW,cAAc,MAAM;AAC7B,QAAI,OAAO,eAAe,UAAU,GAAG;AACrC,eAAS,OAAO,UAAU;AAAA,IAC5B;AAAA,EACF;AACA,SAAQ;AACV;AAWO,SAAS,eACd,QACA,YAAoB,IACV;AACV,MAAI,OAAiB,CAAC;AACtB,aAAW,OAAO,QAAQ;AACxB,QAAI,OAAO,eAAe,GAAG,GAAG;AAC9B,YAAM,aAAa,YAAY,GAAG,SAAS,IAAI,GAAG,KAAK;AAEvD,UAAI,OAAO,OAAO,GAAG,MAAM,YAAY,OAAO,GAAG,MAAM,MAAM;AAC3D,eAAO,KAAK,OAAO,eAAe,OAAO,GAAG,GAAG,UAAU,CAAC;AAAA,MAC5D,OAAO;AACL,aAAK,KAAK,UAAU;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;",
4
+ "sourcesContent": ["import { SimpleDocumentSearchResultSetUnit } from 'flexsearch';\n\n/**\n * Extracts the unique item IDs from the result set\n *\n * @param result - The result set to extract the IDs from\n */\nexport function getResultIds(result: SimpleDocumentSearchResultSetUnit[]) {\n const set = new Set<number | string>();\n result.forEach((item) => {\n item.result.forEach((id) => set.add(id));\n });\n return Array.from(set);\n}\n\n/**\n * Get the items from the list that match the given IDs\n *\n * @param items - The list of items to search through\n * @param ids - The list of IDs to search for\n * @param idKey - The key to use to find the IDs in the items\n */\nexport function findItemsByIds<T extends Record<string, any>>(\n items: T[],\n ids: (string | number)[],\n idKey: Extract<keyof T, string>\n) {\n return items.filter(\n (item) => item && ids.includes(getValueFromNestedKey(item, idKey))\n );\n}\n\nfunction getValueFromNestedKey(object: Record<string, any>, nestedKey: string) {\n const keys = nestedKey.split(':');\n\n let result = object;\n for (const keySegment of keys) {\n if (Object.prototype.hasOwnProperty.call(result, keySegment)) {\n result = result[keySegment];\n }\n }\n return result as unknown as string;\n}\n\n/**\n * Recursively get all the keys from an object\n *\n * The keys are returned in the format `parentKey.childKey` for nested objects\n * and `key` for top level objects (objects that are not nested inside another object).\n *\n * @param object - The item to get the keys from\n * @param parentKey - The parent key to which the current key should be appended\n */\nexport function getAllItemKeys(\n object: Record<string, any>,\n parentKey = ''\n): string[] {\n let keys: string[] = [];\n for (const key in object) {\n if (Object.prototype.hasOwnProperty.call(object, key)) {\n const currentKey = parentKey ? `${parentKey}.${key}` : key;\n\n if (typeof object[key] === 'object' && object[key] !== null) {\n keys = keys.concat(getAllItemKeys(object[key], currentKey));\n } else {\n keys.push(currentKey);\n }\n }\n }\n\n return keys;\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOO,SAAS,aAAa,QAA6C;AACxE,QAAM,MAAM,oBAAI,IAAqB;AACrC,SAAO,QAAQ,CAAC,SAAS;AACvB,SAAK,OAAO,QAAQ,CAAC,OAAO,IAAI,IAAI,EAAE,CAAC;AAAA,EACzC,CAAC;AACD,SAAO,MAAM,KAAK,GAAG;AACvB;AASO,SAAS,eACd,OACA,KACA,OACA;AACA,SAAO,MAAM;AAAA,IACX,CAAC,SAAS,QAAQ,IAAI,SAAS,sBAAsB,MAAM,KAAK,CAAC;AAAA,EACnE;AACF;AAEA,SAAS,sBAAsB,QAA6B,WAAmB;AAC7E,QAAM,OAAO,UAAU,MAAM,GAAG;AAEhC,MAAI,SAAS;AACb,aAAW,cAAc,MAAM;AAC7B,QAAI,OAAO,UAAU,eAAe,KAAK,QAAQ,UAAU,GAAG;AAC5D,eAAS,OAAO,UAAU;AAAA,IAC5B;AAAA,EACF;AACA,SAAO;AACT;AAWO,SAAS,eACd,QACA,YAAY,IACF;AACV,MAAI,OAAiB,CAAC;AACtB,aAAW,OAAO,QAAQ;AACxB,QAAI,OAAO,UAAU,eAAe,KAAK,QAAQ,GAAG,GAAG;AACrD,YAAM,aAAa,YAAY,GAAG,SAAS,IAAI,GAAG,KAAK;AAEvD,UAAI,OAAO,OAAO,GAAG,MAAM,YAAY,OAAO,GAAG,MAAM,MAAM;AAC3D,eAAO,KAAK,OAAO,eAAe,OAAO,GAAG,GAAG,UAAU,CAAC;AAAA,MAC5D,OAAO;AACL,aAAK,KAAK,UAAU;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;",
6
6
  "names": []
7
7
  }
package/cjs/types.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/types.ts"],
4
- "sourcesContent": ["/**\n * Options for configuring the useSearch hook\n */\nexport interface UseSearchOptions<T extends Record<string, any>> {\n indexing: SearchIndexOptions<T>;\n}\n\n/**\n * Options for configuring the search index\n *\n * @typeParam T - The type of the data that will be indexed\n */\nexport interface SearchIndexOptions<T> {\n /**\n * Describes where to find the unique ID for each item in the data\n *\n * This can also be a nested key, e.g. `address.street`. If not specified, the search index will\n * create an 'id' field on each item, with the value being the index of the item in the array.\n */\n idKey?: NestedKeyOf<T>;\n /**\n * List of fields to index\n *\n * Contains a list of fields from the document, that should be indexed. The fields can be nested.\n *\n * @example Using nested keys\n * ```\n * {\n * id: 1,\n * name: 'John',\n * address: {\n * street: '123 Main St',\n * city: 'New York'\n * }\n * }\n * ```\n * To search against the `street` key, add `address.street` to the fields array.\n */\n fields?: NestedKeyOf<T>[];\n /**\n * Whether to use a web worker for indexing\n */\n enableWorker?: boolean;\n}\n\n/**\n * Any key of an object that has nested objects.\n *\n * This utility type is used to get all the primitive keys of an object, including the keys of any nested objects.\n *\n * @typeParam ObjectType - The type of the object to get the keys of\n */\nexport type NestedKeyOf<T> = T extends Primitive\n ? never\n :\n | (keyof T & string)\n | { [P in keyof T & string]: DeepSubKeys<T, P> }[keyof T & string];\n\ntype DeepSubKeys<T, P extends keyof T & string> = T[P] extends (infer Inner)[]\n ? `${P}.${NestedKeyOf<Inner>}`\n : T[P] extends object\n ? `${P}.${NestedKeyOf<T[P]>}`\n : never;\n\ntype Primitive = null | undefined | string | number | boolean | symbol | bigint;\n"],
4
+ "sourcesContent": ["/**\n * Options for configuring the useSearch hook\n */\nexport interface UseSearchOptions<T extends Record<string, any>> {\n indexing: SearchIndexOptions<T>;\n}\n\n/**\n * Options for configuring the search index\n *\n * @typeParam T - The type of the data that will be indexed\n */\nexport interface SearchIndexOptions<T> {\n /**\n * Describes where to find the unique ID for each item in the data\n *\n * This can also be a nested key, e.g. `address.street`. If not specified, the search index will\n * create an 'id' field on each item, with the value being the index of the item in the array.\n */\n idKey?: NestedKeyOf<T>;\n /**\n * List of fields to index\n *\n * Contains a list of fields from the document, that should be indexed. The fields can be nested.\n *\n * @example Using nested keys\n * ```\n * {\n * id: 1,\n * name: 'John',\n * address: {\n * street: '123 Main St',\n * city: 'New York'\n * }\n * }\n * ```\n * To search against the `street` key, add `address.street` to the fields array.\n */\n fields?: NestedKeyOf<T>[];\n /**\n * Whether to use a web worker for indexing\n */\n enableWorker?: boolean;\n}\n\n/**\n * Any key of an object that has nested objects.\n *\n * This utility type is used to get all the primitive keys of an object, including the keys of any nested objects.\n *\n * @typeParam ObjectType - The type of the object to get the keys of\n */\nexport type NestedKeyOf<T> = T extends Primitive\n ? never\n :\n | (keyof T & string)\n | { [P in keyof T & string]: DeepSubKeys<T, P> }[keyof T & string];\n\ntype DeepSubKeys<T, P extends keyof T & string> = T[P] extends (infer Inner)[]\n ? `${P}.${NestedKeyOf<Inner>}`\n : T[P] extends object\n ? `${P}.${NestedKeyOf<T[P]>}`\n : never;\n\ntype Primitive = null | undefined | string | number | boolean | symbol | bigint;\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
package/hook/index.js CHANGED
@@ -1,17 +1,17 @@
1
1
  import { useCallback, useMemo, useState } from "react";
2
- import SearchIndex from "./search";
2
+ import SearchIndex from "@digigov/text-search/search";
3
3
  function useSearch(documents, query, options) {
4
4
  const [loading, setLoading] = useState(false);
5
5
  const [data, setData] = useState(documents);
6
6
  const indexing = options?.indexing;
7
- const index = useMemo(() => new SearchIndex(documents, indexing), [
8
- documents,
9
- indexing
10
- ]);
7
+ const index = useMemo(
8
+ () => new SearchIndex(documents, indexing),
9
+ [documents, indexing]
10
+ );
11
11
  const search = useCallback(() => {
12
12
  if (query) {
13
13
  setLoading(true);
14
- index.searchAsync(documents, query).then((data2) => setData(data2)).finally(() => setLoading(false));
14
+ index.searchAsync(documents, query).then((data2) => setData(data2)).catch(() => setData([])).finally(() => setLoading(false));
15
15
  } else {
16
16
  setData(documents);
17
17
  }
package/hook.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { UseSearchOptions } from './types';
1
+ import { UseSearchOptions } from '@digigov/text-search/types';
2
2
  /**
3
3
  * Hook for searching through a list of documents
4
4
  *
package/hook.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/hook.ts"],
4
- "sourcesContent": ["import { useCallback, useMemo, useState } from 'react';\nimport SearchIndex from './search';\nimport { UseSearchOptions } from './types';\n\n/**\n * Hook for searching through a list of documents\n *\n * Returns a list of documents that match the search query.\n * If no query is provided, it returns the original list of documents.\n *\n * @param documents - The list of documents to search through\n * @param options - Options for configuring the search index\n * @param query - The search query\n *\n * @typeParam T - The type of the data in the documents list\n */\nexport default function useSearch<T extends Record<string, any>>(\n documents: T[],\n query?: string,\n options?: UseSearchOptions<T>\n) {\n const [loading, setLoading] = useState(false);\n const [data, setData] = useState(documents);\n\n const indexing = options?.indexing;\n\n const index = useMemo(() => new SearchIndex(documents, indexing), [\n documents,\n indexing,\n ]);\n\n const search = useCallback(() => {\n if (query) {\n setLoading(true);\n index\n .searchAsync(documents, query)\n .then((data) => setData(data))\n .finally(() => setLoading(false));\n } else {\n setData(documents);\n }\n }, [query, index, documents]);\n\n const reset = useCallback(() => {\n setData(documents);\n setLoading(false);\n }, [documents]);\n\n return { data, loading, search, reset };\n}\n"],
5
- "mappings": "AAAA,SAAS,aAAa,SAAS,gBAAgB;AAC/C,OAAO,iBAAiB;AAeT,SAAR,UACL,WACA,OACA,SACA;AACA,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAC5C,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,SAAS;AAE1C,QAAM,WAAW,SAAS;AAE1B,QAAM,QAAQ,QAAQ,MAAM,IAAI,YAAY,WAAW,QAAQ,GAAG;AAAA,IAChE;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,SAAS,YAAY,MAAM;AAC/B,QAAI,OAAO;AACT,iBAAW,IAAI;AACf,YACG,YAAY,WAAW,KAAK,EAC5B,KAAK,CAACA,UAAS,QAAQA,KAAI,CAAC,EAC5B,QAAQ,MAAM,WAAW,KAAK,CAAC;AAAA,IACpC,OAAO;AACL,cAAQ,SAAS;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,OAAO,OAAO,SAAS,CAAC;AAE5B,QAAM,QAAQ,YAAY,MAAM;AAC9B,YAAQ,SAAS;AACjB,eAAW,KAAK;AAAA,EAClB,GAAG,CAAC,SAAS,CAAC;AAEd,SAAO,EAAE,MAAM,SAAS,QAAQ,MAAM;AACxC;",
4
+ "sourcesContent": ["import { useCallback, useMemo, useState } from 'react';\nimport SearchIndex from '@digigov/text-search/search';\nimport { UseSearchOptions } from '@digigov/text-search/types';\n\n/**\n * Hook for searching through a list of documents\n *\n * Returns a list of documents that match the search query.\n * If no query is provided, it returns the original list of documents.\n *\n * @param documents - The list of documents to search through\n * @param options - Options for configuring the search index\n * @param query - The search query\n *\n * @typeParam T - The type of the data in the documents list\n */\nexport default function useSearch<T extends Record<string, any>>(\n documents: T[],\n query?: string,\n options?: UseSearchOptions<T>\n) {\n const [loading, setLoading] = useState(false);\n const [data, setData] = useState(documents);\n\n const indexing = options?.indexing;\n\n const index = useMemo(\n () => new SearchIndex(documents, indexing),\n [documents, indexing]\n );\n\n const search = useCallback(() => {\n if (query) {\n setLoading(true);\n index\n .searchAsync(documents, query)\n .then((data) => setData(data))\n .catch(() => setData([]))\n .finally(() => setLoading(false));\n } else {\n setData(documents);\n }\n }, [query, index, documents]);\n\n const reset = useCallback(() => {\n setData(documents);\n setLoading(false);\n }, [documents]);\n\n return { data, loading, search, reset };\n}\n"],
5
+ "mappings": "AAAA,SAAS,aAAa,SAAS,gBAAgB;AAC/C,OAAO,iBAAiB;AAeT,SAAR,UACL,WACA,OACA,SACA;AACA,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAC5C,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,SAAS;AAE1C,QAAM,WAAW,SAAS;AAE1B,QAAM,QAAQ;AAAA,IACZ,MAAM,IAAI,YAAY,WAAW,QAAQ;AAAA,IACzC,CAAC,WAAW,QAAQ;AAAA,EACtB;AAEA,QAAM,SAAS,YAAY,MAAM;AAC/B,QAAI,OAAO;AACT,iBAAW,IAAI;AACf,YACG,YAAY,WAAW,KAAK,EAC5B,KAAK,CAACA,UAAS,QAAQA,KAAI,CAAC,EAC5B,MAAM,MAAM,QAAQ,CAAC,CAAC,CAAC,EACvB,QAAQ,MAAM,WAAW,KAAK,CAAC;AAAA,IACpC,OAAO;AACL,cAAQ,SAAS;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,OAAO,OAAO,SAAS,CAAC;AAE5B,QAAM,QAAQ,YAAY,MAAM;AAC9B,YAAQ,SAAS;AACjB,eAAW,KAAK;AAAA,EAClB,GAAG,CAAC,SAAS,CAAC;AAEd,SAAO,EAAE,MAAM,SAAS,QAAQ,MAAM;AACxC;",
6
6
  "names": ["data"]
7
7
  }
package/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import useSearch from './hook';
1
+ import useSearch from '@digigov/text-search/hook';
2
2
  export default useSearch;
3
- export * from './search';
3
+ export * from '@digigov/text-search/search';
package/index.js CHANGED
@@ -1,11 +1,11 @@
1
- /** @license Digigov v1.2.0-85c27c19
1
+ /** @license Digigov v1.2.0-aefd0709
2
2
  *
3
3
  * This source code is licensed under the BSD-2-Clause license found in the
4
4
  * LICENSE file in the root directory of this source tree.
5
5
  */
6
- import useSearch from "./hook";
6
+ import useSearch from "@digigov/text-search/hook";
7
7
  var src_default = useSearch;
8
- export * from "./search";
8
+ export * from "@digigov/text-search/search";
9
9
  export {
10
10
  src_default as default
11
11
  };
package/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["import useSearch from './hook';\n\nexport default useSearch;\nexport * from './search';\n"],
4
+ "sourcesContent": ["import useSearch from '@digigov/text-search/hook';\n\nexport default useSearch;\nexport * from '@digigov/text-search/search';\n"],
5
5
  "mappings": "AAAA,OAAO,eAAe;AAEtB,IAAO,cAAQ;AACf,cAAc;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digigov/text-search",
3
- "version": "1.2.0-85c27c19",
3
+ "version": "1.2.0-aefd0709",
4
4
  "description": "@digigov text-search",
5
5
  "author": "GRNET Developers <devs@lists.grnet.gr>",
6
6
  "license": "BSD-2-Clause",
package/search/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { SearchIndex } from './search-index';
1
+ import { SearchIndex } from '@digigov/text-search/search/search-index';
2
2
  export default SearchIndex;
package/search/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { SearchIndex } from "./search-index";
1
+ import { SearchIndex } from "@digigov/text-search/search/search-index";
2
2
  var search_default = SearchIndex;
3
3
  export {
4
4
  search_default as default
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/search/index.ts"],
4
- "sourcesContent": ["import { SearchIndex } from './search-index';\n\nexport default SearchIndex;\n"],
4
+ "sourcesContent": ["import { SearchIndex } from '@digigov/text-search/search/search-index';\n\nexport default SearchIndex;\n"],
5
5
  "mappings": "AAAA,SAAS,mBAAmB;AAE5B,IAAO,iBAAQ;",
6
6
  "names": []
7
7
  }
@@ -1,12 +1,15 @@
1
- import { greekToGreeklishMap } from "./normalization-map";
2
- const whitespaceRegex = /[\p{Z}\p{S}\p{P}\p{C}]+/u;
3
- const diacriticsRegex = /[\u0300-\u036f]/g;
1
+ import { greekToGreeklishMap } from "@digigov/text-search/search/lang/gr/normalization-map";
2
+ const whitespaceRegex = new RegExp("[p{Z}p{S}p{P}p{C}]+", "u");
3
+ const diacriticsRegex = new RegExp("[\u0300-\u036F]", "g");
4
4
  const greekCharsRegex = new RegExp(
5
5
  Object.keys(greekToGreeklishMap).join("|"),
6
6
  "igu"
7
7
  );
8
8
  function encodeGreek(str) {
9
- return ("" + str).toLowerCase().normalize("NFD").replace(diacriticsRegex, "").replace(greekCharsRegex, (match) => greekToGreeklishMap[match]).split(whitespaceRegex);
9
+ return ("" + str).toLowerCase().normalize("NFD").replace(diacriticsRegex, "").replace(
10
+ greekCharsRegex,
11
+ (match) => match in greekToGreeklishMap ? greekToGreeklishMap[match] : match
12
+ ).split(whitespaceRegex);
10
13
  }
11
14
  export {
12
15
  encodeGreek
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/search/lang/gr/encoder.ts"],
4
- "sourcesContent": ["import { greekToGreeklishMap } from './normalization-map';\n\nconst whitespaceRegex = /[\\p{Z}\\p{S}\\p{P}\\p{C}]+/u;\nconst diacriticsRegex = /[\\u0300-\\u036f]/g;\nconst greekCharsRegex = new RegExp(\n Object.keys(greekToGreeklishMap).join('|'),\n 'igu'\n);\n\n/**\n * Encode a string containing greek characters to greeklish\n *\n * This function is used to encode and tokenize a string containing greek characters.\n * It replaces greek characters with their latin counterparts, while also removing\n * any diacritics.\n *\n * @param str - The string to encode\n * @returns An array of encoded words\n */\nexport function encodeGreek(str: string) {\n return ('' + str)\n .toLowerCase()\n .normalize('NFD')\n .replace(diacriticsRegex, '')\n .replace(greekCharsRegex, (match) => (greekToGreeklishMap as any)[match])\n .split(whitespaceRegex);\n}\n"],
5
- "mappings": "AAAA,SAAS,2BAA2B;AAEpC,MAAM,kBAAkB;AACxB,MAAM,kBAAkB;AACxB,MAAM,kBAAkB,IAAI;AAAA,EAC1B,OAAO,KAAK,mBAAmB,EAAE,KAAK,GAAG;AAAA,EACzC;AACF;AAYO,SAAS,YAAY,KAAa;AACvC,UAAQ,KAAK,KACV,YAAY,EACZ,UAAU,KAAK,EACf,QAAQ,iBAAiB,EAAE,EAC3B,QAAQ,iBAAiB,CAAC,UAAW,oBAA4B,KAAK,CAAC,EACvE,MAAM,eAAe;AAC1B;",
4
+ "sourcesContent": ["import { greekToGreeklishMap } from '@digigov/text-search/search/lang/gr/normalization-map';\n\nconst whitespaceRegex = new RegExp('[p{Z}p{S}p{P}p{C}]+', 'u');\nconst diacriticsRegex = new RegExp('[\\u0300-\\u036f]', 'g');\nconst greekCharsRegex = new RegExp(\n Object.keys(greekToGreeklishMap).join('|'),\n 'igu'\n);\n\n/**\n * Encode a string containing greek characters to greeklish\n *\n * This function is used to encode and tokenize a string containing greek characters.\n * It replaces greek characters with their latin counterparts, while also removing\n * any diacritics.\n *\n * @param str - The string to encode\n * @returns An array of encoded words\n */\nexport function encodeGreek(str: string) {\n return ('' + str)\n .toLowerCase()\n .normalize('NFD')\n .replace(diacriticsRegex, '')\n .replace(greekCharsRegex, (match) =>\n match in greekToGreeklishMap\n ? greekToGreeklishMap[match as keyof typeof greekToGreeklishMap]\n : match\n )\n .split(whitespaceRegex);\n}\n"],
5
+ "mappings": "AAAA,SAAS,2BAA2B;AAEpC,MAAM,kBAAkB,IAAI,OAAO,uBAAuB,GAAG;AAC7D,MAAM,kBAAkB,IAAI,OAAO,mBAAmB,GAAG;AACzD,MAAM,kBAAkB,IAAI;AAAA,EAC1B,OAAO,KAAK,mBAAmB,EAAE,KAAK,GAAG;AAAA,EACzC;AACF;AAYO,SAAS,YAAY,KAAa;AACvC,UAAQ,KAAK,KACV,YAAY,EACZ,UAAU,KAAK,EACf,QAAQ,iBAAiB,EAAE,EAC3B;AAAA,IAAQ;AAAA,IAAiB,CAAC,UACzB,SAAS,sBACL,oBAAoB,KAAyC,IAC7D;AAAA,EACN,EACC,MAAM,eAAe;AAC1B;",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,10 @@
1
1
  import { Document } from "flexsearch";
2
- import { encodeGreek } from "./lang/gr/encoder";
3
- import { findItemsByIds, getAllItemKeys, getResultIds } from "./utils";
2
+ import { encodeGreek } from "@digigov/text-search/search/lang/gr/encoder";
3
+ import {
4
+ findItemsByIds,
5
+ getAllItemKeys,
6
+ getResultIds
7
+ } from "@digigov/text-search/search/utils";
4
8
  class SearchIndex {
5
9
  constructor(items, options) {
6
10
  this.idKey = "id";
@@ -1,4 +1,4 @@
1
- import type { SearchIndexOptions } from '../types';
1
+ import type { SearchIndexOptions } from '@digigov/text-search/types';
2
2
  /**
3
3
  * Wrapper class around third party index and search library
4
4
  *
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/search/search-index.ts"],
4
- "sourcesContent": ["import { Document } from 'flexsearch';\nimport type { SearchIndexOptions } from '../types';\nimport { encodeGreek } from './lang/gr/encoder';\nimport { findItemsByIds, getAllItemKeys, getResultIds } from './utils';\n\n/**\n * Wrapper class around third party index and search library\n *\n * @typeParam T - The type of the data that will be indexed\n */\nexport class SearchIndex<T extends Record<string, any>> {\n /**\n * Instance of the third party library's index\n */\n private index: Document<T>;\n private idKey: string;\n\n constructor(items: T[], options?: SearchIndexOptions<T>) {\n this.idKey = 'id';\n if (options && options.idKey) {\n this.idKey = options.idKey.replace('.', ':');\n } else if (!(items[0] && 'id' in items[0])) {\n items = items.map((item, index) => ({ ...item, id: index }));\n }\n\n let fields: string[] = [];\n if (options && options.fields) {\n fields = options.fields;\n } else if (items[0]) {\n fields = getAllItemKeys(items[0]);\n }\n fields = fields\n .filter((field) => field !== this.idKey)\n .map((field) => field.replace('.', ':'));\n\n this.index = new Document<T>({\n document: {\n id: this.idKey,\n index: fields,\n },\n tokenize: 'forward',\n worker: options?.enableWorker,\n encode: encodeGreek,\n });\n\n this.addAll(items);\n }\n\n /**\n * Add an item to the index\n *\n * @param item - The item to add to the index\n */\n public add(item: T) {\n this.index.add(item);\n return this;\n }\n\n /**\n * Add multiple items to the index\n *\n * @param items - The list of items to add to the index\n */\n public addAll(items: T[]) {\n items.forEach((item) => this.index.add(item));\n return this;\n }\n\n /**\n * Search the index for the given term\n *\n * @param documents - The list of documents to search\n * @param searchTerm - The term to search for\n * @returns The list of items that match the search term\n */\n public search(documents: T[], searchTerm: string) {\n const res = this.index.search(searchTerm);\n const ids = getResultIds(res);\n return findItemsByIds(\n documents,\n ids,\n this.idKey as Extract<keyof T, string>\n );\n }\n\n /**\n * Asynchronously search the index for the given term\n *\n * @param documents - The list of documents to search\n * @param searchTerm - The term to search for\n * @returns The list of items that match the search term\n */\n public async searchAsync(documents: T[], searchTerm: string) {\n return this.index\n .searchAsync(searchTerm)\n .then((res) => {\n return getResultIds(res);\n })\n .then((res) =>\n findItemsByIds(documents, res, this.idKey as Extract<keyof T, string>)\n );\n }\n}\n"],
5
- "mappings": "AAAA,SAAS,gBAAgB;AAEzB,SAAS,mBAAmB;AAC5B,SAAS,gBAAgB,gBAAgB,oBAAoB;AAOtD,MAAM,YAA2C;AAAA,EAOtD,YAAY,OAAY,SAAiC;AACvD,SAAK,QAAQ;AACb,QAAI,WAAW,QAAQ,OAAO;AAC5B,WAAK,QAAQ,QAAQ,MAAM,QAAQ,KAAK,GAAG;AAAA,IAC7C,WAAW,EAAE,MAAM,CAAC,KAAK,QAAQ,MAAM,CAAC,IAAI;AAC1C,cAAQ,MAAM,IAAI,CAAC,MAAM,WAAW,EAAE,GAAG,MAAM,IAAI,MAAM,EAAE;AAAA,IAC7D;AAEA,QAAI,SAAmB,CAAC;AACxB,QAAI,WAAW,QAAQ,QAAQ;AAC7B,eAAS,QAAQ;AAAA,IACnB,WAAW,MAAM,CAAC,GAAG;AACnB,eAAS,eAAe,MAAM,CAAC,CAAC;AAAA,IAClC;AACA,aAAS,OACN,OAAO,CAAC,UAAU,UAAU,KAAK,KAAK,EACtC,IAAI,CAAC,UAAU,MAAM,QAAQ,KAAK,GAAG,CAAC;AAEzC,SAAK,QAAQ,IAAI,SAAY;AAAA,MAC3B,UAAU;AAAA,QACR,IAAI,KAAK;AAAA,QACT,OAAO;AAAA,MACT;AAAA,MACA,UAAU;AAAA,MACV,QAAQ,SAAS;AAAA,MACjB,QAAQ;AAAA,IACV,CAAC;AAED,SAAK,OAAO,KAAK;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,IAAI,MAAS;AAClB,SAAK,MAAM,IAAI,IAAI;AACnB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,OAAO,OAAY;AACxB,UAAM,QAAQ,CAAC,SAAS,KAAK,MAAM,IAAI,IAAI,CAAC;AAC5C,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,OAAO,WAAgB,YAAoB;AAChD,UAAM,MAAM,KAAK,MAAM,OAAO,UAAU;AACxC,UAAM,MAAM,aAAa,GAAG;AAC5B,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,KAAK;AAAA,IACP;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAa,YAAY,WAAgB,YAAoB;AAC3D,WAAO,KAAK,MACT,YAAY,UAAU,EACtB,KAAK,CAAC,QAAQ;AACb,aAAO,aAAa,GAAG;AAAA,IACzB,CAAC,EACA;AAAA,MAAK,CAAC,QACL,eAAe,WAAW,KAAK,KAAK,KAAiC;AAAA,IACvE;AAAA,EACJ;AACF;",
4
+ "sourcesContent": ["import { Document } from 'flexsearch';\nimport { encodeGreek } from '@digigov/text-search/search/lang/gr/encoder';\nimport {\n findItemsByIds,\n getAllItemKeys,\n getResultIds,\n} from '@digigov/text-search/search/utils';\nimport type { SearchIndexOptions } from '@digigov/text-search/types';\n\n/**\n * Wrapper class around third party index and search library\n *\n * @typeParam T - The type of the data that will be indexed\n */\nexport class SearchIndex<T extends Record<string, any>> {\n /**\n * Instance of the third party library's index\n */\n private index: Document<T>;\n private idKey: string;\n\n constructor(items: T[], options?: SearchIndexOptions<T>) {\n this.idKey = 'id';\n if (options && options.idKey) {\n this.idKey = options.idKey.replace('.', ':');\n } else if (!(items[0] && 'id' in items[0])) {\n items = items.map((item, index) => ({ ...item, id: index }));\n }\n\n let fields: string[] = [];\n if (options && options.fields) {\n fields = options.fields;\n } else if (items[0]) {\n fields = getAllItemKeys(items[0]);\n }\n fields = fields\n .filter((field) => field !== this.idKey)\n .map((field) => field.replace('.', ':'));\n\n this.index = new Document<T>({\n document: {\n id: this.idKey,\n index: fields,\n },\n tokenize: 'forward',\n worker: options?.enableWorker,\n encode: encodeGreek,\n });\n\n this.addAll(items);\n }\n\n /**\n * Add an item to the index\n *\n * @param item - The item to add to the index\n */\n public add(item: T) {\n this.index.add(item);\n return this;\n }\n\n /**\n * Add multiple items to the index\n *\n * @param items - The list of items to add to the index\n */\n public addAll(items: T[]) {\n items.forEach((item) => this.index.add(item));\n return this;\n }\n\n /**\n * Search the index for the given term\n *\n * @param documents - The list of documents to search\n * @param searchTerm - The term to search for\n * @returns The list of items that match the search term\n */\n public search(documents: T[], searchTerm: string) {\n const res = this.index.search(searchTerm);\n const ids = getResultIds(res);\n return findItemsByIds(\n documents,\n ids,\n this.idKey as Extract<keyof T, string>\n );\n }\n\n /**\n * Asynchronously search the index for the given term\n *\n * @param documents - The list of documents to search\n * @param searchTerm - The term to search for\n * @returns The list of items that match the search term\n */\n public async searchAsync(documents: T[], searchTerm: string) {\n return this.index\n .searchAsync(searchTerm)\n .then((res) => {\n return getResultIds(res);\n })\n .then((res) =>\n findItemsByIds(documents, res, this.idKey as Extract<keyof T, string>)\n );\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,gBAAgB;AACzB,SAAS,mBAAmB;AAC5B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAQA,MAAM,YAA2C;AAAA,EAOtD,YAAY,OAAY,SAAiC;AACvD,SAAK,QAAQ;AACb,QAAI,WAAW,QAAQ,OAAO;AAC5B,WAAK,QAAQ,QAAQ,MAAM,QAAQ,KAAK,GAAG;AAAA,IAC7C,WAAW,EAAE,MAAM,CAAC,KAAK,QAAQ,MAAM,CAAC,IAAI;AAC1C,cAAQ,MAAM,IAAI,CAAC,MAAM,WAAW,EAAE,GAAG,MAAM,IAAI,MAAM,EAAE;AAAA,IAC7D;AAEA,QAAI,SAAmB,CAAC;AACxB,QAAI,WAAW,QAAQ,QAAQ;AAC7B,eAAS,QAAQ;AAAA,IACnB,WAAW,MAAM,CAAC,GAAG;AACnB,eAAS,eAAe,MAAM,CAAC,CAAC;AAAA,IAClC;AACA,aAAS,OACN,OAAO,CAAC,UAAU,UAAU,KAAK,KAAK,EACtC,IAAI,CAAC,UAAU,MAAM,QAAQ,KAAK,GAAG,CAAC;AAEzC,SAAK,QAAQ,IAAI,SAAY;AAAA,MAC3B,UAAU;AAAA,QACR,IAAI,KAAK;AAAA,QACT,OAAO;AAAA,MACT;AAAA,MACA,UAAU;AAAA,MACV,QAAQ,SAAS;AAAA,MACjB,QAAQ;AAAA,IACV,CAAC;AAED,SAAK,OAAO,KAAK;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,IAAI,MAAS;AAClB,SAAK,MAAM,IAAI,IAAI;AACnB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,OAAO,OAAY;AACxB,UAAM,QAAQ,CAAC,SAAS,KAAK,MAAM,IAAI,IAAI,CAAC;AAC5C,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,OAAO,WAAgB,YAAoB;AAChD,UAAM,MAAM,KAAK,MAAM,OAAO,UAAU;AACxC,UAAM,MAAM,aAAa,GAAG;AAC5B,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,KAAK;AAAA,IACP;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAa,YAAY,WAAgB,YAAoB;AAC3D,WAAO,KAAK,MACT,YAAY,UAAU,EACtB,KAAK,CAAC,QAAQ;AACb,aAAO,aAAa,GAAG;AAAA,IACzB,CAAC,EACA;AAAA,MAAK,CAAC,QACL,eAAe,WAAW,KAAK,KAAK,KAAiC;AAAA,IACvE;AAAA,EACJ;AACF;",
6
6
  "names": []
7
7
  }
@@ -14,7 +14,7 @@ function getValueFromNestedKey(object, nestedKey) {
14
14
  const keys = nestedKey.split(":");
15
15
  let result = object;
16
16
  for (const keySegment of keys) {
17
- if (result.hasOwnProperty(keySegment)) {
17
+ if (Object.prototype.hasOwnProperty.call(result, keySegment)) {
18
18
  result = result[keySegment];
19
19
  }
20
20
  }
@@ -23,7 +23,7 @@ function getValueFromNestedKey(object, nestedKey) {
23
23
  function getAllItemKeys(object, parentKey = "") {
24
24
  let keys = [];
25
25
  for (const key in object) {
26
- if (object.hasOwnProperty(key)) {
26
+ if (Object.prototype.hasOwnProperty.call(object, key)) {
27
27
  const currentKey = parentKey ? `${parentKey}.${key}` : key;
28
28
  if (typeof object[key] === "object" && object[key] !== null) {
29
29
  keys = keys.concat(getAllItemKeys(object[key], currentKey));
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/search/utils.ts"],
4
- "sourcesContent": ["import { SimpleDocumentSearchResultSetUnit } from 'flexsearch';\n\n/**\n * Extracts the unique item IDs from the result set\n *\n * @param result - The result set to extract the IDs from\n */\nexport function getResultIds(result: SimpleDocumentSearchResultSetUnit[]) {\n const set = new Set<number | string>();\n result.forEach((item) => {\n item.result.forEach((id) => set.add(id));\n });\n return Array.from(set);\n}\n\n/**\n * Get the items from the list that match the given IDs\n *\n * @param items - The list of items to search through\n * @param ids - The list of IDs to search for\n * @param idKey - The key to use to find the IDs in the items\n */\nexport function findItemsByIds<T extends Record<string, any>>(\n items: T[],\n ids: (string | number)[],\n idKey: Extract<keyof T, string>\n) {\n return items.filter(\n (item) => item && ids.includes(getValueFromNestedKey(item, idKey))\n );\n}\n\nfunction getValueFromNestedKey(object: Record<string, any>, nestedKey: string) {\n const keys = nestedKey.split(':');\n\n let result = object;\n for (const keySegment of keys) {\n if (result.hasOwnProperty(keySegment)) {\n result = result[keySegment];\n }\n }\n return (result as unknown) as string;\n}\n\n/**\n * Recursively get all the keys from an object\n *\n * The keys are returned in the format `parentKey.childKey` for nested objects\n * and `key` for top level objects (objects that are not nested inside another object).\n *\n * @param object - The item to get the keys from\n * @param parentKey - The parent key to which the current key should be appended\n */\nexport function getAllItemKeys(\n object: Record<string, any>,\n parentKey: string = ''\n): string[] {\n let keys: string[] = [];\n for (const key in object) {\n if (object.hasOwnProperty(key)) {\n const currentKey = parentKey ? `${parentKey}.${key}` : key;\n\n if (typeof object[key] === 'object' && object[key] !== null) {\n keys = keys.concat(getAllItemKeys(object[key], currentKey));\n } else {\n keys.push(currentKey);\n }\n }\n }\n\n return keys;\n}\n"],
5
- "mappings": "AAOO,SAAS,aAAa,QAA6C;AACxE,QAAM,MAAM,oBAAI,IAAqB;AACrC,SAAO,QAAQ,CAAC,SAAS;AACvB,SAAK,OAAO,QAAQ,CAAC,OAAO,IAAI,IAAI,EAAE,CAAC;AAAA,EACzC,CAAC;AACD,SAAO,MAAM,KAAK,GAAG;AACvB;AASO,SAAS,eACd,OACA,KACA,OACA;AACA,SAAO,MAAM;AAAA,IACX,CAAC,SAAS,QAAQ,IAAI,SAAS,sBAAsB,MAAM,KAAK,CAAC;AAAA,EACnE;AACF;AAEA,SAAS,sBAAsB,QAA6B,WAAmB;AAC7E,QAAM,OAAO,UAAU,MAAM,GAAG;AAEhC,MAAI,SAAS;AACb,aAAW,cAAc,MAAM;AAC7B,QAAI,OAAO,eAAe,UAAU,GAAG;AACrC,eAAS,OAAO,UAAU;AAAA,IAC5B;AAAA,EACF;AACA,SAAQ;AACV;AAWO,SAAS,eACd,QACA,YAAoB,IACV;AACV,MAAI,OAAiB,CAAC;AACtB,aAAW,OAAO,QAAQ;AACxB,QAAI,OAAO,eAAe,GAAG,GAAG;AAC9B,YAAM,aAAa,YAAY,GAAG,SAAS,IAAI,GAAG,KAAK;AAEvD,UAAI,OAAO,OAAO,GAAG,MAAM,YAAY,OAAO,GAAG,MAAM,MAAM;AAC3D,eAAO,KAAK,OAAO,eAAe,OAAO,GAAG,GAAG,UAAU,CAAC;AAAA,MAC5D,OAAO;AACL,aAAK,KAAK,UAAU;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;",
4
+ "sourcesContent": ["import { SimpleDocumentSearchResultSetUnit } from 'flexsearch';\n\n/**\n * Extracts the unique item IDs from the result set\n *\n * @param result - The result set to extract the IDs from\n */\nexport function getResultIds(result: SimpleDocumentSearchResultSetUnit[]) {\n const set = new Set<number | string>();\n result.forEach((item) => {\n item.result.forEach((id) => set.add(id));\n });\n return Array.from(set);\n}\n\n/**\n * Get the items from the list that match the given IDs\n *\n * @param items - The list of items to search through\n * @param ids - The list of IDs to search for\n * @param idKey - The key to use to find the IDs in the items\n */\nexport function findItemsByIds<T extends Record<string, any>>(\n items: T[],\n ids: (string | number)[],\n idKey: Extract<keyof T, string>\n) {\n return items.filter(\n (item) => item && ids.includes(getValueFromNestedKey(item, idKey))\n );\n}\n\nfunction getValueFromNestedKey(object: Record<string, any>, nestedKey: string) {\n const keys = nestedKey.split(':');\n\n let result = object;\n for (const keySegment of keys) {\n if (Object.prototype.hasOwnProperty.call(result, keySegment)) {\n result = result[keySegment];\n }\n }\n return result as unknown as string;\n}\n\n/**\n * Recursively get all the keys from an object\n *\n * The keys are returned in the format `parentKey.childKey` for nested objects\n * and `key` for top level objects (objects that are not nested inside another object).\n *\n * @param object - The item to get the keys from\n * @param parentKey - The parent key to which the current key should be appended\n */\nexport function getAllItemKeys(\n object: Record<string, any>,\n parentKey = ''\n): string[] {\n let keys: string[] = [];\n for (const key in object) {\n if (Object.prototype.hasOwnProperty.call(object, key)) {\n const currentKey = parentKey ? `${parentKey}.${key}` : key;\n\n if (typeof object[key] === 'object' && object[key] !== null) {\n keys = keys.concat(getAllItemKeys(object[key], currentKey));\n } else {\n keys.push(currentKey);\n }\n }\n }\n\n return keys;\n}\n"],
5
+ "mappings": "AAOO,SAAS,aAAa,QAA6C;AACxE,QAAM,MAAM,oBAAI,IAAqB;AACrC,SAAO,QAAQ,CAAC,SAAS;AACvB,SAAK,OAAO,QAAQ,CAAC,OAAO,IAAI,IAAI,EAAE,CAAC;AAAA,EACzC,CAAC;AACD,SAAO,MAAM,KAAK,GAAG;AACvB;AASO,SAAS,eACd,OACA,KACA,OACA;AACA,SAAO,MAAM;AAAA,IACX,CAAC,SAAS,QAAQ,IAAI,SAAS,sBAAsB,MAAM,KAAK,CAAC;AAAA,EACnE;AACF;AAEA,SAAS,sBAAsB,QAA6B,WAAmB;AAC7E,QAAM,OAAO,UAAU,MAAM,GAAG;AAEhC,MAAI,SAAS;AACb,aAAW,cAAc,MAAM;AAC7B,QAAI,OAAO,UAAU,eAAe,KAAK,QAAQ,UAAU,GAAG;AAC5D,eAAS,OAAO,UAAU;AAAA,IAC5B;AAAA,EACF;AACA,SAAO;AACT;AAWO,SAAS,eACd,QACA,YAAY,IACF;AACV,MAAI,OAAiB,CAAC;AACtB,aAAW,OAAO,QAAQ;AACxB,QAAI,OAAO,UAAU,eAAe,KAAK,QAAQ,GAAG,GAAG;AACrD,YAAM,aAAa,YAAY,GAAG,SAAS,IAAI,GAAG,KAAK;AAEvD,UAAI,OAAO,OAAO,GAAG,MAAM,YAAY,OAAO,GAAG,MAAM,MAAM;AAC3D,eAAO,KAAK,OAAO,eAAe,OAAO,GAAG,GAAG,UAAU,CAAC;AAAA,MAC5D,OAAO;AACL,aAAK,KAAK,UAAU;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;",
6
6
  "names": []
7
7
  }
package/src/hook.spec.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { act, renderHook } from '@testing-library/react-hooks';
2
- import useSearch from './hook';
3
- import documents from './test-utils/data.json';
1
+ import { act, renderHook, waitFor } from '@testing-library/react';
2
+ import useSearch from '@digigov/text-search/hook';
3
+ import documents from '@digigov/text-search/test-utils/data.json';
4
4
 
5
5
  describe('loading', () => {
6
6
  it('should start when searching', async () => {
@@ -10,33 +10,27 @@ describe('loading', () => {
10
10
  expect(result.current.loading).toBe(true);
11
11
  });
12
12
  it('should stop after search is completed', async () => {
13
- const { result, waitForNextUpdate } = renderHook(() =>
14
- useSearch(documents, 'Anastasia')
15
- );
13
+ const { result } = renderHook(() => useSearch(documents, 'Anastasia'));
16
14
  expect(result.current.loading).toBe(false);
17
15
  act(() => result.current.search());
18
16
  expect(result.current.loading).toBe(true);
19
- await waitForNextUpdate();
20
- expect(result.current.loading).toBe(false);
17
+ await waitFor(() => expect(result.current.loading).toBe(false));
21
18
  });
22
19
  });
23
20
 
24
21
  describe('reset', () => {
25
22
  it('should change the returned result back to the initial data', async () => {
26
- const { result, waitForNextUpdate } = renderHook(() =>
27
- useSearch(documents, 'Anastasia')
28
- );
23
+ const { result } = renderHook(() => useSearch(documents, 'Anastasia'));
29
24
  expect(result.current.loading).toBe(false);
30
25
  act(() => result.current.search());
31
26
  expect(result.current.loading).toBe(true);
32
27
  expect(result.current.data).toEqual(documents);
33
- await waitForNextUpdate();
34
- expect(result.current.loading).toBe(false);
28
+ await waitFor(() => expect(result.current.loading).toBe(false));
35
29
  expect(result.current.data.length).toBe(1);
36
30
 
37
31
  act(() => result.current.reset());
38
32
  expect(result.current.data).toEqual(documents);
39
- expect(result.current.loading).toBe(false);
33
+ await waitFor(() => expect(result.current.loading).toBe(false));
40
34
  });
41
35
  });
42
36
 
@@ -45,23 +39,20 @@ describe('search', () => {
45
39
  const { result } = renderHook(() => useSearch(documents));
46
40
  expect(result.current.loading).toBe(false);
47
41
  act(() => result.current.search());
48
- expect(result.current.loading).toBe(false);
42
+ await waitFor(() => expect(result.current.loading).toBe(false));
49
43
  expect(result.current.data).toEqual(documents);
50
44
  });
51
45
  it('should return an empty array when there are no relevant items', async () => {
52
- const { result, waitForNextUpdate } = renderHook(() =>
53
- useSearch(documents, 'fajsgsdgsdgsd')
54
- );
46
+ const { result } = renderHook(() => useSearch(documents, 'fajsgsdgsdgsd'));
55
47
  expect(result.current.loading).toBe(false);
56
48
  act(() => result.current.search());
57
49
  expect(result.current.loading).toBe(true);
58
50
  expect(result.current.data).toEqual(documents);
59
- await waitForNextUpdate();
60
- expect(result.current.loading).toBe(false);
51
+ await waitFor(() => expect(result.current.loading).toBe(false));
61
52
  expect(result.current.data).toEqual([]);
62
53
  });
63
54
  it('should return an empty array when relevant field is not indexed', async () => {
64
- const { result, waitForNextUpdate } = renderHook(() =>
55
+ const { result } = renderHook(() =>
65
56
  useSearch(documents, 'Anastasia', {
66
57
  indexing: {
67
58
  fields: ['lastName'], // missing 'firstName'
@@ -72,38 +63,31 @@ describe('search', () => {
72
63
  act(() => result.current.search());
73
64
  expect(result.current.loading).toBe(true);
74
65
  expect(result.current.data).toEqual(documents);
75
- await waitForNextUpdate();
76
- expect(result.current.loading).toBe(false);
66
+ await waitFor(() => expect(result.current.loading).toBe(false));
77
67
  expect(result.current.data).toEqual([]);
78
68
  });
79
69
  it('should return a single result when there is only one relevant item', async () => {
80
- const { result, waitForNextUpdate } = renderHook(() =>
81
- useSearch(documents, 'Anastasia')
82
- );
70
+ const { result } = renderHook(() => useSearch(documents, 'Anastasia'));
83
71
  expect(result.current.loading).toBe(false);
84
72
  act(() => result.current.search());
85
73
  expect(result.current.loading).toBe(true);
86
74
  expect(result.current.data).toEqual(documents);
87
- await waitForNextUpdate();
88
- expect(result.current.loading).toBe(false);
75
+ await waitFor(() => expect(result.current.loading).toBe(false));
89
76
  expect(result.current.data.length).toBe(1);
90
77
 
91
78
  const firstResult = result.current.data[0] as NonNullable<
92
- typeof result.current.data[0]
79
+ (typeof result.current.data)[0]
93
80
  >;
94
81
  expect(firstResult).toBeDefined();
95
82
  expect(Object.values(firstResult).values()).toContain('Anastasia');
96
83
  });
97
84
  it('should return multiple results when there are multiple relevant items', async () => {
98
- const { result, waitForNextUpdate } = renderHook(() =>
99
- useSearch(documents, 'Kari')
100
- );
85
+ const { result } = renderHook(() => useSearch(documents, 'Kari'));
101
86
  expect(result.current.loading).toBe(false);
102
87
  act(() => result.current.search());
103
88
  expect(result.current.loading).toBe(true);
104
89
  expect(result.current.data).toEqual(documents);
105
- await waitForNextUpdate();
106
- expect(result.current.loading).toBe(false);
90
+ await waitFor(() => expect(result.current.loading).toBe(false));
107
91
  expect(result.current.data.length).toBeGreaterThanOrEqual(2);
108
92
 
109
93
  result.current.data.forEach((item) => {
@@ -112,43 +96,37 @@ describe('search', () => {
112
96
  });
113
97
  });
114
98
  it('should work with a partial query', async () => {
115
- const { result, waitForNextUpdate } = renderHook(() =>
116
- useSearch(documents, 'anast')
117
- );
99
+ const { result } = renderHook(() => useSearch(documents, 'anast'));
118
100
  expect(result.current.loading).toBe(false);
119
101
  act(() => result.current.search());
120
102
  expect(result.current.loading).toBe(true);
121
103
  expect(result.current.data).toEqual(documents);
122
- await waitForNextUpdate();
123
- expect(result.current.loading).toBe(false);
104
+ await waitFor(() => expect(result.current.loading).toBe(false));
124
105
  expect(result.current.data.length).toBe(1);
125
106
 
126
107
  const firstResult = result.current.data[0] as NonNullable<
127
- typeof result.current.data[0]
108
+ (typeof result.current.data)[0]
128
109
  >;
129
110
  expect(firstResult).toBeDefined();
130
111
  expect(Object.values(firstResult).values()).toContain('Anastasia');
131
112
  });
132
113
  it('should work with nested field if not explicitly stated', async () => {
133
- const { result, waitForNextUpdate } = renderHook(() =>
134
- useSearch(documents, 'Titanic')
135
- );
114
+ const { result } = renderHook(() => useSearch(documents, 'Titanic'));
136
115
  expect(result.current.loading).toBe(false);
137
116
  act(() => result.current.search());
138
117
  expect(result.current.loading).toBe(true);
139
118
  expect(result.current.data).toEqual(documents);
140
- await waitForNextUpdate();
141
- expect(result.current.loading).toBe(false);
119
+ await waitFor(() => expect(result.current.loading).toBe(false));
142
120
  expect(result.current.data.length).toBe(1);
143
121
 
144
122
  const firstResult = result.current.data[0] as NonNullable<
145
- typeof result.current.data[0]
123
+ (typeof result.current.data)[0]
146
124
  >;
147
125
  expect(firstResult).toBeDefined();
148
126
  expect(Object.values(firstResult.address).values()).toContain('Titanic');
149
127
  });
150
128
  it('should work with nested field if explicitly stated', async () => {
151
- const { result, waitForNextUpdate } = renderHook(() =>
129
+ const { result } = renderHook(() =>
152
130
  useSearch(documents, 'Titanic', {
153
131
  indexing: {
154
132
  fields: ['address.city'],
@@ -159,18 +137,17 @@ describe('search', () => {
159
137
  act(() => result.current.search());
160
138
  expect(result.current.loading).toBe(true);
161
139
  expect(result.current.data).toEqual(documents);
162
- await waitForNextUpdate();
163
- expect(result.current.loading).toBe(false);
140
+ await waitFor(() => expect(result.current.loading).toBe(false));
164
141
  expect(result.current.data.length).toBe(1);
165
142
 
166
143
  const firstResult = result.current.data[0] as NonNullable<
167
- typeof result.current.data[0]
144
+ (typeof result.current.data)[0]
168
145
  >;
169
146
  expect(firstResult).toBeDefined();
170
147
  expect(Object.values(firstResult.address).values()).toContain('Titanic');
171
148
  });
172
149
  it('should work with nested ID', async () => {
173
- const { result, waitForNextUpdate } = renderHook(() =>
150
+ const { result } = renderHook(() =>
174
151
  useSearch(documents, 'Titanic', {
175
152
  indexing: {
176
153
  idKey: 'address.street',
@@ -181,55 +158,48 @@ describe('search', () => {
181
158
  act(() => result.current.search());
182
159
  expect(result.current.loading).toBe(true);
183
160
  expect(result.current.data).toEqual(documents);
184
- await waitForNextUpdate();
185
- expect(result.current.loading).toBe(false);
161
+ await waitFor(() => expect(result.current.loading).toBe(false));
186
162
  expect(result.current.data.length).toBe(1);
187
163
 
188
164
  const firstResult = result.current.data[0] as NonNullable<
189
- typeof result.current.data[0]
165
+ (typeof result.current.data)[0]
190
166
  >;
191
167
  expect(firstResult).toBeDefined();
192
168
  expect(Object.values(firstResult.address).values()).toContain('Titanic');
193
169
  });
194
170
  it('should work with indexed Greek characters and Latin query', async () => {
195
- const { result, waitForNextUpdate } = renderHook(() =>
196
- useSearch(documents, 'Markos')
197
- );
171
+ const { result } = renderHook(() => useSearch(documents, 'Markos'));
198
172
  expect(result.current.loading).toBe(false);
199
173
  act(() => result.current.search());
200
174
  expect(result.current.loading).toBe(true);
201
175
  expect(result.current.data).toEqual(documents);
202
- await waitForNextUpdate();
203
- expect(result.current.loading).toBe(false);
176
+ await waitFor(() => expect(result.current.loading).toBe(false));
204
177
  expect(result.current.data.length).toBe(1);
205
178
 
206
179
  const firstResult = result.current.data[0] as NonNullable<
207
- typeof result.current.data[0]
180
+ (typeof result.current.data)[0]
208
181
  >;
209
182
  expect(firstResult).toBeDefined();
210
183
  expect(Object.values(firstResult).values()).toContain('Μάρκος');
211
184
  });
212
185
  it('should work with indexed Greek characters and Greek query', async () => {
213
- const { result, waitForNextUpdate } = renderHook(() =>
214
- useSearch(documents, 'Μάρκος')
215
- );
186
+ const { result } = renderHook(() => useSearch(documents, 'Μάρκος'));
216
187
  expect(result.current.loading).toBe(false);
217
188
  act(() => result.current.search());
218
189
  expect(result.current.loading).toBe(true);
219
190
  expect(result.current.data).toEqual(documents);
220
- await waitForNextUpdate();
221
- expect(result.current.loading).toBe(false);
191
+ await waitFor(() => expect(result.current.loading).toBe(false));
222
192
  expect(result.current.data.length).toBe(1);
223
193
 
224
194
  const firstResult = result.current.data[0] as NonNullable<
225
- typeof result.current.data[0]
195
+ (typeof result.current.data)[0]
226
196
  >;
227
197
  expect(firstResult).toBeDefined();
228
198
  expect(Object.values(firstResult).values()).toContain('Μάρκος');
229
199
  });
230
200
  it('should react to changes in the documents list', async () => {
231
201
  const emptyDocuments: typeof documents = [];
232
- const { result, rerender, waitForNextUpdate } = renderHook(
202
+ const { result, rerender } = renderHook(
233
203
  ({ documents }) => useSearch(documents, 'Anastasia'),
234
204
  {
235
205
  initialProps: { documents: emptyDocuments },
@@ -238,8 +208,7 @@ describe('search', () => {
238
208
  expect(result.current.loading).toBe(false);
239
209
  act(() => result.current.search());
240
210
  expect(result.current.loading).toBe(true);
241
- await waitForNextUpdate();
242
- expect(result.current.loading).toBe(false);
211
+ await waitFor(() => expect(result.current.loading).toBe(false));
243
212
  expect(result.current.data).toEqual([]);
244
213
 
245
214
  rerender({ documents });
@@ -249,18 +218,17 @@ describe('search', () => {
249
218
  act(() => result.current.search());
250
219
  expect(result.current.loading).toBe(true);
251
220
  expect(result.current.data).toEqual([]);
252
- await waitForNextUpdate();
253
- expect(result.current.loading).toBe(false);
221
+ await waitFor(() => expect(result.current.loading).toBe(false));
254
222
  expect(result.current.data.length).toBe(1);
255
223
 
256
224
  const firstResult = result.current.data[0] as NonNullable<
257
- typeof result.current.data[0]
225
+ (typeof result.current.data)[0]
258
226
  >;
259
227
  expect(firstResult).toBeDefined();
260
228
  expect(Object.values(firstResult).values()).toContain('Anastasia');
261
229
  });
262
230
  it('should react to changes in the search query', async () => {
263
- const { result, rerender, waitForNextUpdate } = renderHook(
231
+ const { result, rerender } = renderHook(
264
232
  ({ query }) => useSearch(documents, query),
265
233
  {
266
234
  initialProps: { query: '' },
@@ -276,12 +244,11 @@ describe('search', () => {
276
244
  act(() => result.current.search());
277
245
  expect(result.current.loading).toBe(true);
278
246
  expect(result.current.data).toEqual(documents);
279
- await waitForNextUpdate();
280
- expect(result.current.loading).toBe(false);
247
+ await waitFor(() => expect(result.current.loading).toBe(false));
281
248
  expect(result.current.data.length).toBe(1);
282
249
 
283
250
  const firstResult = result.current.data[0] as NonNullable<
284
- typeof result.current.data[0]
251
+ (typeof result.current.data)[0]
285
252
  >;
286
253
  expect(firstResult).toBeDefined();
287
254
  expect(Object.values(firstResult).values()).toContain('Anastasia');
package/src/hook.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { useCallback, useMemo, useState } from 'react';
2
- import SearchIndex from './search';
3
- import { UseSearchOptions } from './types';
2
+ import SearchIndex from '@digigov/text-search/search';
3
+ import { UseSearchOptions } from '@digigov/text-search/types';
4
4
 
5
5
  /**
6
6
  * Hook for searching through a list of documents
@@ -24,10 +24,10 @@ export default function useSearch<T extends Record<string, any>>(
24
24
 
25
25
  const indexing = options?.indexing;
26
26
 
27
- const index = useMemo(() => new SearchIndex(documents, indexing), [
28
- documents,
29
- indexing,
30
- ]);
27
+ const index = useMemo(
28
+ () => new SearchIndex(documents, indexing),
29
+ [documents, indexing]
30
+ );
31
31
 
32
32
  const search = useCallback(() => {
33
33
  if (query) {
@@ -35,6 +35,7 @@ export default function useSearch<T extends Record<string, any>>(
35
35
  index
36
36
  .searchAsync(documents, query)
37
37
  .then((data) => setData(data))
38
+ .catch(() => setData([]))
38
39
  .finally(() => setLoading(false));
39
40
  } else {
40
41
  setData(documents);
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import useSearch from './hook';
1
+ import useSearch from '@digigov/text-search/hook';
2
2
 
3
3
  export default useSearch;
4
- export * from './search';
4
+ export * from '@digigov/text-search/search';
@@ -1,5 +1,9 @@
1
1
  import type { SimpleDocumentSearchResultSetUnit as ResultType } from 'flexsearch';
2
- import { findItemsByIds, getAllItemKeys, getResultIds } from '../utils';
2
+ import {
3
+ findItemsByIds,
4
+ getAllItemKeys,
5
+ getResultIds,
6
+ } from '@digigov/text-search/search/utils';
3
7
 
4
8
  describe('utils', () => {
5
9
  describe('getResultIds', () => {
@@ -1,3 +1,3 @@
1
- import { SearchIndex } from './search-index';
1
+ import { SearchIndex } from '@digigov/text-search/search/search-index';
2
2
 
3
3
  export default SearchIndex;
@@ -1,7 +1,7 @@
1
- import { greekToGreeklishMap } from './normalization-map';
1
+ import { greekToGreeklishMap } from '@digigov/text-search/search/lang/gr/normalization-map';
2
2
 
3
- const whitespaceRegex = /[\p{Z}\p{S}\p{P}\p{C}]+/u;
4
- const diacriticsRegex = /[\u0300-\u036f]/g;
3
+ const whitespaceRegex = new RegExp('[p{Z}p{S}p{P}p{C}]+', 'u');
4
+ const diacriticsRegex = new RegExp('[\u0300-\u036f]', 'g');
5
5
  const greekCharsRegex = new RegExp(
6
6
  Object.keys(greekToGreeklishMap).join('|'),
7
7
  'igu'
@@ -22,6 +22,10 @@ export function encodeGreek(str: string) {
22
22
  .toLowerCase()
23
23
  .normalize('NFD')
24
24
  .replace(diacriticsRegex, '')
25
- .replace(greekCharsRegex, (match) => (greekToGreeklishMap as any)[match])
25
+ .replace(greekCharsRegex, (match) =>
26
+ match in greekToGreeklishMap
27
+ ? greekToGreeklishMap[match as keyof typeof greekToGreeklishMap]
28
+ : match
29
+ )
26
30
  .split(whitespaceRegex);
27
31
  }
@@ -1,7 +1,11 @@
1
1
  import { Document } from 'flexsearch';
2
- import type { SearchIndexOptions } from '../types';
3
- import { encodeGreek } from './lang/gr/encoder';
4
- import { findItemsByIds, getAllItemKeys, getResultIds } from './utils';
2
+ import { encodeGreek } from '@digigov/text-search/search/lang/gr/encoder';
3
+ import {
4
+ findItemsByIds,
5
+ getAllItemKeys,
6
+ getResultIds,
7
+ } from '@digigov/text-search/search/utils';
8
+ import type { SearchIndexOptions } from '@digigov/text-search/types';
5
9
 
6
10
  /**
7
11
  * Wrapper class around third party index and search library
@@ -35,11 +35,11 @@ function getValueFromNestedKey(object: Record<string, any>, nestedKey: string) {
35
35
 
36
36
  let result = object;
37
37
  for (const keySegment of keys) {
38
- if (result.hasOwnProperty(keySegment)) {
38
+ if (Object.prototype.hasOwnProperty.call(result, keySegment)) {
39
39
  result = result[keySegment];
40
40
  }
41
41
  }
42
- return (result as unknown) as string;
42
+ return result as unknown as string;
43
43
  }
44
44
 
45
45
  /**
@@ -53,11 +53,11 @@ function getValueFromNestedKey(object: Record<string, any>, nestedKey: string) {
53
53
  */
54
54
  export function getAllItemKeys(
55
55
  object: Record<string, any>,
56
- parentKey: string = ''
56
+ parentKey = ''
57
57
  ): string[] {
58
58
  let keys: string[] = [];
59
59
  for (const key in object) {
60
- if (object.hasOwnProperty(key)) {
60
+ if (Object.prototype.hasOwnProperty.call(object, key)) {
61
61
  const currentKey = parentKey ? `${parentKey}.${key}` : key;
62
62
 
63
63
  if (typeof object[key] === 'object' && object[key] !== null) {
package/src/types.ts CHANGED
@@ -59,7 +59,7 @@ export type NestedKeyOf<T> = T extends Primitive
59
59
  type DeepSubKeys<T, P extends keyof T & string> = T[P] extends (infer Inner)[]
60
60
  ? `${P}.${NestedKeyOf<Inner>}`
61
61
  : T[P] extends object
62
- ? `${P}.${NestedKeyOf<T[P]>}`
63
- : never;
62
+ ? `${P}.${NestedKeyOf<T[P]>}`
63
+ : never;
64
64
 
65
65
  type Primitive = null | undefined | string | number | boolean | symbol | bigint;