@ignfab/geocontext 0.9.0 → 0.9.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/README.md +34 -11
- package/dist/gpf/adminexpress.d.ts +2 -1
- package/dist/gpf/adminexpress.js +7 -3
- package/dist/gpf/adminexpress.js.map +1 -1
- package/dist/gpf/altitude.d.ts +2 -1
- package/dist/gpf/altitude.js +13 -19
- package/dist/gpf/altitude.js.map +1 -1
- package/dist/gpf/geocode.d.ts +3 -1
- package/dist/gpf/geocode.js +19 -8
- package/dist/gpf/geocode.js.map +1 -1
- package/dist/gpf/parcellaire-express.d.ts +2 -1
- package/dist/gpf/parcellaire-express.js +8 -4
- package/dist/gpf/parcellaire-express.js.map +1 -1
- package/dist/gpf/urbanisme.d.ts +4 -2
- package/dist/gpf/urbanisme.js +32 -5
- package/dist/gpf/urbanisme.js.map +1 -1
- package/dist/gpf/wfs.d.ts +5 -3
- package/dist/gpf/wfs.js +59 -19
- package/dist/gpf/wfs.js.map +1 -1
- package/dist/logger.js.map +1 -1
- package/dist/resources/WfsCqlFilterResource.d.ts +10 -0
- package/dist/resources/WfsCqlFilterResource.js +21 -0
- package/dist/resources/WfsCqlFilterResource.js.map +1 -0
- package/dist/resources/readMarkdownResource.d.ts +1 -0
- package/dist/resources/readMarkdownResource.js +21 -0
- package/dist/resources/readMarkdownResource.js.map +1 -0
- package/dist/tools/AdminexpressTool.d.ts +58 -15
- package/dist/tools/AdminexpressTool.js +33 -13
- package/dist/tools/AdminexpressTool.js.map +1 -1
- package/dist/tools/AltitudeTool.d.ts +64 -16
- package/dist/tools/AltitudeTool.js +30 -12
- package/dist/tools/AltitudeTool.js.map +1 -1
- package/dist/tools/AssietteSupTool.d.ts +64 -16
- package/dist/tools/AssietteSupTool.js +34 -13
- package/dist/tools/AssietteSupTool.js.map +1 -1
- package/dist/tools/CadastreTool.d.ts +68 -15
- package/dist/tools/CadastreTool.js +35 -13
- package/dist/tools/CadastreTool.js.map +1 -1
- package/dist/tools/GeocodeTool.d.ts +73 -10
- package/dist/tools/GeocodeTool.js +35 -9
- package/dist/tools/GeocodeTool.js.map +1 -1
- package/dist/tools/GpfWfsDescribeTypeTool.d.ts +115 -12
- package/dist/tools/GpfWfsDescribeTypeTool.js +39 -13
- package/dist/tools/GpfWfsDescribeTypeTool.js.map +1 -1
- package/dist/tools/GpfWfsGetFeaturesTool.d.ts +65 -28
- package/dist/tools/GpfWfsGetFeaturesTool.js +117 -47
- package/dist/tools/GpfWfsGetFeaturesTool.js.map +1 -1
- package/dist/tools/GpfWfsListTypesTool.d.ts +18 -6
- package/dist/tools/GpfWfsListTypesTool.js +16 -8
- package/dist/tools/GpfWfsListTypesTool.js.map +1 -1
- package/dist/tools/GpfWfsSearchTypesTool.d.ts +61 -14
- package/dist/tools/GpfWfsSearchTypesTool.js +38 -17
- package/dist/tools/GpfWfsSearchTypesTool.js.map +1 -1
- package/dist/tools/UrbanismeTool.d.ts +63 -15
- package/dist/tools/UrbanismeTool.js +42 -13
- package/dist/tools/UrbanismeTool.js.map +1 -1
- package/dist/tools/toolAnnotations.d.ts +6 -0
- package/dist/tools/toolAnnotations.js +7 -0
- package/dist/tools/toolAnnotations.js.map +1 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ L'idée est ici d'**expérimenter la conception d'un MCP rendant les données et
|
|
|
14
14
|
|
|
15
15
|
## Mises en garde
|
|
16
16
|
|
|
17
|
-
- Ce développement est un POC en incubation
|
|
17
|
+
- Ce développement est un POC en incubation au sein d'ignfab (archivage en cours de [mborne/geocontext](https://github.com/mborne/geocontext))
|
|
18
18
|
- S'il s'avère utile de l'industrialiser, le dépôt sera migré sous responsabilité IGN et l'outil sera renommé (ex : `IGNF/mcp-gpf-server`)
|
|
19
19
|
- Plusieurs problèmes et améliorations possibles ont été identifiés et sont en cours de mitigation/résolution (c.f. [issues](https://github.com/ignfab/geocontext/issues?q=is%3Aissue%20state%3Aopen%20label%3Ametadata)).
|
|
20
20
|
- Cet outil n'est pas magique (voir [Fonctionnalités](#fonctionnalités) pour avoir une idée de ses capacités)
|
|
@@ -74,6 +74,8 @@ npm run build
|
|
|
74
74
|
|
|
75
75
|
### Utilisation de la version locale
|
|
76
76
|
|
|
77
|
+
#### Avec un client MCP compatible JSON
|
|
78
|
+
|
|
77
79
|
```json
|
|
78
80
|
{
|
|
79
81
|
"mcpServers": {
|
|
@@ -85,6 +87,27 @@ npm run build
|
|
|
85
87
|
}
|
|
86
88
|
```
|
|
87
89
|
|
|
90
|
+
#### Avec Codex CLI / VS Code
|
|
91
|
+
|
|
92
|
+
Avec Codex CLI ou l'extension Codex pour VS Code, la configuration se fait dans `~/.codex/config.toml` :
|
|
93
|
+
|
|
94
|
+
```toml
|
|
95
|
+
[mcp_servers.geocontext]
|
|
96
|
+
command = "node"
|
|
97
|
+
args = ["/chemin/absolu/vers/geocontext/dist/index.js"]
|
|
98
|
+
|
|
99
|
+
# Définition d'un corporate proxy si nécessaire
|
|
100
|
+
[mcp_servers.geocontext.env]
|
|
101
|
+
HTTPS_PROXY = "http://proxy.domain.fr:3128"
|
|
102
|
+
HTTP_PROXY = "http://proxy.domain.fr:3128"
|
|
103
|
+
NO_PROXY = "localhost,127.0.0.1"
|
|
104
|
+
http_proxy = "http://proxy.domain.fr:3128"
|
|
105
|
+
https_proxy = "http://proxy.domain.fr:3128"
|
|
106
|
+
no_proxy = "localhost,127.0.0.1"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Après mise à jour de `~/.codex/config.toml`, relancer la session Codex CLI ou recharger VS Code si l'extension Codex est déjà ouverte.
|
|
110
|
+
|
|
88
111
|
### Debug de la version locale
|
|
89
112
|
|
|
90
113
|
```bash
|
|
@@ -98,15 +121,15 @@ Pour une utilisation avancée :
|
|
|
98
121
|
| Nom | Description | Valeur par défaut |
|
|
99
122
|
| ---------------- | -------------------------------------------------------------------------------------------------------------------- | ----------------- |
|
|
100
123
|
| `TRANSPORT_TYPE` | [Transport](https://mcp-framework.com/docs/Transports/transports-overview) permet de choisir entre "stdio" et "http" | "stdio" |
|
|
101
|
-
| `
|
|
124
|
+
| `GPF_WFS_MINISEARCH_OPTIONS` | Chaîne JSON optionnelle pour ajuster les options MiniSearch utilisées par `gpf_wfs_search_types` (`fields`, `combineWith`, `fuzzy`, `boost.namespace`, `boost.name`, `boost.title`, `boost.description`, `boost.properties`, `boost.enums`, `boost.identifierTokens`). | options par défaut de `@ignfab/gpf-schema-store` |
|
|
102
125
|
|
|
103
126
|
Exemple :
|
|
104
127
|
|
|
105
128
|
```bash
|
|
106
|
-
export
|
|
129
|
+
export GPF_WFS_MINISEARCH_OPTIONS='{"fields":["title","identifierTokens"],"combineWith":"OR","fuzzy":0.05,"boost":{"title":4,"name":5}}'
|
|
107
130
|
```
|
|
108
131
|
|
|
109
|
-
Si `
|
|
132
|
+
Si `GPF_WFS_MINISEARCH_OPTIONS` est absent ou vide, les options par défaut restent celles de `@ignfab/gpf-schema-store`, y compris le comportement par défaut `OR` de MiniSearch pour `combineWith`.
|
|
110
133
|
|
|
111
134
|
Remarque :
|
|
112
135
|
|
|
@@ -148,18 +171,18 @@ L'idée est ici de répondre à des précises en traitant côté serveur les app
|
|
|
148
171
|
|
|
149
172
|
### Explorer les données vecteurs
|
|
150
173
|
|
|
151
|
-
#### Explorer les tables
|
|
152
|
-
|
|
153
|
-
* [gpf_wfs_list_types()](src/tools/GpfWfsListTypesTool.ts) pour **lister les
|
|
154
|
-
* [gpf_wfs_search_types(keywords,max_results=10)](src/tools/GpfWfsSearchTypesTool.ts) pour **rechercher
|
|
174
|
+
#### Explorer les tables
|
|
175
|
+
|
|
176
|
+
* [gpf_wfs_list_types()](src/tools/GpfWfsListTypesTool.ts) pour **lister de façon exhaustive les types WFS connus du catalogue de schémas embarqué**. Cet outil est surtout utile pour un inventaire complet ou une exploration globale du catalogue ; pour trouver rapidement un type pertinent, préférer `gpf_wfs_search_types`.
|
|
177
|
+
* [gpf_wfs_search_types(keywords,max_results=10)](src/tools/GpfWfsSearchTypesTool.ts) pour **rechercher un type WFS pertinent à partir de mots-clés et obtenir un `typename` valide**. La recherche est textuelle et configurable via `GPF_WFS_MINISEARCH_OPTIONS`.
|
|
155
178
|
|
|
156
179
|
> - Quels sont les millésimes ADMINEXPRESS disponibles sur la Géoplateforme?
|
|
157
180
|
> - Quelle est la table de la BDTOPO correspondant aux bâtiments?
|
|
158
181
|
> - Dans quelle table de la BDTOPO peut-on trouver les ponts?
|
|
159
182
|
|
|
160
|
-
#### Explorer la structure des tables
|
|
161
|
-
|
|
162
|
-
* [gpf_wfs_describe_type(typename)](src/tools/GpfWfsDescribeTypeTool.ts) pour récupérer le **schéma détaillé d'
|
|
183
|
+
#### Explorer la structure des tables
|
|
184
|
+
|
|
185
|
+
* [gpf_wfs_describe_type(typename)](src/tools/GpfWfsDescribeTypeTool.ts) pour récupérer le **schéma détaillé d'un type WFS** depuis le catalogue embarqué (`id`, `namespace`, `name`, `title`, `description`, `properties`), en particulier avant d'appeler `gpf_wfs_get_features`
|
|
163
186
|
|
|
164
187
|
> - Quelles sont les informations disponibles pour les communes avec ADMINEXPRESS-COG.LATEST?
|
|
165
188
|
> - Compare le modèle des communes entre ADMINEXPRESS-COG:2024 et ADMINEXPRESS-COG.LATEST
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @param {number} lon
|
|
5
5
|
* @param {number} lat
|
|
6
|
+
* @param {(url: string) => Promise<any>} [fetcher]
|
|
6
7
|
* @returns {object[]}
|
|
7
8
|
*/
|
|
8
|
-
export function getAdminUnits(lon: number, lat: number): object[];
|
|
9
|
+
export function getAdminUnits(lon: number, lat: number, fetcher?: (url: string) => Promise<any>): object[];
|
|
9
10
|
/**
|
|
10
11
|
* ADMINEXPRESS-COG.LATEST:{type}
|
|
11
12
|
*
|
package/dist/gpf/adminexpress.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
1
2
|
import { fetchJSON } from '../helpers/http.js';
|
|
2
3
|
import logger from '../logger.js';
|
|
3
|
-
import _ from 'lodash';
|
|
4
4
|
/**
|
|
5
5
|
* ADMINEXPRESS-COG.LATEST:{type}
|
|
6
6
|
*
|
|
@@ -21,9 +21,10 @@ export const ADMINEXPRESS_TYPES = [
|
|
|
21
21
|
*
|
|
22
22
|
* @param {number} lon
|
|
23
23
|
* @param {number} lat
|
|
24
|
+
* @param {(url: string) => Promise<any>} [fetcher]
|
|
24
25
|
* @returns {object[]}
|
|
25
26
|
*/
|
|
26
|
-
export async function getAdminUnits(lon, lat) {
|
|
27
|
+
export async function getAdminUnits(lon, lat, fetcher = fetchJSON) {
|
|
27
28
|
logger.info(`[adminexpress] getAdminUnits(${lon},${lat})...`);
|
|
28
29
|
// note that EPSG:4326 means lat,lon order for GeoServer -> flipped coordinates...
|
|
29
30
|
const cql_filter = `INTERSECTS(geometrie,Point(${lat} ${lon}))`;
|
|
@@ -35,7 +36,10 @@ export async function getAdminUnits(lon, lat) {
|
|
|
35
36
|
outputFormat: 'application/json',
|
|
36
37
|
cql_filter: cql_filter
|
|
37
38
|
}).toString();
|
|
38
|
-
const featureCollection = await
|
|
39
|
+
const featureCollection = await fetcher(url);
|
|
40
|
+
if (!Array.isArray(featureCollection?.features)) {
|
|
41
|
+
throw new Error("Le service ADMINEXPRESS n'a pas retourné de collection d'objets exploitable");
|
|
42
|
+
}
|
|
39
43
|
return featureCollection.features.map((feature) => {
|
|
40
44
|
// parse type from id (ex: "commune.3837")
|
|
41
45
|
const type = feature.id.split('.')[0];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adminexpress.js","sourceRoot":"","sources":["../../src/gpf/adminexpress.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,MAAM,MAAM,cAAc,CAAC;AAElC
|
|
1
|
+
{"version":3,"file":"adminexpress.js","sourceRoot":"","sources":["../../src/gpf/adminexpress.js"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,QAAQ,CAAC;AAEvB,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,MAAM,MAAM,cAAc,CAAC;AAElC;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,8CAA8C,CAAC;AAClF,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAC9B,SAAS;IACT,QAAQ;IACR,2BAA2B;IAC3B,MAAM;IACN,aAAa;IACb,QAAQ;IACR,gBAAgB;CACnB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,GAAG,SAAS;IAC7D,MAAM,CAAC,IAAI,CAAC,gCAAgC,GAAG,IAAI,GAAG,MAAM,CAAC,CAAC;IAE9D,kFAAkF;IAClF,MAAM,UAAU,GAAG,8BAA8B,GAAG,IAAI,GAAG,IAAI,CAAC;IAEhE,uDAAuD;IACvD,MAAM,GAAG,GAAG,4BAA4B,GAAG,IAAI,eAAe,CAAC;QAC3D,OAAO,EAAE,KAAK;QACd,OAAO,EAAE,YAAY;QACrB,QAAQ,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,GAAG,OAAO,2BAA2B,IAAI,EAAE,CAAA,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QAClG,YAAY,EAAE,kBAAkB;QAChC,UAAU,EAAE,UAAU;KACzB,CAAC,CAAC,QAAQ,EAAE,CAAC;IAEd,MAAM,iBAAiB,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,iBAAiB,EAAE,QAAQ,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,6EAA6E,CAAC,CAAC;IACnG,CAAC;IACD,OAAO,iBAAiB,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QAC9C,0CAA0C;QAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACtC,wCAAwC;QACxC,OAAO,MAAM,CAAC,MAAM,CAAC;YACjB,IAAI,EAAE,IAAI;YACV,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,IAAI,EAAE,OAAO,CAAC,IAAI;SACrB,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;AACP,CAAC"}
|
package/dist/gpf/altitude.d.ts
CHANGED
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @param {number} lon
|
|
7
7
|
* @param {number} lat
|
|
8
|
+
* @param {(url: string) => Promise<any>} [fetcher]
|
|
8
9
|
* @returns
|
|
9
10
|
*/
|
|
10
|
-
export function getAltitudeByLocation(lon: number, lat: number): Promise<{
|
|
11
|
+
export function getAltitudeByLocation(lon: number, lat: number, fetcher?: (url: string) => Promise<any>): Promise<{
|
|
11
12
|
lon: number;
|
|
12
13
|
lat: number;
|
|
13
14
|
altitude: any;
|
package/dist/gpf/altitude.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import logger from "../logger.js";
|
|
2
1
|
import { fetchJSON } from "../helpers/http.js";
|
|
2
|
+
import logger from "../logger.js";
|
|
3
3
|
export const ALTITUDE_SOURCE = "Géoplateforme (altimétrie)";
|
|
4
4
|
/**
|
|
5
5
|
* Get altitude for a given location.
|
|
@@ -8,28 +8,22 @@ export const ALTITUDE_SOURCE = "Géoplateforme (altimétrie)";
|
|
|
8
8
|
*
|
|
9
9
|
* @param {number} lon
|
|
10
10
|
* @param {number} lat
|
|
11
|
+
* @param {(url: string) => Promise<any>} [fetcher]
|
|
11
12
|
* @returns
|
|
12
13
|
*/
|
|
13
|
-
export async function getAltitudeByLocation(lon, lat) {
|
|
14
|
+
export async function getAltitudeByLocation(lon, lat, fetcher = fetchJSON) {
|
|
14
15
|
logger.info(`getAltitudeByLocation(${lon},${lat})...`);
|
|
15
16
|
const url = `https://data.geopf.fr/altimetrie/1.0/calcul/alti/rest/elevation.json?lon=${lon}&lat=${lat}&resource=ign_rge_alti_wld`;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
lon: lon,
|
|
21
|
-
lat: lat,
|
|
22
|
-
altitude: elevation.z,
|
|
23
|
-
accuracy: elevation.acc,
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
catch (e) {
|
|
27
|
-
return {
|
|
28
|
-
lon: lon,
|
|
29
|
-
lat: lat,
|
|
30
|
-
altitude: null,
|
|
31
|
-
accuracy: 'No data',
|
|
32
|
-
};
|
|
17
|
+
const json = await fetcher(url);
|
|
18
|
+
const elevation = json?.elevations?.[0];
|
|
19
|
+
if (!elevation) {
|
|
20
|
+
throw new Error("Le service d'altitude n'a renvoyé aucune donnée d'altitude");
|
|
33
21
|
}
|
|
22
|
+
return {
|
|
23
|
+
lon: lon,
|
|
24
|
+
lat: lat,
|
|
25
|
+
altitude: elevation.z,
|
|
26
|
+
accuracy: elevation.acc,
|
|
27
|
+
};
|
|
34
28
|
}
|
|
35
29
|
//# sourceMappingURL=altitude.js.map
|
package/dist/gpf/altitude.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"altitude.js","sourceRoot":"","sources":["../../src/gpf/altitude.js"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"altitude.js","sourceRoot":"","sources":["../../src/gpf/altitude.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,MAAM,MAAM,cAAc,CAAC;AAElC,MAAM,CAAC,MAAM,eAAe,GAAG,4BAA4B,CAAC;AAE5D;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,GAAG,SAAS;IACrE,MAAM,CAAC,IAAI,CAAC,yBAAyB,GAAG,IAAI,GAAG,MAAM,CAAC,CAAC;IAEvD,MAAM,GAAG,GAAG,4EAA4E,GAAG,QAAQ,GAAG,4BAA4B,CAAC;IAEnI,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,SAAS,GAAG,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;IAExC,IAAI,CAAC,SAAS,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;IAClF,CAAC;IAED,OAAO;QACH,GAAG,EAAE,GAAG;QACR,GAAG,EAAE,GAAG;QACR,QAAQ,EAAE,SAAS,CAAC,CAAC;QACrB,QAAQ,EAAE,SAAS,CAAC,GAAG;KAC1B,CAAC;AAEN,CAAC"}
|
package/dist/gpf/geocode.d.ts
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* @see https://geoservices.ign.fr/documentation/services/services-geoplateforme/autocompletion
|
|
5
5
|
*
|
|
6
6
|
* @param {string} text
|
|
7
|
+
* @param {number} [maximumResponses=3]
|
|
8
|
+
* @param {(url: string) => Promise<any>} [fetcher]
|
|
7
9
|
* @returns
|
|
8
10
|
*/
|
|
9
|
-
export function geocode(text: string): Promise<any>;
|
|
11
|
+
export function geocode(text: string, maximumResponses?: number, fetcher?: (url: string) => Promise<any>): Promise<any>;
|
|
10
12
|
export const GEOCODE_SOURCE: "G\u00E9oplateforme (service d'autocompl\u00E9tion)";
|
package/dist/gpf/geocode.js
CHANGED
|
@@ -1,26 +1,37 @@
|
|
|
1
|
-
import logger from "../logger.js";
|
|
2
1
|
import { fetchJSON } from "../helpers/http.js";
|
|
2
|
+
import logger from "../logger.js";
|
|
3
3
|
export const GEOCODE_SOURCE = "Géoplateforme (service d'autocomplétion)";
|
|
4
|
+
// https://data.geopf.fr/geocodage/completion/openapi does not provide all the necessary information yet
|
|
4
5
|
/**
|
|
5
6
|
* Get coordinates for a given location
|
|
6
7
|
*
|
|
7
8
|
* @see https://geoservices.ign.fr/documentation/services/services-geoplateforme/autocompletion
|
|
8
9
|
*
|
|
9
10
|
* @param {string} text
|
|
11
|
+
* @param {number} [maximumResponses=3]
|
|
12
|
+
* @param {(url: string) => Promise<any>} [fetcher]
|
|
10
13
|
* @returns
|
|
11
14
|
*/
|
|
12
|
-
export async function geocode(text) {
|
|
13
|
-
|
|
15
|
+
export async function geocode(text, maximumResponses = 3, fetcher = fetchJSON) {
|
|
16
|
+
const normalizedText = typeof text === "string" ? text.trim() : "";
|
|
17
|
+
if (!normalizedText) {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
logger.info(`geocode(${JSON.stringify(normalizedText)}, ${maximumResponses})...`);
|
|
14
21
|
const url = 'https://data.geopf.fr/geocodage/completion/?' + new URLSearchParams({
|
|
15
|
-
text:
|
|
16
|
-
maximumResponses:
|
|
22
|
+
text: normalizedText,
|
|
23
|
+
maximumResponses: String(maximumResponses)
|
|
17
24
|
}).toString();
|
|
18
|
-
const json = await
|
|
19
|
-
|
|
25
|
+
const json = await fetcher(url);
|
|
26
|
+
const results = Array.isArray(json?.results) ? json.results : [];
|
|
27
|
+
return results.map((item) => {
|
|
20
28
|
return {
|
|
21
29
|
lon: item.x,
|
|
22
30
|
lat: item.y,
|
|
23
|
-
fulltext: item.fulltext
|
|
31
|
+
fulltext: item.fulltext,
|
|
32
|
+
kind: item.kind,
|
|
33
|
+
city: item.city,
|
|
34
|
+
zipcode: item.zipcode
|
|
24
35
|
};
|
|
25
36
|
});
|
|
26
37
|
}
|
package/dist/gpf/geocode.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geocode.js","sourceRoot":"","sources":["../../src/gpf/geocode.js"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"geocode.js","sourceRoot":"","sources":["../../src/gpf/geocode.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,MAAM,MAAM,cAAc,CAAC;AAElC,MAAM,CAAC,MAAM,cAAc,GAAG,0CAA0C,CAAC;AAEzE,wGAAwG;AAExG;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAI,EAAE,gBAAgB,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS;IACzE,MAAM,cAAc,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAEnE,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,KAAK,gBAAgB,MAAM,CAAC,CAAC;IAElF,MAAM,GAAG,GAAG,8CAA8C,GAAG,IAAI,eAAe,CAAC;QAC/E,IAAI,EAAE,cAAc;QACpB,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,CAAC;KAC3C,CAAC,CAAC,QAAQ,EAAE,CAAC;IAEd,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IACjE,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAC,EAAE;QAAC,OAAO;YACjC,GAAG,EAAE,IAAI,CAAC,CAAC;YACX,GAAG,EAAE,IAAI,CAAC,CAAC;YACX,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAA;IAAA,CAAC,CAAC,CAAC;AACR,CAAC"}
|
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @param {number} lon
|
|
7
7
|
* @param {number} lat
|
|
8
|
+
* @param {(url: string) => Promise<any>} [fetcher]
|
|
8
9
|
* @returns
|
|
9
10
|
*/
|
|
10
|
-
export function getParcellaireExpress(lon: number, lat: number): Promise<array<object>>;
|
|
11
|
+
export function getParcellaireExpress(lon: number, lat: number, fetcher?: (url: string) => Promise<any>): Promise<array<object>>;
|
|
11
12
|
export const PARCELLAIRE_EXPRESS_SOURCE: "G\u00E9oplateforme (WFS, CADASTRALPARCELS.PARCELLAIRE_EXPRESS)";
|
|
12
13
|
export const PARCELLAIRE_EXPRESS_TYPES: string[];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import logger from '../logger.js';
|
|
2
|
-
import distance from '../helpers/distance.js';
|
|
3
1
|
import _ from 'lodash';
|
|
2
|
+
import distance from '../helpers/distance.js';
|
|
4
3
|
import { fetchJSON } from '../helpers/http.js';
|
|
4
|
+
import logger from '../logger.js';
|
|
5
5
|
// CADASTRALPARCELS.PARCELLAIRE_EXPRESS:
|
|
6
6
|
// https://data.geopf.fr/wfs/ows?service=WFS&version=2.0.0&request=GetCapabilities
|
|
7
7
|
export const PARCELLAIRE_EXPRESS_SOURCE = "Géoplateforme (WFS, CADASTRALPARCELS.PARCELLAIRE_EXPRESS)";
|
|
@@ -39,9 +39,10 @@ function filterByDistance(items) {
|
|
|
39
39
|
*
|
|
40
40
|
* @param {number} lon
|
|
41
41
|
* @param {number} lat
|
|
42
|
+
* @param {(url: string) => Promise<any>} [fetcher]
|
|
42
43
|
* @returns
|
|
43
44
|
*/
|
|
44
|
-
export async function getParcellaireExpress(lon, lat) {
|
|
45
|
+
export async function getParcellaireExpress(lon, lat, fetcher = fetchJSON) {
|
|
45
46
|
logger.info(`getParcellaireExpress(${lon},${lat}) ...`);
|
|
46
47
|
// note that EPSG:4326 means lat,lon order for GeoServer -> flipped coordinates...
|
|
47
48
|
const cql_filter = `DWITHIN(geom,Point(${lat} ${lon}),10,meters)`;
|
|
@@ -57,7 +58,10 @@ export async function getParcellaireExpress(lon, lat) {
|
|
|
57
58
|
outputFormat: 'application/json',
|
|
58
59
|
cql_filter: cql_filter
|
|
59
60
|
}).toString();
|
|
60
|
-
const featureCollection = await
|
|
61
|
+
const featureCollection = await fetcher(url);
|
|
62
|
+
if (!Array.isArray(featureCollection?.features)) {
|
|
63
|
+
throw new Error("Le service PARCELLAIRE_EXPRESS n'a pas retourné de collection d'objets exploitable");
|
|
64
|
+
}
|
|
61
65
|
return filterByDistance(featureCollection.features.map((feature) => {
|
|
62
66
|
// parse type from id (ex: "commune.3837")
|
|
63
67
|
const type = feature.id.split('.')[0];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parcellaire-express.js","sourceRoot":"","sources":["../../src/gpf/parcellaire-express.js"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"parcellaire-express.js","sourceRoot":"","sources":["../../src/gpf/parcellaire-express.js"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,QAAQ,CAAC;AAEvB,OAAO,QAAQ,MAAM,wBAAwB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,MAAM,MAAM,cAAc,CAAC;AAElC,wCAAwC;AACxC,kFAAkF;AAElF,MAAM,CAAC,MAAM,0BAA0B,GAAG,2DAA2D,CAAC;AACtG,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACrC,gBAAgB;IAChB,SAAS;IACT,SAAS;IACT,UAAU;IACV,qBAAqB;IACrB,YAAY;CACf,CAAC;AAEF;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,KAAK;IAC3B,MAAM,WAAW,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IAE3E,MAAM,MAAM,GAAG,EAAE,CAAC;IAClB,IAAI,QAAQ,GAAG,IAAI,CAAC;IACpB,KAAM,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC9B,IAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACzB,SAAS;QACb,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClB,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC;IACzB,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC;AAGD;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,GAAG,SAAS;IACrE,MAAM,CAAC,IAAI,CAAC,yBAAyB,GAAG,IAAI,GAAG,OAAO,CAAC,CAAC;IACxD,kFAAkF;IAClF,MAAM,UAAU,GAAG,sBAAsB,GAAG,IAAI,GAAG,cAAc,CAAC;IAElE,MAAM,UAAU,GAAG;QACf,MAAM,EAAE,OAAO;QACf,aAAa,EAAE,CAAC,GAAG,EAAC,GAAG,CAAC;KAC3B,CAAC;IAEF,uDAAuD;IACvD,MAAM,GAAG,GAAG,4BAA4B,GAAG,IAAI,eAAe,CAAC;QAC3D,OAAO,EAAE,KAAK;QACd,OAAO,EAAE,YAAY;QACrB,QAAQ,EAAE,yBAAyB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,GAAG,OAAO,wCAAwC,IAAI,EAAE,CAAA,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QACtH,YAAY,EAAE,kBAAkB;QAChC,UAAU,EAAE,UAAU;KACzB,CAAC,CAAC,QAAQ,EAAE,CAAC;IAEd,MAAM,iBAAiB,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,iBAAiB,EAAE,QAAQ,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,oFAAoF,CAAC,CAAC;IAC1G,CAAC;IACD,OAAO,gBAAgB,CAAC,iBAAiB,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QAC/D,0CAA0C;QAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACtC,wCAAwC;QACxC,OAAO,MAAM,CAAC,MAAM,CAAC;YACjB,IAAI,EAAE,IAAI;YACV,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,QAAQ,EAAE,QAAQ,CACd,UAAU,EACV,OAAO,CAAC,QAAQ,CACnB;YACD,MAAM,EAAE,0BAA0B;SACrC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC,CAAC;AACR,CAAC"}
|
package/dist/gpf/urbanisme.d.ts
CHANGED
|
@@ -3,16 +3,18 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @param {number} lon
|
|
5
5
|
* @param {number} lat
|
|
6
|
+
* @param {(url: string) => Promise<any>} [fetcher]
|
|
6
7
|
* @returns
|
|
7
8
|
*/
|
|
8
|
-
export function getUrbanisme(lon: number, lat: number): Promise<any>;
|
|
9
|
+
export function getUrbanisme(lon: number, lat: number, fetcher?: (url: string) => Promise<any>): Promise<any>;
|
|
9
10
|
/**
|
|
10
11
|
* Get SUP infos for a given location
|
|
11
12
|
*
|
|
12
13
|
* @param {number} lon
|
|
13
14
|
* @param {number} lat
|
|
15
|
+
* @param {(url: string) => Promise<any>} [fetcher]
|
|
14
16
|
* @returns
|
|
15
17
|
*/
|
|
16
|
-
export function getAssiettesServitudes(lon: number, lat: number): Promise<any>;
|
|
18
|
+
export function getAssiettesServitudes(lon: number, lat: number, fetcher?: (url: string) => Promise<any>): Promise<any>;
|
|
17
19
|
export const URBANISME_TYPES: string[];
|
|
18
20
|
export const URBANISME_SOURCE: "G\u00E9oplateforme - (WFS G\u00E9oportail de l'Urbanisme)";
|
package/dist/gpf/urbanisme.js
CHANGED
|
@@ -15,14 +15,33 @@ export const URBANISME_TYPES = [
|
|
|
15
15
|
'wfs_du:prescription_surf'
|
|
16
16
|
];
|
|
17
17
|
export const URBANISME_SOURCE = "Géoplateforme - (WFS Géoportail de l'Urbanisme)";
|
|
18
|
+
const URBANISME_INVALID_COLLECTION_ERROR = "Le service Urbanisme n'a pas retourné de collection d'objets exploitable";
|
|
19
|
+
const URBANISME_EXCLUDED_PROPERTIES = new Set([
|
|
20
|
+
'gpu_status',
|
|
21
|
+
'urlfic'
|
|
22
|
+
]);
|
|
23
|
+
function sanitizeUrbanismeItem(item) {
|
|
24
|
+
const sanitized = {};
|
|
25
|
+
for (const [key, value] of Object.entries(item)) {
|
|
26
|
+
if (URBANISME_EXCLUDED_PROPERTIES.has(key)) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (value === null || value === '') {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
sanitized[key] = value;
|
|
33
|
+
}
|
|
34
|
+
return sanitized;
|
|
35
|
+
}
|
|
18
36
|
/**
|
|
19
37
|
* Get urbanism infos for a given location
|
|
20
38
|
*
|
|
21
39
|
* @param {number} lon
|
|
22
40
|
* @param {number} lat
|
|
41
|
+
* @param {(url: string) => Promise<any>} [fetcher]
|
|
23
42
|
* @returns
|
|
24
43
|
*/
|
|
25
|
-
export async function getUrbanisme(lon, lat) {
|
|
44
|
+
export async function getUrbanisme(lon, lat, fetcher = fetchJSON) {
|
|
26
45
|
logger.info(`getUrbanisme(${lon},${lat})...`);
|
|
27
46
|
// note that EPSG:4326 means lat,lon order for GeoServer -> flipped coordinates...
|
|
28
47
|
const cql_filter = `DWITHIN(the_geom,Point(${lat} ${lon}),30,meters)`;
|
|
@@ -38,17 +57,21 @@ export async function getUrbanisme(lon, lat) {
|
|
|
38
57
|
outputFormat: 'application/json',
|
|
39
58
|
cql_filter: cql_filter
|
|
40
59
|
}).toString();
|
|
41
|
-
const featureCollection = await
|
|
60
|
+
const featureCollection = await fetcher(url);
|
|
61
|
+
if (!Array.isArray(featureCollection?.features)) {
|
|
62
|
+
throw new Error(URBANISME_INVALID_COLLECTION_ERROR);
|
|
63
|
+
}
|
|
42
64
|
return featureCollection.features.map((feature) => {
|
|
43
65
|
// parse type from id (ex: "commune.3837")
|
|
44
66
|
const type = feature.id.split('.')[0];
|
|
45
67
|
// ignore geometry and extend properties
|
|
46
|
-
|
|
68
|
+
const item = Object.assign({
|
|
47
69
|
type: type,
|
|
48
70
|
id: feature.id,
|
|
49
71
|
bbox: feature.bbox,
|
|
50
72
|
distance: (distance(sourceGeom, feature.geometry) * 1000.0)
|
|
51
73
|
}, feature.properties);
|
|
74
|
+
return sanitizeUrbanismeItem(item);
|
|
52
75
|
});
|
|
53
76
|
}
|
|
54
77
|
const ASSIETTES_SUP_TYPES = [
|
|
@@ -61,9 +84,10 @@ const ASSIETTES_SUP_TYPES = [
|
|
|
61
84
|
*
|
|
62
85
|
* @param {number} lon
|
|
63
86
|
* @param {number} lat
|
|
87
|
+
* @param {(url: string) => Promise<any>} [fetcher]
|
|
64
88
|
* @returns
|
|
65
89
|
*/
|
|
66
|
-
export async function getAssiettesServitudes(lon, lat) {
|
|
90
|
+
export async function getAssiettesServitudes(lon, lat, fetcher = fetchJSON) {
|
|
67
91
|
logger.info(`getAssiettesServitudes(${lon},${lat})...`);
|
|
68
92
|
// note that EPSG:4326 means lat,lon order for GeoServer -> flipped coordinates...
|
|
69
93
|
const cql_filter = `DWITHIN(the_geom,Point(${lat} ${lon}),30,meters)`;
|
|
@@ -79,7 +103,10 @@ export async function getAssiettesServitudes(lon, lat) {
|
|
|
79
103
|
outputFormat: 'application/json',
|
|
80
104
|
cql_filter: cql_filter
|
|
81
105
|
}).toString();
|
|
82
|
-
const featureCollection = await
|
|
106
|
+
const featureCollection = await fetcher(url);
|
|
107
|
+
if (!Array.isArray(featureCollection?.features)) {
|
|
108
|
+
throw new Error(URBANISME_INVALID_COLLECTION_ERROR);
|
|
109
|
+
}
|
|
83
110
|
return featureCollection.features.map((feature) => {
|
|
84
111
|
// parse type from id (ex: "commune.3837")
|
|
85
112
|
const type = feature.id.split('.')[0];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"urbanisme.js","sourceRoot":"","sources":["../../src/gpf/urbanisme.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"urbanisme.js","sourceRoot":"","sources":["../../src/gpf/urbanisme.js"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,wBAAwB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,MAAM,MAAM,cAAc,CAAC;AAElC,kFAAkF;AAClF,MAAM,CAAC,MAAM,eAAe,GAAG;IAC3B,eAAe;IACf,iBAAiB;IACjB,kBAAkB;IAClB,mBAAmB;IACnB,iBAAiB;IACjB,iBAAiB;IACjB,kBAAkB;IAClB,yBAAyB;IACzB,yBAAyB;IACzB,0BAA0B;CAC7B,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,iDAAiD,CAAC;AAClF,MAAM,kCAAkC,GAAG,0EAA0E,CAAC;AAEtH,MAAM,6BAA6B,GAAG,IAAI,GAAG,CAAC;IAC1C,YAAY;IACZ,QAAQ;CACX,CAAC,CAAC;AAEH,SAAS,qBAAqB,CAAC,IAAI;IAC/B,MAAM,SAAS,GAAG,EAAE,CAAC;IACrB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9C,IAAI,6BAA6B,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACzC,SAAS;QACb,CAAC;QACD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YACjC,SAAS;QACb,CAAC;QACD,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAC3B,CAAC;IACD,OAAO,SAAS,CAAC;AACrB,CAAC;AAGD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,GAAG,SAAS;IAC5D,MAAM,CAAC,IAAI,CAAC,gBAAgB,GAAG,IAAI,GAAG,MAAM,CAAC,CAAC;IAE9C,kFAAkF;IAClF,MAAM,UAAU,GAAG,0BAA0B,GAAG,IAAI,GAAG,cAAc,CAAC;IAEtE,MAAM,UAAU,GAAG;QACf,MAAM,EAAE,OAAO;QACf,aAAa,EAAE,CAAC,GAAG,EAAC,GAAG,CAAC;KAC3B,CAAC;IAEF,uDAAuD;IACvD,MAAM,GAAG,GAAG,4BAA4B,GAAG,IAAI,eAAe,CAAC;QAC3D,OAAO,EAAE,KAAK;QACd,OAAO,EAAE,YAAY;QACrB,QAAQ,EAAE,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC;QACnC,YAAY,EAAE,kBAAkB;QAChC,UAAU,EAAE,UAAU;KACzB,CAAC,CAAC,QAAQ,EAAE,CAAC;IAEd,MAAM,iBAAiB,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,iBAAiB,EAAE,QAAQ,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,iBAAiB,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QAC9C,0CAA0C;QAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACtC,wCAAwC;QACxC,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC;YACvB,IAAI,EAAE,IAAI;YACV,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,QAAQ,EAAE,CAAC,QAAQ,CACf,UAAU,EACV,OAAO,CAAC,QAAQ,CACnB,GAAG,MAAM,CAAC;SACd,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACvB,OAAO,qBAAqB,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACP,CAAC;AAED,MAAM,mBAAmB,GAAG;IACxB,wBAAwB;IACxB,wBAAwB;IACxB,wBAAwB;CAC3B,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,GAAG,SAAS;IACtE,MAAM,CAAC,IAAI,CAAC,0BAA0B,GAAG,IAAI,GAAG,MAAM,CAAC,CAAC;IAExD,kFAAkF;IAClF,MAAM,UAAU,GAAG,0BAA0B,GAAG,IAAI,GAAG,cAAc,CAAC;IAEtE,MAAM,UAAU,GAAG;QACf,MAAM,EAAE,OAAO;QACf,aAAa,EAAE,CAAC,GAAG,EAAC,GAAG,CAAC;KAC3B,CAAC;IAEF,uDAAuD;IACvD,MAAM,GAAG,GAAG,4BAA4B,GAAG,IAAI,eAAe,CAAC;QAC3D,OAAO,EAAE,KAAK;QACd,OAAO,EAAE,YAAY;QACrB,QAAQ,EAAE,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC;QACvC,YAAY,EAAE,kBAAkB;QAChC,UAAU,EAAE,UAAU;KACzB,CAAC,CAAC,QAAQ,EAAE,CAAC;IAEd,MAAM,iBAAiB,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,iBAAiB,EAAE,QAAQ,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,iBAAiB,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QAC9C,0CAA0C;QAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACtC,wCAAwC;QACxC,OAAO,MAAM,CAAC,MAAM,CAAC;YACjB,IAAI,EAAE,IAAI;YACV,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,QAAQ,EAAE,CAAC,QAAQ,CACf,UAAU,EACV,OAAO,CAAC,QAAQ,CACnB,GAAG,MAAM,CAAC;SACd,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;AACP,CAAC"}
|
package/dist/gpf/wfs.d.ts
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import { Collection,
|
|
1
|
+
import { Collection, MiniSearchCollectionSearchOptions } from '@ignfab/gpf-schema-store';
|
|
2
2
|
export declare const GPF_WFS_URL = "https://data.geopf.fr/wfs";
|
|
3
|
+
type MiniSearchOptions = MiniSearchCollectionSearchOptions;
|
|
3
4
|
export declare class FeatureTypeNotFoundError extends Error {
|
|
4
5
|
constructor(name: string);
|
|
5
6
|
}
|
|
6
|
-
export declare function
|
|
7
|
+
export declare function loadMiniSearchOptionsFromEnv(): MiniSearchOptions | undefined;
|
|
7
8
|
export declare class WfsClient {
|
|
8
9
|
baseUrl: string;
|
|
9
10
|
private readonly catalog;
|
|
10
11
|
constructor(baseUrl?: string, options?: {
|
|
11
|
-
|
|
12
|
+
miniSearch?: MiniSearchOptions;
|
|
12
13
|
});
|
|
13
14
|
getFeatureTypes(): Promise<Collection[]>;
|
|
14
15
|
searchFeatureTypes(query: string, maxResults?: number): Promise<Collection[]>;
|
|
15
16
|
getFeatureType(name: string): Promise<Collection>;
|
|
16
17
|
}
|
|
17
18
|
export declare const wfsClient: WfsClient;
|
|
19
|
+
export {};
|
package/dist/gpf/wfs.js
CHANGED
|
@@ -2,22 +2,28 @@
|
|
|
2
2
|
import { getCollectionCatalog, MiniSearchCollectionSearchEngine, } from '@ignfab/gpf-schema-store';
|
|
3
3
|
// --- Constants ---
|
|
4
4
|
export const GPF_WFS_URL = "https://data.geopf.fr/wfs";
|
|
5
|
-
// Environment variable used to inject
|
|
6
|
-
const
|
|
5
|
+
// Environment variable used to inject MiniSearch options at runtime (JSON string).
|
|
6
|
+
const GPF_WFS_MINISEARCH_OPTIONS_ENV = "GPF_WFS_MINISEARCH_OPTIONS";
|
|
7
7
|
// Keys accepted at the top level of the search options object.
|
|
8
|
-
const
|
|
9
|
-
//
|
|
10
|
-
const
|
|
8
|
+
const TOP_LEVEL_MINISEARCH_OPTION_KEYS = ["fields", "combineWith", "fuzzy", "boost"];
|
|
9
|
+
// Shared keys used by both `fields` and `boost` in MiniSearchCollectionSearchOptions.
|
|
10
|
+
const MINISEARCH_INDEXED_OPTION_KEYS = [
|
|
11
11
|
"namespace",
|
|
12
12
|
"name",
|
|
13
13
|
"title",
|
|
14
14
|
"description",
|
|
15
15
|
"properties",
|
|
16
|
+
"enums",
|
|
17
|
+
"identifierTokens",
|
|
16
18
|
];
|
|
19
|
+
const MINISEARCH_FIELD_OPTION_KEYS = MINISEARCH_INDEXED_OPTION_KEYS;
|
|
20
|
+
const MINISEARCH_COMBINE_WITH_VALUES = ["AND", "OR"];
|
|
21
|
+
const MINISEARCH_BOOST_OPTION_KEYS = MINISEARCH_INDEXED_OPTION_KEYS;
|
|
17
22
|
// --- Errors ---
|
|
18
23
|
export class FeatureTypeNotFoundError extends Error {
|
|
19
24
|
constructor(name) {
|
|
20
|
-
super(`
|
|
25
|
+
super(`Le type '${name}' est introuvable`);
|
|
26
|
+
this.name = "FeatureTypeNotFoundError";
|
|
21
27
|
}
|
|
22
28
|
}
|
|
23
29
|
// --- Helpers ---
|
|
@@ -28,21 +34,47 @@ function isFiniteNumber(value) {
|
|
|
28
34
|
return typeof value === "number" && Number.isFinite(value);
|
|
29
35
|
}
|
|
30
36
|
function invalidSearchOptionsError(reason) {
|
|
31
|
-
return new Error(`Invalid ${
|
|
37
|
+
return new Error(`Invalid ${GPF_WFS_MINISEARCH_OPTIONS_ENV}: ${reason}`);
|
|
32
38
|
}
|
|
33
39
|
// --- Search options parsing ---
|
|
34
|
-
// Parses and validates a plain-object value into
|
|
40
|
+
// Parses and validates a plain-object value into MiniSearchCollectionSearchOptions.
|
|
35
41
|
// Throws a descriptive error if the value has unexpected keys or wrong value types.
|
|
36
|
-
function
|
|
42
|
+
function parseMiniSearchOptions(value) {
|
|
37
43
|
if (!isPlainObject(value)) {
|
|
38
44
|
throw invalidSearchOptionsError("expected a JSON object");
|
|
39
45
|
}
|
|
40
46
|
for (const key of Object.keys(value)) {
|
|
41
|
-
if (!
|
|
47
|
+
if (!TOP_LEVEL_MINISEARCH_OPTION_KEYS.includes(key)) {
|
|
42
48
|
throw invalidSearchOptionsError(`unexpected key '${key}'`);
|
|
43
49
|
}
|
|
44
50
|
}
|
|
45
51
|
const options = {};
|
|
52
|
+
if (value.fields !== undefined) {
|
|
53
|
+
if (!Array.isArray(value.fields)) {
|
|
54
|
+
throw invalidSearchOptionsError("expected 'fields' to be an array");
|
|
55
|
+
}
|
|
56
|
+
const fields = [];
|
|
57
|
+
for (const field of value.fields) {
|
|
58
|
+
if (typeof field !== "string") {
|
|
59
|
+
throw invalidSearchOptionsError("expected every 'fields' item to be a string");
|
|
60
|
+
}
|
|
61
|
+
if (!MINISEARCH_FIELD_OPTION_KEYS.includes(field)) {
|
|
62
|
+
throw invalidSearchOptionsError(`unexpected value 'fields.${field}'`);
|
|
63
|
+
}
|
|
64
|
+
fields.push(field);
|
|
65
|
+
}
|
|
66
|
+
options.fields = fields;
|
|
67
|
+
}
|
|
68
|
+
if (value.combineWith !== undefined) {
|
|
69
|
+
if (typeof value.combineWith !== "string") {
|
|
70
|
+
throw invalidSearchOptionsError("expected 'combineWith' to be a string");
|
|
71
|
+
}
|
|
72
|
+
const combineWith = value.combineWith;
|
|
73
|
+
if (!MINISEARCH_COMBINE_WITH_VALUES.includes(combineWith)) {
|
|
74
|
+
throw invalidSearchOptionsError("expected 'combineWith' to be 'AND' or 'OR'");
|
|
75
|
+
}
|
|
76
|
+
options.combineWith = combineWith;
|
|
77
|
+
}
|
|
46
78
|
if (value.fuzzy !== undefined) {
|
|
47
79
|
if (!isFiniteNumber(value.fuzzy)) {
|
|
48
80
|
throw invalidSearchOptionsError("expected 'fuzzy' to be a finite number");
|
|
@@ -55,7 +87,7 @@ function parseSearchOptions(value) {
|
|
|
55
87
|
}
|
|
56
88
|
const boost = {};
|
|
57
89
|
for (const key of Object.keys(value.boost)) {
|
|
58
|
-
if (!
|
|
90
|
+
if (!MINISEARCH_BOOST_OPTION_KEYS.includes(key)) {
|
|
59
91
|
throw invalidSearchOptionsError(`unexpected key 'boost.${key}'`);
|
|
60
92
|
}
|
|
61
93
|
const rawScore = value.boost[key];
|
|
@@ -68,10 +100,18 @@ function parseSearchOptions(value) {
|
|
|
68
100
|
}
|
|
69
101
|
return options;
|
|
70
102
|
}
|
|
71
|
-
|
|
103
|
+
function createMiniSearchEngineOptions(miniSearch) {
|
|
104
|
+
if (!miniSearch) {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
defaultSearchOptions: miniSearch,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
// Reads MiniSearch options from the GPF_WFS_MINISEARCH_OPTIONS environment variable.
|
|
72
112
|
// Returns undefined when the variable is absent or empty.
|
|
73
|
-
export function
|
|
74
|
-
const rawValue = process.env[
|
|
113
|
+
export function loadMiniSearchOptionsFromEnv() {
|
|
114
|
+
const rawValue = process.env[GPF_WFS_MINISEARCH_OPTIONS_ENV];
|
|
75
115
|
if (!rawValue || rawValue.trim() === "") {
|
|
76
116
|
return undefined;
|
|
77
117
|
}
|
|
@@ -83,7 +123,7 @@ export function loadSearchOptionsFromEnv() {
|
|
|
83
123
|
const reason = error instanceof Error ? error.message : "unknown JSON parse error";
|
|
84
124
|
throw invalidSearchOptionsError(`expected valid JSON (${reason})`);
|
|
85
125
|
}
|
|
86
|
-
return
|
|
126
|
+
return parseMiniSearchOptions(parsedValue);
|
|
87
127
|
}
|
|
88
128
|
// --- WFS client ---
|
|
89
129
|
export class WfsClient {
|
|
@@ -91,8 +131,9 @@ export class WfsClient {
|
|
|
91
131
|
catalog;
|
|
92
132
|
constructor(baseUrl = GPF_WFS_URL, options = {}) {
|
|
93
133
|
this.baseUrl = baseUrl;
|
|
134
|
+
const searchEngineOptions = createMiniSearchEngineOptions(options.miniSearch);
|
|
94
135
|
this.catalog = getCollectionCatalog({
|
|
95
|
-
engineFactory: (items) => new MiniSearchCollectionSearchEngine(items,
|
|
136
|
+
engineFactory: (items) => new MiniSearchCollectionSearchEngine(items, searchEngineOptions),
|
|
96
137
|
});
|
|
97
138
|
}
|
|
98
139
|
async getFeatureTypes() {
|
|
@@ -101,7 +142,6 @@ export class WfsClient {
|
|
|
101
142
|
async searchFeatureTypes(query, maxResults = 20) {
|
|
102
143
|
return this.catalog.search(query, {
|
|
103
144
|
limit: maxResults,
|
|
104
|
-
combineWith: 'AND',
|
|
105
145
|
});
|
|
106
146
|
}
|
|
107
147
|
async getFeatureType(name) {
|
|
@@ -113,8 +153,8 @@ export class WfsClient {
|
|
|
113
153
|
}
|
|
114
154
|
}
|
|
115
155
|
// --- Default singleton ---
|
|
116
|
-
// Pre-configured client using the default GPF endpoint and optional env-based
|
|
156
|
+
// Pre-configured client using the default GPF endpoint and optional env-based MiniSearch options.
|
|
117
157
|
export const wfsClient = new WfsClient(undefined, {
|
|
118
|
-
|
|
158
|
+
miniSearch: loadMiniSearchOptionsFromEnv(),
|
|
119
159
|
});
|
|
120
160
|
//# sourceMappingURL=wfs.js.map
|