@ifc-lite/data 1.14.5 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -36,6 +36,20 @@ const graph: RelationshipGraph = graphBuilder.build();
36
36
  - Relationship graph with typed edges
37
37
  - IFC type enum for fast type comparisons
38
38
  - Spatial hierarchy representation
39
+ - Local EPSG CRS index with exact-code lookup and text search
40
+
41
+ ## EPSG Lookup
42
+
43
+ ```typescript
44
+ import { lookupEpsgByCode, searchEpsgIndex } from '@ifc-lite/data';
45
+
46
+ const lv95 = await lookupEpsgByCode(2056);
47
+ const search = await searchEpsgIndex('web mercator');
48
+ ```
49
+
50
+ The EPSG search index is generated ahead of time and committed to the repo, so
51
+ normal builds stay offline and fast. Refresh it explicitly with
52
+ `pnpm generate:epsg-index`.
39
53
 
40
54
  ## API
41
55
 
@@ -0,0 +1,10 @@
1
+ import type { EpsgIndexEntry, LookupEpsgByCodeOptions, SearchEpsgIndexOptions } from './epsg-types.js';
2
+ export declare function loadEpsgIndex(): Promise<readonly EpsgIndexEntry[]>;
3
+ export declare function loadEpsgIndexDatasetVersion(): Promise<string>;
4
+ export declare function loadEpsgIndexByCode(): Promise<ReadonlyMap<string, EpsgIndexEntry>>;
5
+ export declare function lookupEpsgByCode(code: string | number): Promise<EpsgIndexEntry | undefined>;
6
+ export declare function lookupEpsgByCode(code: string | number, options: LookupEpsgByCodeOptions & {
7
+ prefix: true;
8
+ }): Promise<EpsgIndexEntry[]>;
9
+ export declare function searchEpsgIndex(query: string, options?: SearchEpsgIndexOptions): Promise<EpsgIndexEntry[]>;
10
+ //# sourceMappingURL=epsg-index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"epsg-index.d.ts","sourceRoot":"","sources":["../src/epsg-index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,cAAc,EACd,uBAAuB,EACvB,sBAAsB,EACvB,MAAM,iBAAiB,CAAC;AA8CzB,wBAAsB,aAAa,IAAI,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC,CAUxE;AAED,wBAAsB,2BAA2B,IAAI,OAAO,CAAC,MAAM,CAAC,CAUnE;AAED,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAUxF;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAAC;AACnG,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,OAAO,EAAE,uBAAuB,GAAG;IAAE,MAAM,EAAE,IAAI,CAAA;CAAE,GAClD,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;AAuB7B,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,cAAc,EAAE,CAAC,CAe3B"}
@@ -0,0 +1,111 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ let epsgIndexPromise = null;
5
+ let epsgByCodePromise = null;
6
+ let epsgDatasetVersionPromise = null;
7
+ function normalizeQuery(query) {
8
+ return query.trim().toLowerCase();
9
+ }
10
+ function normalizeLimit(limit, fallback = 25) {
11
+ const numericLimit = typeof limit === 'number' ? limit : Number(limit);
12
+ if (!Number.isFinite(numericLimit))
13
+ return fallback;
14
+ return Math.max(1, Math.floor(numericLimit));
15
+ }
16
+ function scoreEntry(entry, query) {
17
+ if (!query)
18
+ return 0;
19
+ let score = 0;
20
+ if (entry.code === query)
21
+ score += 1000;
22
+ else if (entry.code.startsWith(query))
23
+ score += 700;
24
+ const name = entry.name.toLowerCase();
25
+ const tokens = query.split(/\s+/).filter(Boolean);
26
+ const tokenMatches = tokens.filter(token => entry.searchText.includes(token)).length;
27
+ if (name === query)
28
+ score += 500;
29
+ else if (name.startsWith(query))
30
+ score += 350;
31
+ else if (name.includes(query))
32
+ score += 200;
33
+ for (const alias of entry.aliases) {
34
+ const aliasLower = alias.toLowerCase();
35
+ if (aliasLower === query)
36
+ score += 250;
37
+ else if (aliasLower.startsWith(query))
38
+ score += 175;
39
+ else if (aliasLower.includes(query))
40
+ score += 100;
41
+ }
42
+ if (entry.searchText.includes(query))
43
+ score += 50;
44
+ if (tokens.length > 1 && tokenMatches === tokens.length)
45
+ score += 120;
46
+ else
47
+ score += tokenMatches * 20;
48
+ if (!entry.deprecated)
49
+ score += 10;
50
+ return score;
51
+ }
52
+ export async function loadEpsgIndex() {
53
+ if (!epsgIndexPromise) {
54
+ epsgIndexPromise = import('./generated/epsg-index.generated.js').then(module => module.EPSG_INDEX).catch(error => {
55
+ epsgIndexPromise = null;
56
+ throw error;
57
+ });
58
+ }
59
+ return epsgIndexPromise;
60
+ }
61
+ export async function loadEpsgIndexDatasetVersion() {
62
+ if (!epsgDatasetVersionPromise) {
63
+ epsgDatasetVersionPromise = import('./generated/epsg-index.generated.js').then(module => module.EPSG_INDEX_DATASET_VERSION).catch(error => {
64
+ epsgDatasetVersionPromise = null;
65
+ throw error;
66
+ });
67
+ }
68
+ return epsgDatasetVersionPromise;
69
+ }
70
+ export async function loadEpsgIndexByCode() {
71
+ if (!epsgByCodePromise) {
72
+ epsgByCodePromise = loadEpsgIndex().then(entries => new Map(entries.map(entry => [entry.code, entry]))).catch(error => {
73
+ epsgByCodePromise = null;
74
+ throw error;
75
+ });
76
+ }
77
+ return epsgByCodePromise;
78
+ }
79
+ export async function lookupEpsgByCode(code, options = {}) {
80
+ const key = String(code).trim();
81
+ if (!key)
82
+ return undefined;
83
+ if (options.prefix) {
84
+ const limit = normalizeLimit(options.limit, 25);
85
+ const includeDeprecated = options.includeDeprecated ?? false;
86
+ const entries = await loadEpsgIndex();
87
+ return entries
88
+ .filter(entry => entry.code.startsWith(key))
89
+ .filter(entry => includeDeprecated || !entry.deprecated)
90
+ .sort((left, right) => Number(left.code) - Number(right.code))
91
+ .slice(0, limit);
92
+ }
93
+ const byCode = await loadEpsgIndexByCode();
94
+ return byCode.get(key);
95
+ }
96
+ export async function searchEpsgIndex(query, options = {}) {
97
+ const normalized = normalizeQuery(query);
98
+ if (!normalized)
99
+ return [];
100
+ const limit = normalizeLimit(options.limit, 25);
101
+ const includeDeprecated = options.includeDeprecated ?? false;
102
+ const entries = await loadEpsgIndex();
103
+ return entries
104
+ .filter(entry => includeDeprecated || !entry.deprecated)
105
+ .map(entry => ({ entry, score: scoreEntry(entry, normalized) }))
106
+ .filter(result => result.score > 0)
107
+ .sort((left, right) => right.score - left.score || Number(left.entry.code) - Number(right.entry.code))
108
+ .slice(0, limit)
109
+ .map(result => result.entry);
110
+ }
111
+ //# sourceMappingURL=epsg-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"epsg-index.js","sourceRoot":"","sources":["../src/epsg-index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ export type EpsgKind = 'Projected' | 'Geographic' | 'Compound' | 'Vertical' | 'Engineering' | 'Geocentric' | 'Derived' | 'Unknown';
2
+ export interface EpsgIndexEntry {
3
+ code: string;
4
+ name: string;
5
+ kind: EpsgKind | string;
6
+ area: string;
7
+ scope: string;
8
+ datum: string;
9
+ projection: string;
10
+ unit: string;
11
+ deprecated: boolean;
12
+ aliases: string[];
13
+ searchText: string;
14
+ }
15
+ export interface SearchEpsgIndexOptions {
16
+ includeDeprecated?: boolean;
17
+ limit?: number;
18
+ }
19
+ export interface LookupEpsgByCodeOptions {
20
+ prefix?: boolean;
21
+ includeDeprecated?: boolean;
22
+ limit?: number;
23
+ }
24
+ //# sourceMappingURL=epsg-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"epsg-types.d.ts","sourceRoot":"","sources":["../src/epsg-types.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,QAAQ,GAChB,WAAW,GACX,YAAY,GACZ,UAAU,GACV,UAAU,GACV,aAAa,GACb,YAAY,GACZ,SAAS,GACT,SAAS,CAAC;AAEd,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB;IACrC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
@@ -0,0 +1,5 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ export {};
5
+ //# sourceMappingURL=epsg-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"epsg-types.js","sourceRoot":"","sources":["../src/epsg-types.ts"],"names":[],"mappings":"AAAA;;+DAE+D"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * AUTO-GENERATED by `scripts/generate-epsg-index.ts`.
3
+ *
4
+ * Source: EPSG Registry API (https://apps.epsg.org/api/v1)
5
+ * Dataset version: 12.054
6
+ * Terms: https://epsg.org/terms-of-use.html
7
+ *
8
+ * Do not edit by hand. Re-run `pnpm generate:epsg-index` to refresh.
9
+ */
10
+ import type { EpsgIndexEntry } from '../epsg-types.js';
11
+ export declare const EPSG_INDEX_DATASET_VERSION = "12.054";
12
+ export declare const EPSG_INDEX: readonly EpsgIndexEntry[];
13
+ //# sourceMappingURL=epsg-index.generated.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"epsg-index.generated.d.ts","sourceRoot":"","sources":["../../src/generated/epsg-index.generated.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,eAAO,MAAM,0BAA0B,WAAW,CAAC;AAInD,eAAO,MAAM,UAAU,EAAE,SAAS,cAAc,EAAoD,CAAC"}