@honua/react 0.1.0-beta.0 → 0.1.2-beta.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/contract/discovery.d.ts +231 -0
- package/contract/discovery.d.ts.map +1 -0
- package/contract/discovery.js +554 -0
- package/contract/edit-sketch.d.ts +8 -0
- package/contract/edit-sketch.d.ts.map +1 -1
- package/contract/edit-sketch.js +15 -0
- package/contract/edit-snapping.d.ts +160 -0
- package/contract/edit-snapping.d.ts.map +1 -0
- package/contract/edit-snapping.js +675 -0
- package/contract/generated/projjson-v0.7-crs-validator.d.ts +35 -0
- package/contract/generated/projjson-v0.7-crs-validator.d.ts.map +1 -0
- package/contract/generated/projjson-v0.7-crs-validator.js +3941 -0
- package/contract/index.d.ts +11 -2
- package/contract/index.d.ts.map +1 -1
- package/contract/index.js +4 -1
- package/contract/pmtiles.d.ts +31 -0
- package/contract/pmtiles.d.ts.map +1 -1
- package/contract/pmtiles.js +60 -20
- package/contract/protocol-module.d.ts +70 -0
- package/contract/protocol-module.d.ts.map +1 -0
- package/contract/protocol-module.js +1 -0
- package/contract/schema-envelope.d.ts +26 -0
- package/contract/schema-envelope.d.ts.map +1 -0
- package/contract/schema-envelope.js +25 -0
- package/contract/schema.d.ts +582 -0
- package/contract/schema.d.ts.map +1 -0
- package/contract/schema.js +2483 -0
- package/contract/source-capability-support.d.ts +6 -0
- package/contract/source-capability-support.d.ts.map +1 -0
- package/contract/source-capability-support.js +154 -0
- package/contract/source.d.ts +35 -17
- package/contract/source.d.ts.map +1 -1
- package/contract/source.js +267 -71
- package/contract/types.d.ts +140 -4
- package/contract/types.d.ts.map +1 -1
- package/contract/types.js +6 -14
- package/core/bounded-json.d.ts +4 -0
- package/core/bounded-json.d.ts.map +1 -0
- package/core/bounded-json.js +38 -0
- package/core/cache-state.d.ts +9 -0
- package/core/cache-state.d.ts.map +1 -1
- package/core/cache-state.js +10 -0
- package/core/capabilities-xml.d.ts +33 -0
- package/core/capabilities-xml.d.ts.map +1 -0
- package/core/capabilities-xml.js +331 -0
- package/core/client.d.ts +4 -1
- package/core/client.d.ts.map +1 -1
- package/core/client.js +115 -29
- package/core/error-classifications.d.ts +153 -0
- package/core/error-classifications.d.ts.map +1 -0
- package/core/error-classifications.js +140 -0
- package/core/error-code-registry.d.ts +158 -0
- package/core/error-code-registry.d.ts.map +1 -0
- package/core/error-code-registry.js +143 -0
- package/core/error-envelope.d.ts +68 -0
- package/core/error-envelope.d.ts.map +1 -0
- package/core/error-envelope.js +357 -0
- package/core/errors.d.ts +45 -29
- package/core/errors.d.ts.map +1 -1
- package/core/errors.js +97 -50
- package/core/geoparquet-sql.d.ts +30 -2
- package/core/geoparquet-sql.d.ts.map +1 -1
- package/core/geoparquet-sql.js +38 -3
- package/core/odata-key-path.d.ts +12 -0
- package/core/odata-key-path.d.ts.map +1 -0
- package/core/odata-key-path.js +28 -0
- package/core/odata-write-codec.d.ts +66 -0
- package/core/odata-write-codec.d.ts.map +1 -0
- package/core/odata-write-codec.js +1083 -0
- package/core/odata.d.ts +59 -7
- package/core/odata.d.ts.map +1 -1
- package/core/odata.js +431 -99
- package/core/ogc-features.d.ts.map +1 -1
- package/core/ogc-features.js +3 -0
- package/core/ogc-maps.d.ts +7 -0
- package/core/ogc-maps.d.ts.map +1 -1
- package/core/ogc-maps.js +46 -7
- package/core/ogc-processes.d.ts +2 -1
- package/core/ogc-processes.d.ts.map +1 -1
- package/core/ogc-processes.js +33 -5
- package/core/ogc-records.d.ts +9 -0
- package/core/ogc-records.d.ts.map +1 -1
- package/core/ogc-records.js +78 -29
- package/core/ogc-tiles.d.ts +10 -1
- package/core/ogc-tiles.d.ts.map +1 -1
- package/core/ogc-tiles.js +56 -17
- package/core/path-utils.d.ts +9 -0
- package/core/path-utils.d.ts.map +1 -1
- package/core/path-utils.js +19 -0
- package/core/protocol-transport.d.ts +1 -0
- package/core/protocol-transport.d.ts.map +1 -1
- package/core/request-pipeline.d.ts.map +1 -1
- package/core/request-pipeline.js +1 -1
- package/core/spatial-filter.d.ts +8 -4
- package/core/spatial-filter.d.ts.map +1 -1
- package/core/spatial-filter.js +206 -16
- package/core/stac-static.d.ts +6 -2
- package/core/stac-static.d.ts.map +1 -1
- package/core/stac-static.js +260 -69
- package/core/surfaces.d.ts.map +1 -1
- package/core/surfaces.js +69 -5
- package/core/types.d.ts +125 -7
- package/core/types.d.ts.map +1 -1
- package/core/wfs-capabilities.d.ts +2 -0
- package/core/wfs-capabilities.d.ts.map +1 -1
- package/core/wfs-capabilities.js +8 -1
- package/core/wfs.d.ts.map +1 -1
- package/core/wfs.js +10 -0
- package/core/wms-capabilities.d.ts +56 -84
- package/core/wms-capabilities.d.ts.map +1 -1
- package/core/wms-capabilities.js +212 -509
- package/core/wmts-capabilities.d.ts +62 -62
- package/core/wmts-capabilities.d.ts.map +1 -1
- package/core/wmts-capabilities.js +224 -371
- package/esri-compat/editor.d.ts +8 -0
- package/esri-compat/editor.d.ts.map +1 -1
- package/esri-compat/editor.js +13 -0
- package/esri-compat/feature-layer.d.ts +2 -0
- package/esri-compat/feature-layer.d.ts.map +1 -1
- package/esri-compat/feature-layer.js +1 -0
- package/esri-compat/layer-list.d.ts +11 -0
- package/esri-compat/layer-list.d.ts.map +1 -1
- package/esri-compat/layer-list.js +49 -0
- package/esri-compat/legend.d.ts +10 -0
- package/esri-compat/legend.d.ts.map +1 -1
- package/esri-compat/legend.js +27 -0
- package/esri-compat/portal.d.ts +197 -0
- package/esri-compat/portal.d.ts.map +1 -0
- package/esri-compat/portal.js +251 -0
- package/esri-compat/renderer-objects.d.ts +40 -0
- package/esri-compat/renderer-objects.d.ts.map +1 -0
- package/esri-compat/renderer-objects.js +62 -0
- package/esri-compat/sketch.d.ts +43 -0
- package/esri-compat/sketch.d.ts.map +1 -1
- package/esri-compat/sketch.js +46 -0
- package/esri-compat/snapping.d.ts +43 -0
- package/esri-compat/snapping.d.ts.map +1 -0
- package/esri-compat/snapping.js +45 -0
- package/esri-compat/url.d.ts.map +1 -1
- package/esri-compat/url.js +1 -1
- package/esri-compat/widget-host.d.ts +84 -0
- package/esri-compat/widget-host.d.ts.map +1 -0
- package/esri-compat/widget-host.js +159 -0
- package/filter-registry/index.d.ts +145 -0
- package/filter-registry/index.d.ts.map +1 -0
- package/filter-registry/index.js +531 -0
- package/generated-app/errors.d.ts +18 -2
- package/generated-app/errors.d.ts.map +1 -1
- package/generated-app/errors.js +44 -11
- package/map/automatic-mount-integration.d.ts +134 -0
- package/map/automatic-mount-integration.d.ts.map +1 -0
- package/map/automatic-mount-integration.js +305 -0
- package/map/automatic-source-strategy.d.ts +125 -0
- package/map/automatic-source-strategy.d.ts.map +1 -0
- package/map/automatic-source-strategy.js +494 -0
- package/map/data-to-map-bridge.d.ts +293 -0
- package/map/data-to-map-bridge.d.ts.map +1 -0
- package/map/data-to-map-bridge.js +817 -0
- package/map/geojson-projection.d.ts +33 -0
- package/map/geojson-projection.d.ts.map +1 -0
- package/map/geojson-projection.js +118 -0
- package/map/index.d.ts +14 -0
- package/map/index.d.ts.map +1 -1
- package/map/index.js +8 -0
- package/map/raster-source-spec.d.ts +30 -0
- package/map/raster-source-spec.d.ts.map +1 -0
- package/map/raster-source-spec.js +190 -0
- package/map/raster-source-strategy.d.ts +65 -0
- package/map/raster-source-strategy.d.ts.map +1 -0
- package/map/raster-source-strategy.js +232 -0
- package/map/source-to-maplibre.d.ts +91 -0
- package/map/source-to-maplibre.d.ts.map +1 -0
- package/map/source-to-maplibre.js +454 -0
- package/map/temporal-playback.d.ts +139 -0
- package/map/temporal-playback.d.ts.map +1 -0
- package/map/temporal-playback.js +247 -0
- package/package.json +14 -1
- package/query-planner/canonical.d.ts +7 -0
- package/query-planner/canonical.d.ts.map +1 -0
- package/query-planner/canonical.js +145 -0
- package/query-planner/cql2-json.d.ts +17 -0
- package/query-planner/cql2-json.d.ts.map +1 -0
- package/query-planner/cql2-json.js +646 -0
- package/query-planner/diagnostics.d.ts +35 -0
- package/query-planner/diagnostics.d.ts.map +1 -0
- package/query-planner/diagnostics.js +373 -0
- package/query-planner/duckdb.d.ts +79 -0
- package/query-planner/duckdb.d.ts.map +1 -0
- package/query-planner/duckdb.js +758 -0
- package/query-planner/execution-context.d.ts +5 -0
- package/query-planner/execution-context.d.ts.map +1 -0
- package/query-planner/execution-context.js +50 -0
- package/query-planner/executor.d.ts +5 -0
- package/query-planner/executor.d.ts.map +1 -0
- package/query-planner/executor.js +223 -0
- package/query-planner/geoservices.d.ts +91 -0
- package/query-planner/geoservices.d.ts.map +1 -0
- package/query-planner/geoservices.js +667 -0
- package/query-planner/grpc.d.ts +100 -0
- package/query-planner/grpc.d.ts.map +1 -0
- package/query-planner/grpc.js +736 -0
- package/query-planner/index.d.ts +44 -0
- package/query-planner/index.d.ts.map +1 -0
- package/query-planner/index.js +30 -0
- package/query-planner/ir.d.ts +20 -0
- package/query-planner/ir.d.ts.map +1 -0
- package/query-planner/ir.js +417 -0
- package/query-planner/local-aggregate.d.ts +5 -0
- package/query-planner/local-aggregate.d.ts.map +1 -0
- package/query-planner/local-aggregate.js +126 -0
- package/query-planner/odata.d.ts +48 -0
- package/query-planner/odata.d.ts.map +1 -0
- package/query-planner/odata.js +662 -0
- package/query-planner/ogc-compiler.d.ts +55 -0
- package/query-planner/ogc-compiler.d.ts.map +1 -0
- package/query-planner/ogc-compiler.js +480 -0
- package/query-planner/ogc-features.d.ts +53 -0
- package/query-planner/ogc-features.d.ts.map +1 -0
- package/query-planner/ogc-features.js +617 -0
- package/query-planner/planner.d.ts +17 -0
- package/query-planner/planner.d.ts.map +1 -0
- package/query-planner/planner.js +818 -0
- package/query-planner/resource.d.ts +94 -0
- package/query-planner/resource.d.ts.map +1 -0
- package/query-planner/resource.js +526 -0
- package/query-planner/semantic-canonical.d.ts +15 -0
- package/query-planner/semantic-canonical.d.ts.map +1 -0
- package/query-planner/semantic-canonical.js +62 -0
- package/query-planner/semantic-compat.d.ts +10 -0
- package/query-planner/semantic-compat.d.ts.map +1 -0
- package/query-planner/semantic-compat.js +35 -0
- package/query-planner/semantic-compiler.d.ts +64 -0
- package/query-planner/semantic-compiler.d.ts.map +1 -0
- package/query-planner/semantic-compiler.js +81 -0
- package/query-planner/semantic-literals.d.ts +30 -0
- package/query-planner/semantic-literals.d.ts.map +1 -0
- package/query-planner/semantic-literals.js +133 -0
- package/query-planner/semantic-types.d.ts +265 -0
- package/query-planner/semantic-types.d.ts.map +1 -0
- package/query-planner/semantic-types.js +1 -0
- package/query-planner/semantic.d.ts +54 -0
- package/query-planner/semantic.d.ts.map +1 -0
- package/query-planner/semantic.js +1421 -0
- package/query-planner/types.d.ts +560 -0
- package/query-planner/types.d.ts.map +1 -0
- package/query-planner/types.js +49 -0
- package/query-planner/wfs-semantic.d.ts +58 -0
- package/query-planner/wfs-semantic.d.ts.map +1 -0
- package/query-planner/wfs-semantic.js +547 -0
- package/query-planner/wfs.d.ts +6 -0
- package/query-planner/wfs.d.ts.map +1 -0
- package/query-planner/wfs.js +71 -0
- package/react/external-map.d.ts +67 -0
- package/react/external-map.d.ts.map +1 -0
- package/react/external-map.js +63 -0
- package/react/honua-map.d.ts.map +1 -1
- package/react/honua-map.js +3 -2
- package/react/honua-source-layer.d.ts +110 -0
- package/react/honua-source-layer.d.ts.map +1 -0
- package/react/honua-source-layer.js +101 -0
- package/react/hooks.d.ts +28 -0
- package/react/hooks.d.ts.map +1 -1
- package/react/hooks.js +26 -4
- package/react/index.d.ts +8 -0
- package/react/index.d.ts.map +1 -1
- package/react/index.js +5 -0
- package/react/query-cache.d.ts +26 -4
- package/react/query-cache.d.ts.map +1 -1
- package/react/query-cache.js +51 -8
- package/react/selection.d.ts +177 -0
- package/react/selection.d.ts.map +1 -0
- package/react/selection.js +0 -0
- package/react/use-mounted-source.d.ts +69 -0
- package/react/use-mounted-source.d.ts.map +1 -0
- package/react/use-mounted-source.js +346 -0
- package/runtime/edit-snapping.d.ts +107 -0
- package/runtime/edit-snapping.d.ts.map +1 -0
- package/runtime/edit-snapping.js +190 -0
- package/runtime/errors.d.ts +3 -2
- package/runtime/errors.d.ts.map +1 -1
- package/runtime/errors.js +19 -2
- package/runtime/index.d.ts +6 -0
- package/runtime/index.d.ts.map +1 -1
- package/runtime/index.js +3 -0
- package/runtime/maplibre-renderer.d.ts +41 -0
- package/runtime/maplibre-renderer.d.ts.map +1 -0
- package/runtime/maplibre-renderer.js +322 -0
- package/runtime/query-tiles.d.ts +2 -1
- package/runtime/query-tiles.d.ts.map +1 -1
- package/runtime/query-tiles.js +6 -2
- package/runtime/source-bridge.d.ts +4 -4
- package/runtime/source-bridge.d.ts.map +1 -1
- package/runtime/source-bridge.js +9 -56
- package/runtime/style-interactions.d.ts +3 -2
- package/runtime/style-interactions.d.ts.map +1 -1
- package/runtime/style-interactions.js +11 -3
- package/runtime/terra-draw-sketch.d.ts +275 -0
- package/runtime/terra-draw-sketch.d.ts.map +1 -0
- package/runtime/terra-draw-sketch.js +404 -0
- package/source-capability-registry.d.ts +1 -0
- package/source-capability-registry.js +1 -0
- package/source-capability-types.d.ts +186 -0
- package/source-capability-types.js +7 -0
- package/style/index.d.ts +2 -0
- package/style/index.d.ts.map +1 -1
- package/style/index.js +2 -0
- package/style/renderers.d.ts +326 -0
- package/style/renderers.d.ts.map +1 -0
- package/style/renderers.js +517 -0
- package/webmap/convert-renderer.d.ts +24 -3
- package/webmap/convert-renderer.d.ts.map +1 -1
- package/webmap/convert-renderer.js +93 -112
- package/webmap/index.d.ts +1 -1
- package/webmap/index.d.ts.map +1 -1
- package/webmap/index.js +1 -1
package/core/odata.js
CHANGED
|
@@ -15,7 +15,34 @@
|
|
|
15
15
|
* @module
|
|
16
16
|
*/
|
|
17
17
|
import { createHonuaCacheState, honuaCacheValidatorFromHeaders, honuaMetadataRequestHeaders, isHonuaCacheEntryFresh, normalizeHonuaMetadataRequestOptions, withHonuaCacheState, withoutHonuaCacheState, } from "./cache-state.js";
|
|
18
|
+
import { encodeOdataKeyPredicatePath } from "./odata-key-path.js";
|
|
18
19
|
import { trimTrailingSlashes } from "./path-utils.js";
|
|
20
|
+
const MAX_ODATA_METADATA_CHARACTERS = 4 * 1024 * 1024;
|
|
21
|
+
const ODATA_SOURCE_SCHEMA_PROJECTION_SAFETY = Symbol("honua.odata.source-schema-projection-safety");
|
|
22
|
+
const ODATA_SOURCE_SCHEMA_PROJECTION_DETAILS = Symbol("honua.odata.source-schema-projection-details");
|
|
23
|
+
/** @internal Read parser evidence without changing the legacy string-keyed metadata shape. */
|
|
24
|
+
export function getOdataSourceSchemaProjectionSafety(metadata) {
|
|
25
|
+
return odataProjectionEvidence(metadata, ODATA_SOURCE_SCHEMA_PROJECTION_SAFETY);
|
|
26
|
+
}
|
|
27
|
+
/** @internal Read rich CSDL state without changing the legacy string-keyed metadata shape. */
|
|
28
|
+
export function getOdataSourceSchemaProjectionDetails(metadata) {
|
|
29
|
+
return odataProjectionEvidence(metadata, ODATA_SOURCE_SCHEMA_PROJECTION_DETAILS);
|
|
30
|
+
}
|
|
31
|
+
function odataProjectionEvidence(metadata, key) {
|
|
32
|
+
let descriptor;
|
|
33
|
+
try {
|
|
34
|
+
descriptor = Object.getOwnPropertyDescriptor(metadata, key);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
throw new TypeError("OData metadata projection evidence is inaccessible");
|
|
38
|
+
}
|
|
39
|
+
if (!descriptor)
|
|
40
|
+
return undefined;
|
|
41
|
+
if (!("value" in descriptor)) {
|
|
42
|
+
throw new TypeError("OData metadata projection evidence must be a data property");
|
|
43
|
+
}
|
|
44
|
+
return descriptor.value;
|
|
45
|
+
}
|
|
19
46
|
// ── Runtime class ─────────────────────────────────────────────
|
|
20
47
|
/**
|
|
21
48
|
* Runtime handle for one OData entity set. Returned by
|
|
@@ -166,7 +193,7 @@ export class HonuaOdataEntitySet {
|
|
|
166
193
|
async add(body, options = {}) {
|
|
167
194
|
const path = this.entitySetPath();
|
|
168
195
|
return this.requestJson("POST", path, undefined, options.signal, JSON.stringify(body), {
|
|
169
|
-
"Content-Type": "application/json",
|
|
196
|
+
"Content-Type": options.contentType ?? "application/json",
|
|
170
197
|
});
|
|
171
198
|
}
|
|
172
199
|
/**
|
|
@@ -177,14 +204,14 @@ export class HonuaOdataEntitySet {
|
|
|
177
204
|
* `docs/protocol-capability-matrix.md` under the OData section).
|
|
178
205
|
*/
|
|
179
206
|
async update(key, body, options = {}) {
|
|
180
|
-
const path = `${this.entitySetPath()}(${
|
|
207
|
+
const path = `${this.entitySetPath()}(${encodeOdataKeyPredicatePath(key)})`;
|
|
181
208
|
return this.requestJson("PATCH", path, undefined, options.signal, JSON.stringify(body), {
|
|
182
|
-
"Content-Type": "application/json",
|
|
209
|
+
"Content-Type": options.contentType ?? "application/json",
|
|
183
210
|
});
|
|
184
211
|
}
|
|
185
212
|
/** Delete a row via `DELETE /<entitySet>(<key>)`. */
|
|
186
213
|
async delete(key, options = {}) {
|
|
187
|
-
const path = `${this.entitySetPath()}(${
|
|
214
|
+
const path = `${this.entitySetPath()}(${encodeOdataKeyPredicatePath(key)})`;
|
|
188
215
|
await this.requestJson("DELETE", path, undefined, options.signal);
|
|
189
216
|
}
|
|
190
217
|
/**
|
|
@@ -210,9 +237,7 @@ export class HonuaOdataEntitySet {
|
|
|
210
237
|
url: stripLeadingSlash(op.url),
|
|
211
238
|
...(op.headers
|
|
212
239
|
? { headers: { "Content-Type": "application/json", ...op.headers } }
|
|
213
|
-
: {
|
|
214
|
-
headers: { "Content-Type": "application/json" },
|
|
215
|
-
}),
|
|
240
|
+
: { headers: { "Content-Type": "application/json" } }),
|
|
216
241
|
...(op.body !== undefined ? { body: op.body } : {}),
|
|
217
242
|
...(groupId !== undefined ? { atomicityGroup: groupId } : {}),
|
|
218
243
|
}));
|
|
@@ -390,46 +415,6 @@ function ensureLeadingSlash(path) {
|
|
|
390
415
|
function stripLeadingSlash(path) {
|
|
391
416
|
return path.startsWith("/") ? path.slice(1) : path;
|
|
392
417
|
}
|
|
393
|
-
/**
|
|
394
|
-
* Make an OData entity key safe to interpolate into the URL path segment
|
|
395
|
-
* `<entitySet>(<key>)`. A raw key containing characters such as `&`, `?`,
|
|
396
|
-
* `#`, `/`, space, or `'` would otherwise split or mis-target the path
|
|
397
|
-
* (e.g. `Customers(A&B)`).
|
|
398
|
-
*
|
|
399
|
-
* The key is treated as an OData literal: single-quoted spans are kept as
|
|
400
|
-
* quoted string literals (with embedded `'` doubled per OData v4 §5.1.1.6.1),
|
|
401
|
-
* and structural characters that delimit composite keys (`,`, `=`) and
|
|
402
|
-
* literal quotes are preserved. Everything else is percent-encoded so the
|
|
403
|
-
* resulting segment is a single, correctly-targeted URL path component.
|
|
404
|
-
*/
|
|
405
|
-
function encodeOdataKey(key) {
|
|
406
|
-
const raw = String(key);
|
|
407
|
-
let out = "";
|
|
408
|
-
let inQuote = false;
|
|
409
|
-
for (let i = 0; i < raw.length; i += 1) {
|
|
410
|
-
const ch = raw[i];
|
|
411
|
-
if (ch === "'") {
|
|
412
|
-
// Toggle quoted-literal state and keep the (URL-safe) quote verbatim.
|
|
413
|
-
inQuote = !inQuote;
|
|
414
|
-
out += "'";
|
|
415
|
-
continue;
|
|
416
|
-
}
|
|
417
|
-
if (!inQuote && (ch === "," || ch === "=")) {
|
|
418
|
-
// Composite-key delimiters stay structural outside quoted spans.
|
|
419
|
-
out += ch;
|
|
420
|
-
continue;
|
|
421
|
-
}
|
|
422
|
-
// Percent-encode anything that is unsafe in a path segment. Unreserved
|
|
423
|
-
// characters (RFC 3986) pass through untouched.
|
|
424
|
-
if (/[A-Za-z0-9\-._~]/.test(ch)) {
|
|
425
|
-
out += ch;
|
|
426
|
-
}
|
|
427
|
-
else {
|
|
428
|
-
out += encodeURIComponent(ch);
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
return out;
|
|
432
|
-
}
|
|
433
418
|
/**
|
|
434
419
|
* Translate canonical query params onto the OData `$`-prefixed query
|
|
435
420
|
* string. Empty strings, undefined values, and zero-length lists are
|
|
@@ -491,18 +476,24 @@ function ensureTrailingSlash(url) {
|
|
|
491
476
|
* well-defined by OData CSDL §6 and the Honua Server spec page.
|
|
492
477
|
*/
|
|
493
478
|
export function parseOdataMetadata(xml) {
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
const
|
|
479
|
+
if (xml.length > MAX_ODATA_METADATA_CHARACTERS) {
|
|
480
|
+
throw new RangeError(`OData metadata exceeds ${MAX_ODATA_METADATA_CHARACTERS} characters`);
|
|
481
|
+
}
|
|
482
|
+
const entitySets = Object.create(null);
|
|
483
|
+
const keys = Object.create(null);
|
|
484
|
+
const fields = Object.create(null);
|
|
485
|
+
const projectionFields = Object.create(null);
|
|
486
|
+
const complexTypes = Object.create(null);
|
|
487
|
+
const enumTypes = Object.create(null);
|
|
488
|
+
const openTypes = Object.create(null);
|
|
489
|
+
const capabilities = Object.create(null);
|
|
498
490
|
// Sibling annotations: <Annotations Target="<schema>.<container>/<entitySet>">
|
|
499
491
|
// …</Annotations>. Honua Server emits Capabilities.* this way (next to
|
|
500
492
|
// the EntityContainer) rather than nesting them inside <EntitySet>, so
|
|
501
493
|
// capability negotiation must merge both shapes.
|
|
502
494
|
const siblingByEntitySet = new Map();
|
|
503
|
-
const
|
|
504
|
-
|
|
505
|
-
const attrs = match[1] ?? "";
|
|
495
|
+
for (const element of xmlElements(xml, "Annotations")) {
|
|
496
|
+
const attrs = element.attributes;
|
|
506
497
|
const target = readAttr(attrs, "Target");
|
|
507
498
|
if (!target)
|
|
508
499
|
continue;
|
|
@@ -512,20 +503,19 @@ export function parseOdataMetadata(xml) {
|
|
|
512
503
|
const setName = target.slice(slash + 1);
|
|
513
504
|
if (!setName)
|
|
514
505
|
continue;
|
|
515
|
-
const body =
|
|
506
|
+
const body = element.body;
|
|
516
507
|
const existing = siblingByEntitySet.get(setName);
|
|
517
508
|
siblingByEntitySet.set(setName, existing === undefined ? body : `${existing}\n${body}`);
|
|
518
509
|
}
|
|
519
510
|
// Entity sets: <EntitySet Name="Foo" EntityType="ns.FooEntity"/>
|
|
520
|
-
const
|
|
521
|
-
|
|
522
|
-
const attrs = match[1] ?? match[2] ?? "";
|
|
511
|
+
for (const element of xmlElements(xml, "EntitySet")) {
|
|
512
|
+
const attrs = element.attributes;
|
|
523
513
|
const name = readAttr(attrs, "Name");
|
|
524
514
|
const type = readAttr(attrs, "EntityType");
|
|
525
515
|
if (!name || !type)
|
|
526
516
|
continue;
|
|
527
517
|
entitySets[name] = stripNamespace(type);
|
|
528
|
-
const inlineBody =
|
|
518
|
+
const inlineBody = element.body;
|
|
529
519
|
const siblingBody = siblingByEntitySet.get(name) ?? "";
|
|
530
520
|
capabilities[name] = parseEntitySetAnnotations(`${inlineBody}\n${siblingBody}`);
|
|
531
521
|
siblingByEntitySet.delete(name);
|
|
@@ -537,48 +527,242 @@ export function parseOdataMetadata(xml) {
|
|
|
537
527
|
capabilities[setName] = parseEntitySetAnnotations(body);
|
|
538
528
|
}
|
|
539
529
|
// Entity types: <EntityType Name="FooEntity">…<Key><PropertyRef Name="Id"/></Key><Property…/>…</EntityType>
|
|
540
|
-
const
|
|
541
|
-
|
|
542
|
-
const
|
|
543
|
-
const body = match[2] ?? "";
|
|
530
|
+
for (const element of xmlElements(xml, "EntityType")) {
|
|
531
|
+
const attrs = element.attributes;
|
|
532
|
+
const body = element.body;
|
|
544
533
|
const name = readAttr(attrs, "Name");
|
|
545
534
|
if (!name)
|
|
546
535
|
continue;
|
|
536
|
+
if (readAttr(attrs, "OpenType")?.toLowerCase() === "true")
|
|
537
|
+
openTypes[name] = true;
|
|
547
538
|
const keyNames = [];
|
|
548
|
-
const keyBlock =
|
|
549
|
-
if (keyBlock) {
|
|
550
|
-
for (const
|
|
551
|
-
const refName = readAttr(
|
|
539
|
+
const keyBlock = xmlElements(body, "Key").next();
|
|
540
|
+
if (!keyBlock.done) {
|
|
541
|
+
for (const refAttrs of xmlStartTags(keyBlock.value.body, "PropertyRef")) {
|
|
542
|
+
const refName = readAttr(refAttrs, "Name");
|
|
552
543
|
if (refName)
|
|
553
544
|
keyNames.push(refName);
|
|
554
545
|
}
|
|
555
546
|
}
|
|
556
547
|
keys[name] = keyNames;
|
|
557
|
-
const
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
548
|
+
const richFields = parseOdataProperties(body);
|
|
549
|
+
projectionFields[name] = richFields;
|
|
550
|
+
fields[name] = richFields.map(legacyOdataFieldInfo);
|
|
551
|
+
}
|
|
552
|
+
for (const element of xmlElements(xml, "ComplexType")) {
|
|
553
|
+
const name = readAttr(element.attributes, "Name");
|
|
554
|
+
if (name)
|
|
555
|
+
complexTypes[name] = parseOdataProperties(element.body);
|
|
556
|
+
}
|
|
557
|
+
for (const element of xmlElements(xml, "EnumType")) {
|
|
558
|
+
const attrs = element.attributes;
|
|
559
|
+
const name = readAttr(attrs, "Name");
|
|
560
|
+
if (!name)
|
|
561
|
+
continue;
|
|
562
|
+
const underlyingType = readAttr(attrs, "UnderlyingType") ?? "Edm.Int32";
|
|
563
|
+
const isFlags = readAttr(attrs, "IsFlags")?.toLowerCase() === "true";
|
|
564
|
+
const declarations = [...xmlStartTags(element.body, "Member")].map((memberAttrs) => ({
|
|
565
|
+
name: readAttr(memberAttrs, "Name"),
|
|
566
|
+
rawValue: readAttr(memberAttrs, "Value"),
|
|
567
|
+
}));
|
|
568
|
+
const hasExplicit = declarations.some((member) => member.rawValue !== undefined);
|
|
569
|
+
const hasImplicit = declarations.some((member) => member.rawValue === undefined);
|
|
570
|
+
const valueMode = hasExplicit ? (hasImplicit ? "mixed" : "explicit") : "implicit";
|
|
571
|
+
let declarationReason;
|
|
572
|
+
const invalidate = (reason) => {
|
|
573
|
+
declarationReason ??= reason;
|
|
574
|
+
};
|
|
575
|
+
const bounds = odataEnumBounds(underlyingType);
|
|
576
|
+
if (declarations.length === 0)
|
|
577
|
+
invalidate("empty-declaration");
|
|
578
|
+
if (!bounds)
|
|
579
|
+
invalidate("invalid-underlying-type");
|
|
580
|
+
if (isFlags && hasImplicit)
|
|
581
|
+
invalidate("flags-require-explicit-values");
|
|
582
|
+
const members = [];
|
|
583
|
+
const names = new Set();
|
|
584
|
+
let previousValue;
|
|
585
|
+
for (const [index, declaration] of declarations.entries()) {
|
|
586
|
+
let parsed;
|
|
587
|
+
if (declaration.rawValue === undefined) {
|
|
588
|
+
if (!isFlags) {
|
|
589
|
+
parsed = index === 0 ? 0n : previousValue === undefined ? undefined : previousValue + 1n;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
else if (declaration.rawValue.length <= 20 && /^[+-]?\d+$/.test(declaration.rawValue)) {
|
|
593
|
+
try {
|
|
594
|
+
parsed = BigInt(declaration.rawValue);
|
|
595
|
+
}
|
|
596
|
+
catch {
|
|
597
|
+
parsed = undefined;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
if (parsed === undefined)
|
|
601
|
+
invalidate("invalid-member-value");
|
|
602
|
+
else if (isFlags && parsed < 0n)
|
|
603
|
+
invalidate("negative-flags-value");
|
|
604
|
+
else if (bounds && (parsed < bounds.minimum || parsed > bounds.maximum))
|
|
605
|
+
invalidate("out-of-range");
|
|
606
|
+
previousValue = parsed;
|
|
607
|
+
if (!declaration.name || !odataSimpleIdentifier(declaration.name)) {
|
|
608
|
+
invalidate("invalid-member-name");
|
|
609
|
+
continue;
|
|
610
|
+
}
|
|
611
|
+
if (names.has(declaration.name))
|
|
612
|
+
invalidate("duplicate-member-name");
|
|
613
|
+
names.add(declaration.name);
|
|
614
|
+
if (parsed === undefined)
|
|
563
615
|
continue;
|
|
564
|
-
const
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
616
|
+
const value = underlyingType === "Edm.Int64" || !Number.isSafeInteger(Number(parsed)) ? parsed.toString() : Number(parsed);
|
|
617
|
+
members.push({ name: declaration.name, value });
|
|
618
|
+
}
|
|
619
|
+
enumTypes[name] = {
|
|
620
|
+
underlyingType,
|
|
621
|
+
isFlags,
|
|
622
|
+
members,
|
|
623
|
+
declaration: declarationReason ? { state: "invalid", reason: declarationReason } : { state: "valid", valueMode },
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
const metadata = {
|
|
627
|
+
entitySets,
|
|
628
|
+
keys,
|
|
629
|
+
fields,
|
|
630
|
+
capabilities,
|
|
631
|
+
};
|
|
632
|
+
Object.defineProperty(metadata, ODATA_SOURCE_SCHEMA_PROJECTION_DETAILS, {
|
|
633
|
+
value: { fields: projectionFields, complexTypes, enumTypes, openTypes },
|
|
634
|
+
enumerable: true,
|
|
635
|
+
});
|
|
636
|
+
Object.defineProperty(metadata, ODATA_SOURCE_SCHEMA_PROJECTION_SAFETY, {
|
|
637
|
+
value: inspectOdataSourceSchemaProjectionSafety(xml),
|
|
638
|
+
enumerable: true,
|
|
639
|
+
});
|
|
640
|
+
return metadata;
|
|
641
|
+
}
|
|
642
|
+
function inspectOdataSourceSchemaProjectionSafety(xml) {
|
|
643
|
+
const edmxAttributes = firstXmlStartTagByLocalName(xml, "Edmx");
|
|
644
|
+
const csdlVersion = edmxAttributes === undefined ? undefined : readAttr(edmxAttributes, "Version");
|
|
645
|
+
const declarations = new Map();
|
|
646
|
+
const inheritedTypeNames = new Set();
|
|
647
|
+
const openComplexTypeNames = new Set();
|
|
648
|
+
const unqualifiedTypeNames = new Set();
|
|
649
|
+
for (const schema of xmlElements(xml, "Schema")) {
|
|
650
|
+
const namespace = readAttr(schema.attributes, "Namespace");
|
|
651
|
+
for (const kind of ["EntityType", "ComplexType", "EnumType"]) {
|
|
652
|
+
for (const attributes of xmlStartTags(schema.body, kind)) {
|
|
653
|
+
const name = readAttr(attributes, "Name");
|
|
654
|
+
if (!name)
|
|
655
|
+
continue;
|
|
656
|
+
const qualifiedIdentity = `${kind}:${namespace ? `${namespace}.${name}` : name}`;
|
|
657
|
+
const identities = declarations.get(name) ?? new Map();
|
|
658
|
+
identities.set(qualifiedIdentity, (identities.get(qualifiedIdentity) ?? 0) + 1);
|
|
659
|
+
declarations.set(name, identities);
|
|
660
|
+
if (!namespace)
|
|
661
|
+
unqualifiedTypeNames.add(name);
|
|
662
|
+
if (kind !== "EnumType" && readAttr(attributes, "BaseType"))
|
|
663
|
+
inheritedTypeNames.add(name);
|
|
664
|
+
if (kind === "ComplexType" && readAttr(attributes, "OpenType")?.toLowerCase() === "true") {
|
|
665
|
+
openComplexTypeNames.add(name);
|
|
666
|
+
}
|
|
576
667
|
}
|
|
577
|
-
props.push(info);
|
|
578
668
|
}
|
|
579
|
-
fields[name] = props;
|
|
580
669
|
}
|
|
581
|
-
|
|
670
|
+
const ambiguousTypeNames = [...declarations]
|
|
671
|
+
.filter(([, identities]) => identities.size > 1 || [...identities.values()].some((count) => count > 1))
|
|
672
|
+
.map(([name]) => name)
|
|
673
|
+
.sort();
|
|
674
|
+
return Object.freeze({
|
|
675
|
+
...(csdlVersion === undefined ? {} : { csdlVersion }),
|
|
676
|
+
ambiguousTypeNames: Object.freeze(ambiguousTypeNames),
|
|
677
|
+
inheritedTypeNames: Object.freeze([...inheritedTypeNames].sort()),
|
|
678
|
+
openComplexTypeNames: Object.freeze([...openComplexTypeNames].sort()),
|
|
679
|
+
unqualifiedTypeNames: Object.freeze([...unqualifiedTypeNames].sort()),
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
function odataEnumBounds(underlyingType) {
|
|
683
|
+
switch (underlyingType) {
|
|
684
|
+
case "Edm.Byte":
|
|
685
|
+
return { minimum: 0n, maximum: 255n };
|
|
686
|
+
case "Edm.SByte":
|
|
687
|
+
return { minimum: -128n, maximum: 127n };
|
|
688
|
+
case "Edm.Int16":
|
|
689
|
+
return { minimum: -32768n, maximum: 32767n };
|
|
690
|
+
case "Edm.Int32":
|
|
691
|
+
return { minimum: -2147483648n, maximum: 2147483647n };
|
|
692
|
+
case "Edm.Int64":
|
|
693
|
+
return { minimum: -(1n << 63n), maximum: (1n << 63n) - 1n };
|
|
694
|
+
default:
|
|
695
|
+
return undefined;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
function odataSimpleIdentifier(value) {
|
|
699
|
+
if (value.length > 256)
|
|
700
|
+
return false;
|
|
701
|
+
let codePoints = 0;
|
|
702
|
+
for (const _character of value) {
|
|
703
|
+
codePoints += 1;
|
|
704
|
+
if (codePoints > 128)
|
|
705
|
+
return false;
|
|
706
|
+
}
|
|
707
|
+
return /^[\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]*$/u.test(value);
|
|
708
|
+
}
|
|
709
|
+
function parseOdataProperties(body) {
|
|
710
|
+
const props = [];
|
|
711
|
+
for (const propAttrs of xmlStartTags(body, "Property")) {
|
|
712
|
+
const propName = readAttr(propAttrs, "Name");
|
|
713
|
+
const propType = readAttr(propAttrs, "Type");
|
|
714
|
+
if (!propName || !propType)
|
|
715
|
+
continue;
|
|
716
|
+
const nullable = readAttr(propAttrs, "Nullable");
|
|
717
|
+
const maxLengthAttr = readAttr(propAttrs, "MaxLength");
|
|
718
|
+
const precisionAttr = readAttr(propAttrs, "Precision");
|
|
719
|
+
const scaleAttr = readAttr(propAttrs, "Scale");
|
|
720
|
+
const sridAttr = readAttr(propAttrs, "SRID");
|
|
721
|
+
const isSpatial = propType.startsWith("Edm.Geography") || propType.startsWith("Edm.Geometry");
|
|
722
|
+
const info = { name: propName, type: propType };
|
|
723
|
+
if (nullable !== undefined)
|
|
724
|
+
info.nullable = nullable !== "false";
|
|
725
|
+
if (maxLengthAttr?.toLowerCase() === "max")
|
|
726
|
+
info.maxLength = "max";
|
|
727
|
+
else if (maxLengthAttr !== undefined) {
|
|
728
|
+
const maxLength = Number(maxLengthAttr);
|
|
729
|
+
if (Number.isSafeInteger(maxLength) && maxLength >= 0)
|
|
730
|
+
info.maxLength = maxLength;
|
|
731
|
+
}
|
|
732
|
+
if (precisionAttr !== undefined) {
|
|
733
|
+
const precision = Number(precisionAttr);
|
|
734
|
+
if (Number.isSafeInteger(precision) && precision >= 0)
|
|
735
|
+
info.precision = precision;
|
|
736
|
+
}
|
|
737
|
+
if (scaleAttr?.toLowerCase() === "variable" || scaleAttr?.toLowerCase() === "floating") {
|
|
738
|
+
info.scale = scaleAttr.toLowerCase();
|
|
739
|
+
}
|
|
740
|
+
else if (scaleAttr !== undefined) {
|
|
741
|
+
const scale = Number(scaleAttr);
|
|
742
|
+
if (Number.isSafeInteger(scale) && scale >= 0)
|
|
743
|
+
info.scale = scale;
|
|
744
|
+
}
|
|
745
|
+
if (isSpatial)
|
|
746
|
+
info.isSpatial = true;
|
|
747
|
+
if (sridAttr?.toLowerCase() === "variable")
|
|
748
|
+
info.srid = "variable";
|
|
749
|
+
else if (sridAttr !== undefined) {
|
|
750
|
+
const srid = Number(sridAttr);
|
|
751
|
+
if (Number.isSafeInteger(srid) && srid >= 0)
|
|
752
|
+
info.srid = srid;
|
|
753
|
+
}
|
|
754
|
+
props.push(info);
|
|
755
|
+
}
|
|
756
|
+
return props;
|
|
757
|
+
}
|
|
758
|
+
function legacyOdataFieldInfo(field) {
|
|
759
|
+
return {
|
|
760
|
+
name: field.name,
|
|
761
|
+
type: field.type,
|
|
762
|
+
...(field.nullable === undefined ? {} : { nullable: field.nullable }),
|
|
763
|
+
...(field.isSpatial === true ? { isSpatial: true } : {}),
|
|
764
|
+
...(typeof field.srid === "number" ? { srid: field.srid } : {}),
|
|
765
|
+
};
|
|
582
766
|
}
|
|
583
767
|
/**
|
|
584
768
|
* Convenience: project the field schema for one entity set into the
|
|
@@ -614,12 +798,12 @@ function edmToHonuaFieldType(edm) {
|
|
|
614
798
|
}
|
|
615
799
|
function parseEntitySetAnnotations(body) {
|
|
616
800
|
const out = {};
|
|
617
|
-
for (const
|
|
618
|
-
const attrs =
|
|
801
|
+
for (const element of xmlElements(body, "Annotation")) {
|
|
802
|
+
const attrs = element.attributes;
|
|
619
803
|
const term = readAttr(attrs, "Term");
|
|
620
804
|
if (!term || !term.includes("Capabilities."))
|
|
621
805
|
continue;
|
|
622
|
-
const inner =
|
|
806
|
+
const inner = element.body.trim();
|
|
623
807
|
const boolValue = readAttr(attrs, "Bool") ??
|
|
624
808
|
matchBool(inner) ??
|
|
625
809
|
matchPropertyValueBool(inner, "Insertable") ??
|
|
@@ -672,22 +856,170 @@ function parseEntitySetAnnotations(body) {
|
|
|
672
856
|
return out;
|
|
673
857
|
}
|
|
674
858
|
function readAttr(attrs, name) {
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
859
|
+
let cursor = 0;
|
|
860
|
+
while (cursor < attrs.length) {
|
|
861
|
+
while (cursor < attrs.length && xmlWhitespace(attrs.charCodeAt(cursor)))
|
|
862
|
+
cursor += 1;
|
|
863
|
+
if (cursor >= attrs.length || attrs.charCodeAt(cursor) === 47)
|
|
864
|
+
return undefined;
|
|
865
|
+
const nameStart = cursor;
|
|
866
|
+
while (cursor < attrs.length) {
|
|
867
|
+
const code = attrs.charCodeAt(cursor);
|
|
868
|
+
if (xmlWhitespace(code) || code === 61 || code === 47 || code === 62)
|
|
869
|
+
break;
|
|
870
|
+
cursor += 1;
|
|
871
|
+
}
|
|
872
|
+
const attributeName = attrs.slice(nameStart, cursor);
|
|
873
|
+
while (cursor < attrs.length && xmlWhitespace(attrs.charCodeAt(cursor)))
|
|
874
|
+
cursor += 1;
|
|
875
|
+
if (attrs.charCodeAt(cursor) !== 61) {
|
|
876
|
+
cursor += 1;
|
|
877
|
+
continue;
|
|
878
|
+
}
|
|
879
|
+
cursor += 1;
|
|
880
|
+
while (cursor < attrs.length && xmlWhitespace(attrs.charCodeAt(cursor)))
|
|
881
|
+
cursor += 1;
|
|
882
|
+
const quote = attrs.charCodeAt(cursor);
|
|
883
|
+
if (quote !== 34 && quote !== 39) {
|
|
884
|
+
cursor += 1;
|
|
885
|
+
continue;
|
|
886
|
+
}
|
|
887
|
+
const valueStart = ++cursor;
|
|
888
|
+
while (cursor < attrs.length && attrs.charCodeAt(cursor) !== quote)
|
|
889
|
+
cursor += 1;
|
|
890
|
+
if (cursor >= attrs.length)
|
|
891
|
+
return undefined;
|
|
892
|
+
if (attributeName === name)
|
|
893
|
+
return attrs.slice(valueStart, cursor);
|
|
894
|
+
cursor += 1;
|
|
895
|
+
}
|
|
896
|
+
return undefined;
|
|
897
|
+
}
|
|
898
|
+
function* xmlElements(xml, tagName) {
|
|
899
|
+
const marker = `<${tagName}`;
|
|
900
|
+
const closing = `</${tagName}>`;
|
|
901
|
+
let cursor = 0;
|
|
902
|
+
while (cursor < xml.length) {
|
|
903
|
+
const start = findXmlTag(xml, marker, cursor);
|
|
904
|
+
if (start === -1)
|
|
905
|
+
return;
|
|
906
|
+
const tagEnd = findXmlTagEnd(xml, start + marker.length);
|
|
907
|
+
if (tagEnd === -1)
|
|
908
|
+
return;
|
|
909
|
+
const attributes = xml.slice(start + marker.length, tagEnd);
|
|
910
|
+
if (xmlSelfClosing(attributes)) {
|
|
911
|
+
yield { attributes, body: "" };
|
|
912
|
+
cursor = tagEnd + 1;
|
|
913
|
+
continue;
|
|
914
|
+
}
|
|
915
|
+
const closeStart = xml.indexOf(closing, tagEnd + 1);
|
|
916
|
+
if (closeStart === -1)
|
|
917
|
+
return;
|
|
918
|
+
yield { attributes, body: xml.slice(tagEnd + 1, closeStart) };
|
|
919
|
+
cursor = closeStart + closing.length;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
function* xmlStartTags(xml, tagName) {
|
|
923
|
+
const marker = `<${tagName}`;
|
|
924
|
+
let cursor = 0;
|
|
925
|
+
while (cursor < xml.length) {
|
|
926
|
+
const start = findXmlTag(xml, marker, cursor);
|
|
927
|
+
if (start === -1)
|
|
928
|
+
return;
|
|
929
|
+
const tagEnd = findXmlTagEnd(xml, start + marker.length);
|
|
930
|
+
if (tagEnd === -1)
|
|
931
|
+
return;
|
|
932
|
+
yield xml.slice(start + marker.length, tagEnd);
|
|
933
|
+
cursor = tagEnd + 1;
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
function firstXmlStartTagByLocalName(xml, localName) {
|
|
937
|
+
let cursor = 0;
|
|
938
|
+
while (cursor < xml.length) {
|
|
939
|
+
const start = xml.indexOf("<", cursor);
|
|
940
|
+
if (start === -1)
|
|
941
|
+
return undefined;
|
|
942
|
+
const nameStart = start + 1;
|
|
943
|
+
const first = xml.charCodeAt(nameStart);
|
|
944
|
+
if (first === 33 || first === 47 || first === 63) {
|
|
945
|
+
cursor = nameStart + 1;
|
|
946
|
+
continue;
|
|
947
|
+
}
|
|
948
|
+
let nameEnd = nameStart;
|
|
949
|
+
while (nameEnd < xml.length) {
|
|
950
|
+
const code = xml.charCodeAt(nameEnd);
|
|
951
|
+
if (xmlWhitespace(code) || code === 47 || code === 62)
|
|
952
|
+
break;
|
|
953
|
+
nameEnd += 1;
|
|
954
|
+
}
|
|
955
|
+
const qualifiedName = xml.slice(nameStart, nameEnd);
|
|
956
|
+
const colon = qualifiedName.lastIndexOf(":");
|
|
957
|
+
if (qualifiedName.slice(colon + 1) === localName) {
|
|
958
|
+
const tagEnd = findXmlTagEnd(xml, nameEnd);
|
|
959
|
+
return tagEnd === -1 ? undefined : xml.slice(nameEnd, tagEnd);
|
|
960
|
+
}
|
|
961
|
+
cursor = nameEnd > nameStart ? nameEnd : nameStart + 1;
|
|
962
|
+
}
|
|
963
|
+
return undefined;
|
|
964
|
+
}
|
|
965
|
+
function findXmlTag(xml, marker, from) {
|
|
966
|
+
let cursor = from;
|
|
967
|
+
while (cursor < xml.length) {
|
|
968
|
+
const start = xml.indexOf(marker, cursor);
|
|
969
|
+
if (start === -1)
|
|
970
|
+
return -1;
|
|
971
|
+
const boundary = xml.charCodeAt(start + marker.length);
|
|
972
|
+
if (xmlWhitespace(boundary) || boundary === 47 || boundary === 62)
|
|
973
|
+
return start;
|
|
974
|
+
cursor = start + marker.length;
|
|
975
|
+
}
|
|
976
|
+
return -1;
|
|
977
|
+
}
|
|
978
|
+
function findXmlTagEnd(xml, from) {
|
|
979
|
+
let quote = 0;
|
|
980
|
+
for (let cursor = from; cursor < xml.length; cursor += 1) {
|
|
981
|
+
const code = xml.charCodeAt(cursor);
|
|
982
|
+
if (quote !== 0) {
|
|
983
|
+
if (code === quote)
|
|
984
|
+
quote = 0;
|
|
985
|
+
}
|
|
986
|
+
else if (code === 34 || code === 39) {
|
|
987
|
+
quote = code;
|
|
988
|
+
}
|
|
989
|
+
else if (code === 62) {
|
|
990
|
+
return cursor;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
return -1;
|
|
994
|
+
}
|
|
995
|
+
function xmlSelfClosing(attributes) {
|
|
996
|
+
let cursor = attributes.length - 1;
|
|
997
|
+
while (cursor >= 0 && xmlWhitespace(attributes.charCodeAt(cursor)))
|
|
998
|
+
cursor -= 1;
|
|
999
|
+
return cursor >= 0 && attributes.charCodeAt(cursor) === 47;
|
|
1000
|
+
}
|
|
1001
|
+
function xmlWhitespace(code) {
|
|
1002
|
+
return code === 9 || code === 10 || code === 13 || code === 32;
|
|
678
1003
|
}
|
|
679
1004
|
function stripNamespace(name) {
|
|
680
1005
|
const idx = name.lastIndexOf(".");
|
|
681
1006
|
return idx === -1 ? name : name.slice(idx + 1);
|
|
682
1007
|
}
|
|
683
1008
|
function matchBool(inner) {
|
|
684
|
-
const
|
|
685
|
-
|
|
1009
|
+
const element = xmlElements(inner, "Bool").next();
|
|
1010
|
+
if (element.done)
|
|
1011
|
+
return undefined;
|
|
1012
|
+
return element.value.body === "true" || element.value.body === "false" ? element.value.body : undefined;
|
|
686
1013
|
}
|
|
687
1014
|
function matchPropertyValueBool(inner, property) {
|
|
688
|
-
const
|
|
689
|
-
|
|
690
|
-
|
|
1015
|
+
for (const attributes of xmlStartTags(inner, "PropertyValue")) {
|
|
1016
|
+
if (readAttr(attributes, "Property") !== property)
|
|
1017
|
+
continue;
|
|
1018
|
+
const value = readAttr(attributes, "Bool");
|
|
1019
|
+
if (value === "true" || value === "false")
|
|
1020
|
+
return value;
|
|
1021
|
+
}
|
|
1022
|
+
return undefined;
|
|
691
1023
|
}
|
|
692
1024
|
const UNSUPPORTED_OPERATOR_RES = [
|
|
693
1025
|
{ token: "has", re: /\bhas\b/i },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ogc-features.d.ts","sourceRoot":"","sources":["../../../src/core/ogc-features.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,KAAK,EACV,0BAA0B,EAC1B,2BAA2B,EAC3B,2BAA2B,EAC3B,iCAAiC,EACjC,uBAAuB,EACvB,uBAAuB,EACvB,0BAA0B,EAC1B,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EAEpB,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AAoBpB,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,sBAAsB,EACjC,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,uBAAuB,CAAC,CAQlC;AAED,wBAAsB,yBAAyB,CAC7C,SAAS,EAAE,sBAAsB,EACjC,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,2BAA2B,CAAC,CAQtC;AAED,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,sBAAsB,EACjC,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,2BAA2B,CAAC,CAQtC;AAED,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,sBAAsB,EACjC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,0BAA0B,CAAC,CAQrC;AAED,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,sBAAsB,EACjC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,0BAA0B,CAAC,CAQrC;AAED,wBAAsB,YAAY,CAChC,SAAS,EAAE,sBAAsB,EACjC,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,iCAAiC,CAAC,
|
|
1
|
+
{"version":3,"file":"ogc-features.d.ts","sourceRoot":"","sources":["../../../src/core/ogc-features.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,KAAK,EACV,0BAA0B,EAC1B,2BAA2B,EAC3B,2BAA2B,EAC3B,iCAAiC,EACjC,uBAAuB,EACvB,uBAAuB,EACvB,0BAA0B,EAC1B,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EAEpB,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AAoBpB,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,sBAAsB,EACjC,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,uBAAuB,CAAC,CAQlC;AAED,wBAAsB,yBAAyB,CAC7C,SAAS,EAAE,sBAAsB,EACjC,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,2BAA2B,CAAC,CAQtC;AAED,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,sBAAsB,EACjC,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,2BAA2B,CAAC,CAQtC;AAED,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,sBAAsB,EACjC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,0BAA0B,CAAC,CAQrC;AAED,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,sBAAsB,EACjC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,0BAA0B,CAAC,CAQrC;AAED,wBAAsB,YAAY,CAChC,SAAS,EAAE,sBAAsB,EACjC,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,iCAAiC,CAAC,CAuC5C;AAED,wBAAsB,UAAU,CAC9B,SAAS,EAAE,sBAAsB,EACjC,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,uBAAuB,CAAC,CAYlC;AAED,wBAAsB,aAAa,CACjC,SAAS,EAAE,sBAAsB,EACjC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,uBAAuB,CAAC,CAYlC;AAED,wBAAsB,cAAc,CAClC,SAAS,EAAE,sBAAsB,EACjC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,uBAAuB,CAAC,CAelC;AAED,wBAAsB,YAAY,CAChC,SAAS,EAAE,sBAAsB,EACjC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,uBAAuB,CAAC,CAelC;AAED,wBAAsB,aAAa,CAAC,SAAS,EAAE,sBAAsB,EAAE,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAOnH"}
|
package/core/ogc-features.js
CHANGED
|
@@ -66,6 +66,9 @@ export async function listOgcItems(transport, request) {
|
|
|
66
66
|
if (request.filter !== undefined) {
|
|
67
67
|
params.set("filter", request.filter);
|
|
68
68
|
}
|
|
69
|
+
if (request.filterLang !== undefined) {
|
|
70
|
+
params.set("filter-lang", request.filterLang);
|
|
71
|
+
}
|
|
69
72
|
if (request.ids !== undefined) {
|
|
70
73
|
params.set("ids", normalizeCsv(request.ids));
|
|
71
74
|
}
|