1
1
import type { UpsertableMap } from '@getodk/common/lib/collections/UpsertableMap.ts' ;
2
- import { filter } from '../lib/iterators/common.ts' ;
3
2
import type { XPathDOMAdapter } from './interface/XPathDOMAdapter.ts' ;
4
3
import type { XPathDOMOptimizableOperations } from './interface/XPathDOMOptimizableOperations.ts' ;
5
4
import type { XPathNode } from './interface/XPathNode.ts' ;
@@ -118,53 +117,6 @@ const extendNodeKindGuards = <T extends XPathNode>(
118
117
return Object . assign ( base , extensions ) ;
119
118
} ;
120
119
121
- type IterableNodeFilter < T extends XPathNode , U extends T > = ( nodes : Iterable < T > ) => Iterable < U > ;
122
-
123
- /**
124
- * Provides frequently used operations, such as filtering and sorting, on
125
- * {@link Iterable} sequences of an {@link XPathDOMAdapter}'s node
126
- * representation.
127
- */
128
- interface IterableOperations < T extends XPathNode > {
129
- readonly filterAttributes : IterableNodeFilter < T , AdapterAttribute < T > > ;
130
- readonly filterQualifiedNamedNodes : IterableNodeFilter < T , AdapterQualifiedNamedNode < T > > ;
131
- readonly filterComments : IterableNodeFilter < T , AdapterComment < T > > ;
132
- readonly filterNamespaceDeclarations : IterableNodeFilter < T , AdapterNamespaceDeclaration < T > > ;
133
- readonly filterProcessingInstructions : IterableNodeFilter < T , AdapterProcessingInstruction < T > > ;
134
- readonly filterTextNodes : IterableNodeFilter < T , AdapterText < T > > ;
135
-
136
- // Note: iterable -> array is intentional. Can't sort a lazy, arbitrary-order
137
- // sequence without iterating every item!
138
- readonly sortInDocumentOrder : ( nodes : Iterable < T > ) => readonly T [ ] ;
139
- }
140
-
141
- interface ExtendedIterableOperations < T extends XPathNode >
142
- extends ExtendedNodeKindGuards < T > ,
143
- IterableOperations < T > { }
144
-
145
- /**
146
- * Derives frequently used {@link IterableOperations | iterable operations} from an
147
- * {@link XPathDOMAdapter} and its derived
148
- * {@link NodeKindGuards | node kind predicates}.
149
- */
150
- const extendIterableOperations = < T extends XPathNode > (
151
- base : ExtendedNodeKindGuards < T >
152
- ) : ExtendedIterableOperations < T > => {
153
- const extensions : IterableOperations < T > = {
154
- filterAttributes : filter ( base . isAttribute ) ,
155
- filterQualifiedNamedNodes : filter ( base . isQualifiedNamedNode ) ,
156
- filterComments : filter ( base . isComment ) ,
157
- filterNamespaceDeclarations : filter ( base . isNamespaceDeclaration ) ,
158
- filterProcessingInstructions : filter ( base . isProcessingInstruction ) ,
159
- filterTextNodes : filter ( base . isText ) ,
160
- sortInDocumentOrder : ( nodes : Iterable < T > ) : readonly T [ ] => {
161
- return Array . from ( nodes ) . sort ( ( a , b ) => base . compareDocumentOrder ( a , b ) ) ;
162
- } ,
163
- } ;
164
-
165
- return Object . assign ( base , extensions ) ;
166
- } ;
167
-
168
120
type UniqueIDElementLookup < T extends XPathNode > = (
169
121
node : AdapterDocument < T > ,
170
122
id : string
@@ -180,29 +132,26 @@ const getElementByUniqueIdFactory = <T extends XPathNode>(
180
132
return adapterImplementation ;
181
133
}
182
134
183
- function * getElementDescendants ( node : AdapterParentNode < T > ) : Iterable < AdapterElement < T > > {
184
- if ( adapter . isElement ( node ) ) {
185
- yield node ;
186
- }
187
-
188
- for ( const element of adapter . getChildElements ( node ) ) {
189
- yield element ;
190
-
191
- yield * getElementDescendants ( element ) ;
135
+ const getElementByUniqueId = (
136
+ node : AdapterParentNode < T > ,
137
+ id : string
138
+ ) : AdapterElement < T > | null => {
139
+ if ( adapter . isElement ( node ) && getNamedAttributeValue ( node , 'id' ) === id ) {
140
+ return node ;
192
141
}
193
- }
194
142
195
- return ( node , id ) => {
196
- const containingDocument = adapter . getContainingDocument ( node ) ;
143
+ for ( const childElement of adapter . getChildElements ( node ) ) {
144
+ const element = getElementByUniqueId ( childElement , id ) ;
197
145
198
- for ( const element of getElementDescendants ( containingDocument ) ) {
199
- if ( getNamedAttributeValue ( element , 'id' ) === id ) {
146
+ if ( element != null ) {
200
147
return element ;
201
148
}
202
149
}
203
150
204
151
return null ;
205
152
} ;
153
+
154
+ return getElementByUniqueId ;
206
155
} ;
207
156
208
157
type QualifiedNamedAttributeValueLookup < T extends XPathNode > = (
@@ -286,7 +235,7 @@ const hasLocalNamedAttributeFactory = <T extends XPathNode>(
286
235
type LocalNamedChildElementsLookup < T extends XPathNode > = (
287
236
node : AdapterParentNode < T > ,
288
237
localName : string
289
- ) => Iterable < AdapterElement < T > > ;
238
+ ) => ReadonlyArray < AdapterElement < T > > ;
290
239
291
240
const getChildrenByLocalNameFactory = < T extends XPathNode > (
292
241
adapter : XPathDOMAdapter < T >
@@ -298,7 +247,7 @@ const getChildrenByLocalNameFactory = <T extends XPathNode>(
298
247
}
299
248
300
249
return ( node , localName ) => {
301
- return Array . from ( adapter . getChildElements ( node ) ) . filter ( ( element ) => {
250
+ return adapter . getChildElements ( node ) . filter ( ( element ) => {
302
251
return adapter . getLocalName ( element ) === localName ;
303
252
} ) ;
304
253
} ;
@@ -364,7 +313,7 @@ const getLastChildElementFactory = <T extends XPathNode>(
364
313
}
365
314
366
315
return ( node ) => {
367
- return Array . from ( adapter . getChildElements ( node ) ) . at ( - 1 ) ?? null ;
316
+ return adapter . getChildElements ( node ) . at ( - 1 ) ?? null ;
368
317
} ;
369
318
} ;
370
319
@@ -376,7 +325,7 @@ const getLastChildElementFactory = <T extends XPathNode>(
376
325
type OmitOptionalOptimizableOperations < T > = Omit < T , keyof XPathDOMOptimizableOperations < XPathNode > > ;
377
326
378
327
interface ExtendedOptimizableOperations < T extends XPathNode >
379
- extends OmitOptionalOptimizableOperations < ExtendedIterableOperations < T > > ,
328
+ extends OmitOptionalOptimizableOperations < ExtendedNodeKindGuards < T > > ,
380
329
XPathDOMOptimizableOperations < T > { }
381
330
382
331
/**
@@ -391,7 +340,7 @@ interface ExtendedOptimizableOperations<T extends XPathNode>
391
340
* will be derived from other aspects of the adapter's required APIs.
392
341
*/
393
342
const extendOptimizableOperations = < T extends XPathNode > (
394
- base : ExtendedIterableOperations < T >
343
+ base : ExtendedNodeKindGuards < T >
395
344
) : ExtendedOptimizableOperations < T > => {
396
345
const getLocalNamedAttributeValue = getLocalNamedAttributeValueFactory ( base ) ;
397
346
@@ -451,7 +400,6 @@ const derivedDOMProvider = <T>(base: T): DerivedDOMProvider & T => {
451
400
export interface XPathDOMProvider < T extends XPathNode >
452
401
extends OmitOptionalOptimizableOperations < XPathDOMAdapter < T > > ,
453
402
NodeKindGuards < T > ,
454
- IterableOperations < T > ,
455
403
XPathDOMOptimizableOperations < T > ,
456
404
DerivedDOMProvider { }
457
405
@@ -477,8 +425,7 @@ export const xpathDOMProvider = <T extends XPathNode>(
477
425
}
478
426
479
427
const extendedGuards = extendNodeKindGuards ( adapter ) ;
480
- const extendedIterableOperations = extendIterableOperations ( extendedGuards ) ;
481
- const exended = extendOptimizableOperations ( extendedIterableOperations ) ;
428
+ const exended = extendOptimizableOperations ( extendedGuards ) ;
482
429
483
430
return derivedDOMProvider ( exended ) ;
484
431
} ;
0 commit comments