@honua/sdk-esri-compat 0.1.12 → 0.1.14
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 +2 -0
- package/columnar/apache-arrow.d.ts +17 -0
- package/columnar/apache-arrow.d.ts.map +1 -0
- package/columnar/apache-arrow.js +1036 -0
- package/columnar/batch-cache-conformance.d.ts +66 -0
- package/columnar/batch-cache-conformance.d.ts.map +1 -0
- package/columnar/batch-cache-conformance.js +317 -0
- package/columnar/batch-cache-indexeddb.d.ts +31 -0
- package/columnar/batch-cache-indexeddb.d.ts.map +1 -0
- package/columnar/batch-cache-indexeddb.js +148 -0
- package/columnar/batch-cache.d.ts +298 -0
- package/columnar/batch-cache.d.ts.map +1 -0
- package/columnar/batch-cache.js +757 -0
- package/columnar/geoarrow-aggregate.d.ts +178 -0
- package/columnar/geoarrow-aggregate.d.ts.map +1 -0
- package/columnar/geoarrow-aggregate.js +976 -0
- package/columnar/geoarrow-patch.d.ts +382 -0
- package/columnar/geoarrow-patch.d.ts.map +1 -0
- package/columnar/geoarrow-patch.js +1656 -0
- package/columnar/geoarrow-reproject.d.ts +22 -0
- package/columnar/geoarrow-reproject.d.ts.map +1 -0
- package/columnar/geoarrow-reproject.js +119 -0
- package/columnar/geoarrow-serialization.d.ts +68 -0
- package/columnar/geoarrow-serialization.d.ts.map +1 -0
- package/columnar/geoarrow-serialization.js +331 -0
- package/columnar/geoarrow-types.d.ts +271 -0
- package/columnar/geoarrow-types.d.ts.map +1 -0
- package/columnar/geoarrow-types.js +15 -0
- package/columnar/geoarrow.d.ts +52 -0
- package/columnar/geoarrow.d.ts.map +1 -0
- package/columnar/geoarrow.js +1469 -0
- package/columnar/index.d.ts +43 -0
- package/columnar/index.d.ts.map +1 -0
- package/columnar/index.js +29 -0
- package/columnar/operators.d.ts +70 -0
- package/columnar/operators.d.ts.map +1 -0
- package/columnar/operators.js +307 -0
- package/columnar/result.d.ts +369 -0
- package/columnar/result.d.ts.map +1 -0
- package/columnar/result.js +815 -0
- package/columnar/telemetry.d.ts +152 -0
- package/columnar/telemetry.d.ts.map +1 -0
- package/columnar/telemetry.js +265 -0
- package/columnar/transfer.d.ts +28 -0
- package/columnar/transfer.d.ts.map +1 -0
- package/columnar/transfer.js +669 -0
- package/columnar/types.d.ts +175 -0
- package/columnar/types.d.ts.map +1 -0
- package/columnar/types.js +22 -0
- package/columnar/worker.d.ts +157 -0
- package/columnar/worker.d.ts.map +1 -0
- package/columnar/worker.js +1059 -0
- package/connect-url-safety.d.ts +53 -0
- package/connect-url-safety.js +189 -0
- package/contract/pmtiles.d.ts +6 -5
- package/contract/pmtiles.d.ts.map +1 -1
- package/contract/pmtiles.js +30 -5
- package/contract/source.d.ts.map +1 -1
- package/contract/source.js +11 -8
- package/core/client.d.ts.map +1 -1
- package/core/client.js +87 -19
- package/core/deprecation-notice.d.ts +28 -0
- package/core/deprecation-notice.d.ts.map +1 -0
- package/core/deprecation-notice.js +22 -0
- package/core/esri-geojson.d.ts.map +1 -1
- package/core/esri-geojson.js +14 -8
- package/core/optional-grpc-peer.d.ts +15 -0
- package/core/optional-grpc-peer.d.ts.map +1 -0
- package/core/optional-grpc-peer.js +60 -0
- package/esri-compat/basemap-gallery.d.ts +2 -0
- package/esri-compat/basemap-gallery.d.ts.map +1 -1
- package/esri-compat/basemap-gallery.js +12 -0
- package/esri-compat/basemap.d.ts +4 -0
- package/esri-compat/basemap.d.ts.map +1 -1
- package/esri-compat/basemap.js +70 -0
- package/esri-compat/bookmarks.d.ts +2 -0
- package/esri-compat/bookmarks.d.ts.map +1 -1
- package/esri-compat/bookmarks.js +12 -0
- package/esri-compat/controls.d.ts +18 -0
- package/esri-compat/controls.d.ts.map +1 -1
- package/esri-compat/controls.js +120 -57
- package/esri-compat/directions.d.ts +4 -0
- package/esri-compat/directions.d.ts.map +1 -1
- package/esri-compat/directions.js +30 -20
- package/esri-compat/editor.d.ts +4 -0
- package/esri-compat/editor.d.ts.map +1 -1
- package/esri-compat/editor.js +16 -0
- package/esri-compat/esri-config.d.ts +2 -1
- package/esri-compat/esri-config.d.ts.map +1 -1
- package/esri-compat/feature-effect.d.ts +23 -0
- package/esri-compat/feature-effect.d.ts.map +1 -0
- package/esri-compat/feature-effect.js +12 -0
- package/esri-compat/feature-form.d.ts +6 -0
- package/esri-compat/feature-form.d.ts.map +1 -1
- package/esri-compat/feature-form.js +63 -0
- package/esri-compat/feature-layer.d.ts +21 -2
- package/esri-compat/feature-layer.d.ts.map +1 -1
- package/esri-compat/feature-layer.js +172 -1
- package/esri-compat/feature-table.d.ts +5 -0
- package/esri-compat/feature-table.d.ts.map +1 -1
- package/esri-compat/feature-table.js +23 -0
- package/esri-compat/identity-manager.d.ts +1 -1
- package/esri-compat/identity-manager.js +1 -1
- package/esri-compat/legend.d.ts +2 -0
- package/esri-compat/legend.d.ts.map +1 -1
- package/esri-compat/legend.js +98 -0
- package/esri-compat/locator.d.ts +1 -1
- package/esri-compat/locator.js +1 -1
- package/esri-compat/map-view-mount.d.ts +1 -0
- package/esri-compat/map-view-mount.d.ts.map +1 -1
- package/esri-compat/map-view-mount.js +46 -25
- package/esri-compat/map-view.d.ts +13 -0
- package/esri-compat/map-view.d.ts.map +1 -1
- package/esri-compat/map-view.js +94 -8
- package/esri-compat/map.d.ts +5 -1
- package/esri-compat/map.d.ts.map +1 -1
- package/esri-compat/map.js +10 -0
- package/esri-compat/measurement.d.ts +2 -0
- package/esri-compat/measurement.d.ts.map +1 -1
- package/esri-compat/measurement.js +14 -0
- package/esri-compat/point.d.ts +7 -0
- package/esri-compat/point.d.ts.map +1 -1
- package/esri-compat/point.js +33 -3
- package/esri-compat/popup.d.ts +2 -0
- package/esri-compat/popup.d.ts.map +1 -1
- package/esri-compat/popup.js +12 -0
- package/esri-compat/portal.d.ts +1 -1
- package/esri-compat/portal.js +1 -1
- package/esri-compat/print.d.ts +3 -0
- package/esri-compat/print.d.ts.map +1 -1
- package/esri-compat/print.js +15 -0
- package/esri-compat/search.d.ts +4 -0
- package/esri-compat/search.d.ts.map +1 -1
- package/esri-compat/search.js +25 -28
- package/esri-compat/sketch.d.ts +2 -0
- package/esri-compat/sketch.d.ts.map +1 -1
- package/esri-compat/sketch.js +12 -0
- package/esri-compat/widget-host.d.ts +46 -17
- package/esri-compat/widget-host.d.ts.map +1 -1
- package/esri-compat/widget-host.js +84 -20
- package/esri-compat/widget-shell-hosts.d.ts +61 -0
- package/esri-compat/widget-shell-hosts.d.ts.map +1 -0
- package/esri-compat/widget-shell-hosts.js +76 -0
- package/index.d.ts +3 -1
- package/index.js +1 -0
- package/offline/digest.d.ts +15 -0
- package/offline/digest.js +58 -0
- package/offline/quota.d.ts +161 -0
- package/offline/quota.js +370 -0
- package/offline/types.d.ts +349 -0
- package/offline/types.js +75 -0
- package/package.json +21 -2
- package/query-planner/canonical-filter.d.ts +30 -0
- package/query-planner/canonical-filter.d.ts.map +1 -0
- package/query-planner/canonical-filter.js +30 -0
- 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/columnar-plan.d.ts +63 -0
- package/query-planner/columnar-plan.d.ts.map +1 -0
- package/query-planner/columnar-plan.js +94 -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 +386 -0
- package/query-planner/duckdb.d.ts +79 -0
- package/query-planner/duckdb.d.ts.map +1 -0
- package/query-planner/duckdb.js +772 -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 +52 -0
- package/query-planner/executor.d.ts +5 -0
- package/query-planner/executor.d.ts.map +1 -0
- package/query-planner/executor.js +229 -0
- package/query-planner/geoservices.d.ts +91 -0
- package/query-planner/geoservices.d.ts.map +1 -0
- package/query-planner/geoservices.js +688 -0
- package/query-planner/grpc.d.ts +100 -0
- package/query-planner/grpc.d.ts.map +1 -0
- package/query-planner/grpc.js +760 -0
- package/query-planner/index.d.ts +59 -0
- package/query-planner/index.d.ts.map +1 -0
- package/query-planner/index.js +43 -0
- package/query-planner/ir.d.ts +25 -0
- package/query-planner/ir.d.ts.map +1 -0
- package/query-planner/ir.js +479 -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-protocol-module.d.ts +54 -0
- package/query-planner/odata-protocol-module.d.ts.map +1 -0
- package/query-planner/odata-protocol-module.js +199 -0
- package/query-planner/odata-v1.d.ts +23 -0
- package/query-planner/odata-v1.d.ts.map +1 -0
- package/query-planner/odata-v1.js +202 -0
- package/query-planner/odata.d.ts +45 -0
- package/query-planner/odata.d.ts.map +1 -0
- package/query-planner/odata.js +519 -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 +639 -0
- package/query-planner/planner.d.ts +17 -0
- package/query-planner/planner.d.ts.map +1 -0
- package/query-planner/planner.js +937 -0
- package/query-planner/representation.d.ts +59 -0
- package/query-planner/representation.d.ts.map +1 -0
- package/query-planner/representation.js +140 -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 +712 -0
- package/query-planner/types.d.ts.map +1 -0
- package/query-planner/types.js +49 -0
- package/query-planner/wfs-protocol-module.d.ts +57 -0
- package/query-planner/wfs-protocol-module.d.ts.map +1 -0
- package/query-planner/wfs-protocol-module.js +731 -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-v1.d.ts +41 -0
- package/query-planner/wfs-v1.d.ts.map +1 -0
- package/query-planner/wfs-v1.js +366 -0
- package/query-planner/wfs.d.ts +4 -0
- package/query-planner/wfs.d.ts.map +1 -0
- package/query-planner/wfs.js +2 -0
- package/widget-capabilities.d.ts +67 -0
- package/widget-capabilities.js +152 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { PROTOCOL_DEFAULT_CAPABILITIES } from "../contract/types.js";
|
|
2
|
+
import { HonuaCapabilityNotSupportedError } from "../core/errors.js";
|
|
3
|
+
import { HonuaOdataEntitySet } from "../core/odata.js";
|
|
4
|
+
import { trimTrailingSlashes } from "../core/path-utils.js";
|
|
5
|
+
import { bindOdataProtocolQueryOperation, odataProtocolQueryCompiler } from "./odata-v1.js";
|
|
6
|
+
/**
|
|
7
|
+
* Project already-negotiated OData query params onto the credential-free
|
|
8
|
+
* deterministic artifact consumed by the module executor.
|
|
9
|
+
*
|
|
10
|
+
* `count` and `signal` are intentionally omitted: count is runtime response
|
|
11
|
+
* metadata policy, and cancellation can never participate in request identity.
|
|
12
|
+
*/
|
|
13
|
+
export function createOdataProtocolCompiledQuery(entitySet, operation, params) {
|
|
14
|
+
const request = Object.freeze({
|
|
15
|
+
compiler: "odata-v4-query-v1",
|
|
16
|
+
entitySet,
|
|
17
|
+
...(params.filter !== undefined ? { filter: params.filter } : {}),
|
|
18
|
+
...(params.select !== undefined ? { select: Object.freeze([...params.select]) } : {}),
|
|
19
|
+
...(params.expand !== undefined ? { expand: Object.freeze([...params.expand]) } : {}),
|
|
20
|
+
...(params.orderBy !== undefined ? { orderBy: Object.freeze([...params.orderBy]) } : {}),
|
|
21
|
+
...(params.skip !== undefined ? { skip: params.skip } : {}),
|
|
22
|
+
...(params.top !== undefined ? { top: params.top } : {}),
|
|
23
|
+
});
|
|
24
|
+
return bindOdataProtocolQueryOperation(request, operation);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Construct the first-party query-capable OData protocol module.
|
|
28
|
+
*
|
|
29
|
+
* Discovery is synchronous and performs no I/O. `$metadata` remains lazy on
|
|
30
|
+
* the returned `HonuaOdataEntitySet`, exactly as it was before the migration.
|
|
31
|
+
* The client stays in this module instance's closure; there is no global
|
|
32
|
+
* protocol registry or ambient authority.
|
|
33
|
+
*/
|
|
34
|
+
export function odataProtocolModule(client) {
|
|
35
|
+
return Object.freeze({
|
|
36
|
+
kind: "odata",
|
|
37
|
+
environments: Object.freeze(["browser", "node", "worker"]),
|
|
38
|
+
capabilities(descriptor) {
|
|
39
|
+
return descriptor.capabilities ?? PROTOCOL_DEFAULT_CAPABILITIES.odata;
|
|
40
|
+
},
|
|
41
|
+
discover(descriptor) {
|
|
42
|
+
const { entitySet, basePath } = requireOdataLocator(descriptor);
|
|
43
|
+
const adapter = new HonuaOdataEntitySet({ client, entitySet, basePath });
|
|
44
|
+
return Object.freeze({
|
|
45
|
+
descriptor,
|
|
46
|
+
capabilities: descriptor.capabilities ?? PROTOCOL_DEFAULT_CAPABILITIES.odata,
|
|
47
|
+
adapter,
|
|
48
|
+
diagnostics: Object.freeze([]),
|
|
49
|
+
dispose() {
|
|
50
|
+
// HonuaOdataEntitySet retains only settled/in-flight promises and
|
|
51
|
+
// opens no persistent handles. Disposal is deterministic and
|
|
52
|
+
// synchronous with nothing to release.
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
compile: odataProtocolQueryCompiler.compile,
|
|
57
|
+
async execute(handle, input) {
|
|
58
|
+
assertExecutableOdataArtifact(handle.adapter, input.compiled, input.operation);
|
|
59
|
+
const logicalLimit = input.operation === "queryAll"
|
|
60
|
+
? resolveOdataQueryAllLogicalLimit(input.compiled, input.query.limit)
|
|
61
|
+
: undefined;
|
|
62
|
+
const params = odataParamsFromCompiled(input.compiled, input.query.count, input.signal);
|
|
63
|
+
switch (input.operation) {
|
|
64
|
+
case "query": {
|
|
65
|
+
const page = await handle.adapter.query(params);
|
|
66
|
+
return odataProtocolResultFromPage(handle.descriptor, page, input.query.fields, input.query.returnGeometry, input.query.geometryColumn);
|
|
67
|
+
}
|
|
68
|
+
case "queryAll": {
|
|
69
|
+
const drained = await handle.adapter.queryAll(params);
|
|
70
|
+
const allFeatures = drained.rows.map((row) => odataRowToFeature(row, handle.descriptor, input.query.returnGeometry, input.query.geometryColumn));
|
|
71
|
+
const { features, exceededTransferLimit: collectedExceeded } = applyLimit(allFeatures, logicalLimit);
|
|
72
|
+
const countExceeded = typeof drained.totalCount === "number" &&
|
|
73
|
+
typeof logicalLimit === "number" &&
|
|
74
|
+
drained.totalCount > features.length;
|
|
75
|
+
return {
|
|
76
|
+
features,
|
|
77
|
+
exceededTransferLimit: collectedExceeded || countExceeded,
|
|
78
|
+
...(typeof drained.totalCount === "number"
|
|
79
|
+
? { totalCount: drained.totalCount }
|
|
80
|
+
: { totalCount: features.length }),
|
|
81
|
+
...(input.query.fields.length > 0 ? { fields: input.query.fields } : {}),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
case "queryAggregate":
|
|
85
|
+
throw new HonuaCapabilityNotSupportedError("queryAggregate", handle.descriptor.protocol, handle.descriptor.id);
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
function requireOdataLocator(descriptor) {
|
|
91
|
+
const { entitySet, url, layerId } = descriptor.locator;
|
|
92
|
+
let resolvedEntitySet;
|
|
93
|
+
if (typeof entitySet === "string" && entitySet !== "") {
|
|
94
|
+
resolvedEntitySet = entitySet;
|
|
95
|
+
}
|
|
96
|
+
else if (typeof layerId === "number" && Number.isFinite(layerId)) {
|
|
97
|
+
resolvedEntitySet = `Layers(${layerId})/Features`;
|
|
98
|
+
}
|
|
99
|
+
if (resolvedEntitySet === undefined) {
|
|
100
|
+
throw new Error(`createDataset: source "${descriptor.id}" (odata) requires locator.entitySet or locator.layerId`);
|
|
101
|
+
}
|
|
102
|
+
const basePath = url ? extractOdataBasePath(url) : "/odata";
|
|
103
|
+
return { entitySet: resolvedEntitySet, basePath };
|
|
104
|
+
}
|
|
105
|
+
function extractOdataBasePath(url) {
|
|
106
|
+
try {
|
|
107
|
+
const parsed = new URL(url);
|
|
108
|
+
const pathname = trimTrailingSlashes(parsed.pathname);
|
|
109
|
+
return pathname === "" ? "/odata" : pathname;
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return url.startsWith("/") ? trimTrailingSlashes(url) || "/odata" : `/${trimTrailingSlashes(url)}`;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function assertExecutableOdataArtifact(adapter, compiled, operation) {
|
|
116
|
+
if (compiled.compiler !== "odata-v4-protocol-query-v1") {
|
|
117
|
+
throw new TypeError("odata: protocol module requires an odata-v4-protocol-query-v1 artifact");
|
|
118
|
+
}
|
|
119
|
+
if (compiled.entitySet !== adapter.entitySet) {
|
|
120
|
+
throw new TypeError("odata: compiled entitySet does not match the discovered protocol handle");
|
|
121
|
+
}
|
|
122
|
+
if (compiled.operation !== operation) {
|
|
123
|
+
throw new TypeError("odata: compiled operation does not match the requested protocol operation");
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Recover the caller-visible queryAll ceiling from the compiler-owned
|
|
128
|
+
* lookahead row and reject any runtime context that does not describe the
|
|
129
|
+
* same bounded request. This runs before the adapter performs I/O.
|
|
130
|
+
*/
|
|
131
|
+
function resolveOdataQueryAllLogicalLimit(compiled, requestedLimit) {
|
|
132
|
+
if (requestedLimit !== undefined && (!Number.isSafeInteger(requestedLimit) || requestedLimit < 0)) {
|
|
133
|
+
throw new TypeError("odata: queryAll logical limit must be a non-negative safe integer");
|
|
134
|
+
}
|
|
135
|
+
if (compiled.top === undefined) {
|
|
136
|
+
if (requestedLimit !== undefined) {
|
|
137
|
+
throw new TypeError("odata: queryAll compiled top does not match the logical limit");
|
|
138
|
+
}
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
if (!Number.isSafeInteger(compiled.top) || compiled.top < 1) {
|
|
142
|
+
throw new TypeError("odata: queryAll compiled top must contain one lookahead row");
|
|
143
|
+
}
|
|
144
|
+
const compiledLogicalLimit = compiled.top - 1;
|
|
145
|
+
if (requestedLimit !== undefined && requestedLimit !== compiledLogicalLimit) {
|
|
146
|
+
throw new TypeError("odata: queryAll compiled top does not match the logical limit");
|
|
147
|
+
}
|
|
148
|
+
return requestedLimit ?? compiledLogicalLimit;
|
|
149
|
+
}
|
|
150
|
+
function odataParamsFromCompiled(compiled, count, signal) {
|
|
151
|
+
return {
|
|
152
|
+
...(compiled.filter !== undefined ? { filter: compiled.filter } : {}),
|
|
153
|
+
...(compiled.select !== undefined ? { select: compiled.select } : {}),
|
|
154
|
+
...(compiled.expand !== undefined ? { expand: compiled.expand } : {}),
|
|
155
|
+
...(compiled.orderBy !== undefined ? { orderBy: compiled.orderBy } : {}),
|
|
156
|
+
...(compiled.skip !== undefined ? { skip: compiled.skip } : {}),
|
|
157
|
+
...(compiled.top !== undefined ? { top: compiled.top } : {}),
|
|
158
|
+
...(count ? { count: true } : {}),
|
|
159
|
+
...(signal ? { signal } : {}),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
/** Internal shared result projection used by query execution and OData streaming. */
|
|
163
|
+
export function odataProtocolResultFromPage(descriptor, page, fields, returnGeometry, geometryColumn) {
|
|
164
|
+
const features = page.rows.map((row) => odataRowToFeature(row, descriptor, returnGeometry, geometryColumn));
|
|
165
|
+
const exceededTransferLimit = typeof page.totalCount === "number" ? features.length < page.totalCount : Boolean(page.nextLink);
|
|
166
|
+
return {
|
|
167
|
+
features,
|
|
168
|
+
exceededTransferLimit,
|
|
169
|
+
...(typeof page.totalCount === "number" ? { totalCount: page.totalCount } : {}),
|
|
170
|
+
...(fields.length > 0 ? { fields } : {}),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
function odataRowToFeature(row, descriptor, returnGeometry, geometryColumn) {
|
|
174
|
+
const geometryKey = geometryColumn ??
|
|
175
|
+
descriptor.schema?.fields?.find((field) => field.type === "esriFieldTypeGeometry")?.name ??
|
|
176
|
+
findGeometryKey(row);
|
|
177
|
+
if (geometryKey && row[geometryKey] !== undefined) {
|
|
178
|
+
const { [geometryKey]: geometry, ...attributes } = row;
|
|
179
|
+
return {
|
|
180
|
+
attributes: attributes,
|
|
181
|
+
geometry: returnGeometry === false ? null : (geometry ?? null),
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
return { attributes: row, geometry: null };
|
|
185
|
+
}
|
|
186
|
+
function findGeometryKey(row) {
|
|
187
|
+
for (const key of Object.keys(row)) {
|
|
188
|
+
const lower = key.toLowerCase();
|
|
189
|
+
if (lower === "geometry" || lower === "geography" || lower === "shape")
|
|
190
|
+
return key;
|
|
191
|
+
}
|
|
192
|
+
return undefined;
|
|
193
|
+
}
|
|
194
|
+
function applyLimit(features, limit) {
|
|
195
|
+
if (typeof limit !== "number" || limit < 0 || features.length <= limit) {
|
|
196
|
+
return { features, exceededTransferLimit: false };
|
|
197
|
+
}
|
|
198
|
+
return { features: features.slice(0, limit), exceededTransferLimit: true };
|
|
199
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight deterministic OData v4 compiler.
|
|
3
|
+
*
|
|
4
|
+
* Kept separate from the semantic OData compiler so importing the public
|
|
5
|
+
* `odataProtocolModule()` does not pull the larger semantic compiler graph
|
|
6
|
+
* into contract-only bundles.
|
|
7
|
+
*/
|
|
8
|
+
import type { ProtocolModuleQueryCompileInput, ProtocolModuleQueryOperation } from "../contract/protocol-module.js";
|
|
9
|
+
import type { CanonicalQuery, OdataCompiledQueryV1, OdataProtocolCompiledQueryV1, QueryIrSourceIdentity } from "./types.js";
|
|
10
|
+
/** Compile canonical query IR to a deterministic OData v4 entity-set request. */
|
|
11
|
+
export declare function compileOdataQuery(source: QueryIrSourceIdentity, query: CanonicalQuery): OdataCompiledQueryV1;
|
|
12
|
+
/**
|
|
13
|
+
* The deterministic compiler hook installed on the first-party OData
|
|
14
|
+
* ProtocolModule. Planner dispatch and module consumers call this exact
|
|
15
|
+
* object, while runtime authority remains outside the compiler.
|
|
16
|
+
*/
|
|
17
|
+
export declare const odataProtocolQueryCompiler: Readonly<{
|
|
18
|
+
kind: "odata";
|
|
19
|
+
compile(input: ProtocolModuleQueryCompileInput<QueryIrSourceIdentity, CanonicalQuery>): OdataProtocolCompiledQueryV1;
|
|
20
|
+
}>;
|
|
21
|
+
/** Bind a legacy wire request to the exact operation authorized to execute it. */
|
|
22
|
+
export declare function bindOdataProtocolQueryOperation(compiled: OdataCompiledQueryV1, operation: ProtocolModuleQueryOperation): OdataProtocolCompiledQueryV1;
|
|
23
|
+
//# sourceMappingURL=odata-v1.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"odata-v1.d.ts","sourceRoot":"","sources":["../../../src/query-planner/odata-v1.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,+BAA+B,EAAE,4BAA4B,EAAE,MAAM,gCAAgC,CAAC;AAIpH,OAAO,KAAK,EACV,cAAc,EACd,oBAAoB,EACpB,4BAA4B,EAC5B,qBAAqB,EACtB,MAAM,YAAY,CAAC;AAGpB,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,qBAAqB,EAAE,KAAK,EAAE,cAAc,GAAG,oBAAoB,CAqH5G;AAED;;;;GAIG;AACH,eAAO,MAAM,0BAA0B;;mBAEtB,+BAA+B,CAAC,qBAAqB,EAAE,cAAc,CAAC,GAAG,4BAA4B;EAGpH,CAAC;AAEH,kFAAkF;AAClF,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,oBAAoB,EAC9B,SAAS,EAAE,4BAA4B,GACtC,4BAA4B,CAsB9B"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { compileQueryFilterToOData } from "../contract/query-filter.js";
|
|
2
|
+
import { buildOdataSpatialFilter, rewriteWhereToOdataFilter } from "../core/odata.js";
|
|
3
|
+
import { canonicalFilterParts, refuseCanonicalFilter } from "./canonical-filter.js";
|
|
4
|
+
import { HonuaQueryPlanningError } from "./types.js";
|
|
5
|
+
/** Compile canonical query IR to a deterministic OData v4 entity-set request. */
|
|
6
|
+
export function compileOdataQuery(source, query) {
|
|
7
|
+
if (source.protocol !== "odata") {
|
|
8
|
+
throw new HonuaQueryPlanningError("unsupported-compiler", `odata-v4-query-v1 does not compile protocol "${source.protocol}"`);
|
|
9
|
+
}
|
|
10
|
+
if (!source.entitySet) {
|
|
11
|
+
throw new HonuaQueryPlanningError("invalid-query", `Source "${source.id}" requires locator.entitySet for OData planning`);
|
|
12
|
+
}
|
|
13
|
+
if (query.aggregation) {
|
|
14
|
+
throw new HonuaQueryPlanningError("unsupported-query", "Canonical OData aggregation is not portable; use the typed $apply escape hatch");
|
|
15
|
+
}
|
|
16
|
+
if (query.outSr !== undefined) {
|
|
17
|
+
throw new HonuaQueryPlanningError("unsupported-query", "OData v4 has no portable output-CRS query option; omit outSr or use the typed OData escape hatch");
|
|
18
|
+
}
|
|
19
|
+
const ctx = {
|
|
20
|
+
protocol: source.protocol,
|
|
21
|
+
sourceId: source.id,
|
|
22
|
+
...(source.geometryProperty !== undefined ? { geometryProperty: source.geometryProperty } : {}),
|
|
23
|
+
};
|
|
24
|
+
const parts = canonicalFilterParts(query, ctx);
|
|
25
|
+
if (parts.protocolTime) {
|
|
26
|
+
refuseCanonicalFilter("Query.temporalFilter without a field", "OData v4", "the protocol has no time parameter; name the temporal field so the predicate stays exact");
|
|
27
|
+
}
|
|
28
|
+
const filterParts = [];
|
|
29
|
+
try {
|
|
30
|
+
if (query.where) {
|
|
31
|
+
assertSupportedWhere(query.where.expression);
|
|
32
|
+
const rewritten = rewriteWhereToOdataFilter(query.where.expression);
|
|
33
|
+
if (rewritten)
|
|
34
|
+
filterParts.push(rewritten);
|
|
35
|
+
}
|
|
36
|
+
if (parts.expression) {
|
|
37
|
+
filterParts.push(compileQueryFilterToOData(parts.expression, ctx, (node) => {
|
|
38
|
+
if (!source.geometryProperty) {
|
|
39
|
+
throw new Error("descriptor schema does not identify the OData geometry column");
|
|
40
|
+
}
|
|
41
|
+
if (node.operator !== "intersects" && node.operator !== "bbox-intersects") {
|
|
42
|
+
throw new Error(`OData v4 has no standard ${node.operator} geo function`);
|
|
43
|
+
}
|
|
44
|
+
return buildOdataSpatialFilter({
|
|
45
|
+
geometry: node.geometry.geometry,
|
|
46
|
+
geometryType: node.geometry.geometryType,
|
|
47
|
+
spatialRel: "esriSpatialRelIntersects",
|
|
48
|
+
}, { geometryColumn: source.geometryProperty });
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
if (query.spatialFilter) {
|
|
52
|
+
if (!source.geometryProperty) {
|
|
53
|
+
throw new Error("descriptor schema does not identify the OData geometry column");
|
|
54
|
+
}
|
|
55
|
+
filterParts.push(buildOdataSpatialFilter({
|
|
56
|
+
geometry: query.spatialFilter.geometry,
|
|
57
|
+
geometryType: query.spatialFilter.geometryType,
|
|
58
|
+
...(query.spatialFilter.spatialRel ? { spatialRel: query.spatialFilter.spatialRel } : {}),
|
|
59
|
+
}, { geometryColumn: source.geometryProperty }));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
throw new HonuaQueryPlanningError("unsupported-query", `OData query cannot preserve the requested predicate: ${error instanceof Error ? error.message : String(error)}`);
|
|
64
|
+
}
|
|
65
|
+
let projection;
|
|
66
|
+
if (query.outFields && query.outFields.length > 0) {
|
|
67
|
+
projection = splitProjection(query.outFields, query.returnGeometry === false ? source.geometryProperty : undefined);
|
|
68
|
+
if (query.returnGeometry !== false &&
|
|
69
|
+
source.geometryProperty &&
|
|
70
|
+
!projection.select.includes(source.geometryProperty)) {
|
|
71
|
+
projection = { ...projection, select: [...projection.select, source.geometryProperty] };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
else if (query.returnGeometry === false) {
|
|
75
|
+
throw new HonuaQueryPlanningError("unsupported-query", "Metadata-free OData planning requires explicit outFields to prove returnGeometry=false on the wire");
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
compiler: "odata-v4-query-v1",
|
|
79
|
+
entitySet: source.entitySet,
|
|
80
|
+
...(filterParts.length > 0 ? { filter: filterParts.join(" and ") } : {}),
|
|
81
|
+
...(projection && projection.select.length > 0 ? { select: projection.select } : {}),
|
|
82
|
+
...(projection && projection.expand.length > 0 ? { expand: projection.expand } : {}),
|
|
83
|
+
...(query.orderBy && query.orderBy.length > 0
|
|
84
|
+
? { orderBy: query.orderBy.map((sort) => `${sort.field}${sort.direction === "desc" ? " desc" : ""}`) }
|
|
85
|
+
: {}),
|
|
86
|
+
...(query.pagination?.offset !== undefined ? { skip: query.pagination.offset } : {}),
|
|
87
|
+
...(query.pagination?.limit !== undefined ? { top: query.pagination.limit } : {}),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* The deterministic compiler hook installed on the first-party OData
|
|
92
|
+
* ProtocolModule. Planner dispatch and module consumers call this exact
|
|
93
|
+
* object, while runtime authority remains outside the compiler.
|
|
94
|
+
*/
|
|
95
|
+
export const odataProtocolQueryCompiler = Object.freeze({
|
|
96
|
+
kind: "odata",
|
|
97
|
+
compile(input) {
|
|
98
|
+
return bindOdataProtocolQueryOperation(compileOdataQuery(input.source, input.query), input.operation);
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
/** Bind a legacy wire request to the exact operation authorized to execute it. */
|
|
102
|
+
export function bindOdataProtocolQueryOperation(compiled, operation) {
|
|
103
|
+
let top = compiled.top;
|
|
104
|
+
if (operation === "queryAll" && top !== undefined) {
|
|
105
|
+
if (!Number.isSafeInteger(top) || top < 0 || top >= Number.MAX_SAFE_INTEGER) {
|
|
106
|
+
throw new HonuaQueryPlanningError("invalid-query", "OData queryAll pagination.limit must leave room for one lookahead row");
|
|
107
|
+
}
|
|
108
|
+
top += 1;
|
|
109
|
+
}
|
|
110
|
+
return Object.freeze({
|
|
111
|
+
compiler: "odata-v4-protocol-query-v1",
|
|
112
|
+
operation,
|
|
113
|
+
entitySet: compiled.entitySet,
|
|
114
|
+
...(compiled.filter !== undefined ? { filter: compiled.filter } : {}),
|
|
115
|
+
...(compiled.select !== undefined ? { select: compiled.select } : {}),
|
|
116
|
+
...(compiled.expand !== undefined ? { expand: compiled.expand } : {}),
|
|
117
|
+
...(compiled.orderBy !== undefined ? { orderBy: compiled.orderBy } : {}),
|
|
118
|
+
...(compiled.skip !== undefined ? { skip: compiled.skip } : {}),
|
|
119
|
+
...(top !== undefined ? { top } : {}),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
function assertSupportedWhere(where) {
|
|
123
|
+
const code = outsideQuotedStrings(where);
|
|
124
|
+
if (code === undefined)
|
|
125
|
+
throw new Error("unterminated OData string literal");
|
|
126
|
+
const unsupported = [
|
|
127
|
+
{ expression: /\bLIKE\b/i, name: "LIKE" },
|
|
128
|
+
{ expression: /\bBETWEEN\b/i, name: "BETWEEN" },
|
|
129
|
+
{ expression: /==/, name: "==" },
|
|
130
|
+
{ expression: /!=/, name: "!=" },
|
|
131
|
+
{ expression: /;/, name: ";" },
|
|
132
|
+
];
|
|
133
|
+
for (const candidate of unsupported) {
|
|
134
|
+
if (candidate.expression.test(code)) {
|
|
135
|
+
throw new Error(`operator ${candidate.name} is not translated by the OData compiler`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/** Return only non-literal spans, or undefined for an unterminated literal. */
|
|
140
|
+
function outsideQuotedStrings(input) {
|
|
141
|
+
let output = "";
|
|
142
|
+
let quoted = false;
|
|
143
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
144
|
+
const character = input[index];
|
|
145
|
+
if (character !== "'") {
|
|
146
|
+
if (!quoted)
|
|
147
|
+
output += character;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (quoted && input[index + 1] === "'") {
|
|
151
|
+
index += 1;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
quoted = !quoted;
|
|
155
|
+
}
|
|
156
|
+
return quoted ? undefined : output;
|
|
157
|
+
}
|
|
158
|
+
function splitProjection(fields, excludedGeometry) {
|
|
159
|
+
const root = { select: [], children: new Map() };
|
|
160
|
+
for (const field of fields) {
|
|
161
|
+
if (excludedGeometry && field === excludedGeometry)
|
|
162
|
+
continue;
|
|
163
|
+
const segments = field.split(".").filter(Boolean);
|
|
164
|
+
if (segments.length === 0)
|
|
165
|
+
continue;
|
|
166
|
+
let cursor = root;
|
|
167
|
+
for (let index = 0; index < segments.length - 1; index += 1) {
|
|
168
|
+
const segment = segments[index];
|
|
169
|
+
if (!segment)
|
|
170
|
+
continue;
|
|
171
|
+
let child = cursor.children.get(segment);
|
|
172
|
+
if (!child) {
|
|
173
|
+
child = { select: [], children: new Map() };
|
|
174
|
+
cursor.children.set(segment, child);
|
|
175
|
+
}
|
|
176
|
+
cursor = child;
|
|
177
|
+
}
|
|
178
|
+
const leaf = segments.at(-1);
|
|
179
|
+
if (leaf)
|
|
180
|
+
cursor.select.push(leaf);
|
|
181
|
+
}
|
|
182
|
+
const serialize = (node) => {
|
|
183
|
+
const parts = [];
|
|
184
|
+
if (node.select.length > 0)
|
|
185
|
+
parts.push(`$select=${node.select.join(",")}`);
|
|
186
|
+
if (node.children.size > 0) {
|
|
187
|
+
const children = [...node.children.entries()].map(([name, child]) => {
|
|
188
|
+
const inner = serialize(child);
|
|
189
|
+
return inner ? `${name}(${inner})` : name;
|
|
190
|
+
});
|
|
191
|
+
parts.push(`$expand=${children.join(",")}`);
|
|
192
|
+
}
|
|
193
|
+
return parts.join(";");
|
|
194
|
+
};
|
|
195
|
+
return {
|
|
196
|
+
select: root.select,
|
|
197
|
+
expand: [...root.children.entries()].map(([name, child]) => {
|
|
198
|
+
const inner = serialize(child);
|
|
199
|
+
return inner ? `${name}(${inner})` : name;
|
|
200
|
+
}),
|
|
201
|
+
};
|
|
202
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { ExecutableCrsBinding, SourceSchemaV2 } from "../contract/schema.js";
|
|
2
|
+
import { type SemanticCompilationResult } from "./semantic-compiler.js";
|
|
3
|
+
import { type SemanticCompilerFieldMapping } from "./semantic-literals.js";
|
|
4
|
+
import type { SemanticQuery, SourceSpatiality } from "./semantic-types.js";
|
|
5
|
+
export type SemanticOdataSpatialFunction = "geo.intersects" | "geo.distance";
|
|
6
|
+
/** Static, credential-free OData endpoint evidence used by the semantic compiler. */
|
|
7
|
+
export interface SemanticOdataSourceIdentity {
|
|
8
|
+
readonly entitySet: string;
|
|
9
|
+
readonly sourceVersion?: string;
|
|
10
|
+
/** Spatial functions explicitly advertised or certified for this service. */
|
|
11
|
+
readonly supportedSpatialFunctions?: readonly SemanticOdataSpatialFunction[];
|
|
12
|
+
}
|
|
13
|
+
export interface SemanticOdataCompileOptions<TRecord = Record<string, unknown>, TSpatiality extends SourceSpatiality = SourceSpatiality> {
|
|
14
|
+
readonly query: SemanticQuery<TRecord, "odata", TSpatiality>;
|
|
15
|
+
readonly schema: SourceSchemaV2;
|
|
16
|
+
readonly source: SemanticOdataSourceIdentity;
|
|
17
|
+
}
|
|
18
|
+
export interface SemanticOdataOutputGeometry {
|
|
19
|
+
readonly field: string;
|
|
20
|
+
readonly propertyPath: string;
|
|
21
|
+
readonly spatialType: "geography" | "geometry";
|
|
22
|
+
readonly crs: ExecutableCrsBinding;
|
|
23
|
+
readonly layout: "xy";
|
|
24
|
+
}
|
|
25
|
+
/** Canonical pre-image of an OData v4 entity-set request. */
|
|
26
|
+
export interface SemanticOdataCompiledQueryV1 {
|
|
27
|
+
readonly compiler: "odata-v4-semantic-query-v1";
|
|
28
|
+
readonly dialect: "odata-4.0";
|
|
29
|
+
readonly schemaFingerprint: SourceSchemaV2["fingerprint"];
|
|
30
|
+
readonly queryFingerprint: `sha256:${string}`;
|
|
31
|
+
readonly requestFingerprint: `sha256:${string}`;
|
|
32
|
+
readonly entitySet: string;
|
|
33
|
+
readonly sourceVersion?: string;
|
|
34
|
+
readonly filter?: string;
|
|
35
|
+
readonly select: readonly string[];
|
|
36
|
+
readonly orderBy?: readonly string[];
|
|
37
|
+
readonly skip?: number;
|
|
38
|
+
readonly top?: number;
|
|
39
|
+
readonly outputGeometry?: SemanticOdataOutputGeometry;
|
|
40
|
+
readonly fieldMappings: readonly SemanticCompilerFieldMapping[];
|
|
41
|
+
readonly usesNativeFilter: boolean;
|
|
42
|
+
}
|
|
43
|
+
/** Compile a validated semantic AST to exact OData v4 system query options. */
|
|
44
|
+
export declare function compileSemanticOdataQuery<TRecord, TSpatiality extends SourceSpatiality>(options: SemanticOdataCompileOptions<TRecord, TSpatiality>): SemanticCompilationResult<SemanticOdataCompiledQueryV1>;
|
|
45
|
+
//# sourceMappingURL=odata.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"odata.d.ts","sourceRoot":"","sources":["../../../src/query-planner/odata.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,oBAAoB,EAOpB,cAAc,EACf,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAEL,KAAK,yBAAyB,EAO/B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,4BAA4B,EAWlC,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAe,aAAa,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAGxF,MAAM,MAAM,4BAA4B,GAAG,gBAAgB,GAAG,cAAc,CAAC;AAE7E,qFAAqF;AACrF,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,6EAA6E;IAC7E,QAAQ,CAAC,yBAAyB,CAAC,EAAE,SAAS,4BAA4B,EAAE,CAAC;CAC9E;AAED,MAAM,WAAW,2BAA2B,CAC1C,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,WAAW,SAAS,gBAAgB,GAAG,gBAAgB;IAEvD,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;IAC7D,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAC;CAC9C;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,WAAW,GAAG,UAAU,CAAC;IAC/C,QAAQ,CAAC,GAAG,EAAE,oBAAoB,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;CACvB;AAED,6DAA6D;AAC7D,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,QAAQ,EAAE,4BAA4B,CAAC;IAChD,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,iBAAiB,EAAE,cAAc,CAAC,aAAa,CAAC,CAAC;IAC1D,QAAQ,CAAC,gBAAgB,EAAE,UAAU,MAAM,EAAE,CAAC;IAC9C,QAAQ,CAAC,kBAAkB,EAAE,UAAU,MAAM,EAAE,CAAC;IAChD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,cAAc,CAAC,EAAE,2BAA2B,CAAC;IACtD,QAAQ,CAAC,aAAa,EAAE,SAAS,4BAA4B,EAAE,CAAC;IAChE,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;CACpC;AA0BD,+EAA+E;AAC/E,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,WAAW,SAAS,gBAAgB,EACrF,OAAO,EAAE,2BAA2B,CAAC,OAAO,EAAE,WAAW,CAAC,GACzD,yBAAyB,CAAC,4BAA4B,CAAC,CA4CzD"}
|