@openmrs/esm-extensions 10.0.1-pre.5642 → 10.0.1-pre.5649

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.
@@ -1,3 +1,3 @@
1
- [0] Successfully compiled: 10 files with swc (141.67ms)
1
+ [0] Successfully compiled: 10 files with swc (187.86ms)
2
2
  [0] swc --strip-leading-paths src -d dist exited with code 0
3
3
  [1] tsc --project tsconfig.build.json exited with code 0
@@ -1 +1 @@
1
- {"version":3,"file":"extensions.d.ts","sourceRoot":"","sources":["../src/extensions.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAwBlC,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAQ9B,MAAM,SAAS,CAAC;AAyMjB;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,UAGzD;AAED,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,sBAAsB,EAC7B,WAAW,EAAE,MAAM,GAClB,qBAAqB,GAAG,SAAS,CAGnC;AAED,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS,CAG/F;AAED;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,CAAC,qBAAqB,EAAE,qBAAqB,KAAK,IAO7E,CAAC;AAEN;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,QA4B3D;AAED;;;;;;;GAOG;AACH,wBAAgB,MAAM,CAAC,iBAAiB,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,QAmBpE;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,iBAAiB,EAAE,MAAM,QAmBlD;AA4ID;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,wBAAwB,GAAG,KAAK,CAAC,iBAAiB,CAAC,CAOlH;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC,iBAAiB,CAAC,CAEjF;AAqBD;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAsC1E,CAAC;AAEL;;;GAGG;AACH,eAAO,MAAM,KAAK,EAAE,MAAM,IAOzB,CAAC"}
1
+ {"version":3,"file":"extensions.d.ts","sourceRoot":"","sources":["../src/extensions.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAwBlC,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAQ9B,MAAM,SAAS,CAAC;AAyMjB;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,UAGzD;AAED,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,sBAAsB,EAC7B,WAAW,EAAE,MAAM,GAClB,qBAAqB,GAAG,SAAS,CAGnC;AAED,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS,CAG/F;AAED;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,CAAC,qBAAqB,EAAE,qBAAqB,KAAK,IAO7E,CAAC;AAEN;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,QA4B3D;AAED;;;;;;;GAOG;AACH,wBAAgB,MAAM,CAAC,iBAAiB,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,QAmBpE;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,iBAAiB,EAAE,MAAM,QAmBlD;AAuJD;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,wBAAwB,GAAG,KAAK,CAAC,iBAAiB,CAAC,CAOlH;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC,iBAAiB,CAAC,CAEjF;AAsBD;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAsC1E,CAAC;AAEL;;;GAGG;AACH,eAAO,MAAM,KAAK,EAAE,MAAM,IAOzB,CAAC"}
@@ -292,6 +292,15 @@ export function getExtensionRegistration(extensionId) {
292
292
  }
293
293
  });
294
294
  }
295
+ /** Maps each ID to the index of its first occurrence, matching `Array.prototype.indexOf`. */ function indexById(ids) {
296
+ const index = new Map();
297
+ ids.forEach((id, i)=>{
298
+ if (!index.has(id)) {
299
+ index.set(id, i);
300
+ }
301
+ });
302
+ return index;
303
+ }
295
304
  /**
296
305
  * Get an order index for the extension. This will
297
306
  * come from either its configured order, its registered order
@@ -301,15 +310,15 @@ export function getExtensionRegistration(extensionId) {
301
310
  * those with no ordering information share the last band rather than taking a sentinel that can't be
302
311
  * compared against itself.
303
312
  */ function getOrder(extensionId, configuredOrder, registeredOrderIndex, attachedOrder) {
304
- const configuredIndex = configuredOrder.indexOf(extensionId);
305
- if (configuredIndex !== -1) {
313
+ const configuredIndex = configuredOrder.get(extensionId);
314
+ if (configuredIndex !== undefined) {
306
315
  return configuredIndex;
307
316
  } else if (registeredOrderIndex !== undefined) {
308
317
  // extensions that don't have a configured order should appear after those that do
309
318
  return 1000 + registeredOrderIndex;
310
319
  } else {
311
- const assignedIndex = attachedOrder.indexOf(extensionId);
312
- if (assignedIndex !== -1) {
320
+ const assignedIndex = attachedOrder.get(extensionId);
321
+ if (assignedIndex !== undefined) {
313
322
  // extensions that have neither a configured nor registered order should appear
314
323
  // after all others
315
324
  return 2000 + assignedIndex;
@@ -426,17 +435,22 @@ function calculateAssignedIds(config, attachedIds) {
426
435
  const removedIds = config.remove || [];
427
436
  const idOrder = config.order || [];
428
437
  const { extensions } = extensionInternalStore.getState();
429
- return [
438
+ const removed = new Set(removedIds);
439
+ const ids = [
430
440
  ...attachedIds,
431
441
  ...addedIds
432
- ].filter((id)=>!removedIds.includes(id)).sort((idA, idB)=>{
433
- const ai = getOrder(idA, idOrder, extensions[getExtensionNameFromId(idA)]?.order, attachedIds);
434
- const bi = getOrder(idB, idOrder, extensions[getExtensionNameFromId(idB)]?.order, attachedIds);
435
- // Ties keep their input order — `Array.prototype.sort` is stable, and the input is
436
- // `[...attachedIds, ...addedIds]`, so two extensions the ordering rules can't separate
437
- // come out in the order the code and the configuration declared them.
438
- return ai - bi;
439
- });
442
+ ].filter((id)=>!removed.has(id));
443
+ const configuredIndex = indexById(idOrder);
444
+ const attachedIndex = indexById(attachedIds);
445
+ // Computed once per ID: calling `getOrder` from the comparator makes the sort quadratic.
446
+ const order = new Map(ids.map((id)=>[
447
+ id,
448
+ getOrder(id, configuredIndex, extensions[getExtensionNameFromId(id)]?.order, attachedIndex)
449
+ ]));
450
+ // Ties keep their input order — `Array.prototype.sort` is stable, and the input is
451
+ // `[...attachedIds, ...addedIds]`, so two extensions the ordering rules can't separate
452
+ // come out in the order the code and the configuration declared them.
453
+ return ids.sort((idA, idB)=>order.get(idA) - order.get(idB));
440
454
  }
441
455
  /**
442
456
  * Used by by extension slots at mount time.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-extensions",
3
- "version": "10.0.1-pre.5642",
3
+ "version": "10.0.1-pre.5649",
4
4
  "license": "MPL-2.0",
5
5
  "description": "Coordinates extensions and extension points in the OpenMRS Frontend",
6
6
  "type": "module",
@@ -57,21 +57,21 @@
57
57
  "lodash-es": "^4.17.21"
58
58
  },
59
59
  "peerDependencies": {
60
- "@openmrs/esm-api": "^10.0.1-pre.5642",
61
- "@openmrs/esm-config": "^10.0.1-pre.5642",
62
- "@openmrs/esm-expression-evaluator": "^10.0.1-pre.5642",
63
- "@openmrs/esm-feature-flags": "^10.0.1-pre.5642",
64
- "@openmrs/esm-state": "^10.0.1-pre.5642",
65
- "@openmrs/esm-utils": "^10.0.1-pre.5642",
60
+ "@openmrs/esm-api": "^10.0.1-pre.5649",
61
+ "@openmrs/esm-config": "^10.0.1-pre.5649",
62
+ "@openmrs/esm-expression-evaluator": "^10.0.1-pre.5649",
63
+ "@openmrs/esm-feature-flags": "^10.0.1-pre.5649",
64
+ "@openmrs/esm-state": "^10.0.1-pre.5649",
65
+ "@openmrs/esm-utils": "^10.0.1-pre.5649",
66
66
  "single-spa": "6.x"
67
67
  },
68
68
  "devDependencies": {
69
- "@openmrs/esm-api": "10.0.1-pre.5642",
70
- "@openmrs/esm-config": "10.0.1-pre.5642",
71
- "@openmrs/esm-expression-evaluator": "10.0.1-pre.5642",
72
- "@openmrs/esm-feature-flags": "10.0.1-pre.5642",
73
- "@openmrs/esm-state": "10.0.1-pre.5642",
74
- "@openmrs/esm-utils": "10.0.1-pre.5642",
69
+ "@openmrs/esm-api": "10.0.1-pre.5649",
70
+ "@openmrs/esm-config": "10.0.1-pre.5649",
71
+ "@openmrs/esm-expression-evaluator": "10.0.1-pre.5649",
72
+ "@openmrs/esm-feature-flags": "10.0.1-pre.5649",
73
+ "@openmrs/esm-state": "10.0.1-pre.5649",
74
+ "@openmrs/esm-utils": "10.0.1-pre.5649",
75
75
  "@swc/cli": "0.8.1",
76
76
  "@swc/core": "1.15.21",
77
77
  "@vitest/coverage-v8": "^4.1.2",
package/src/extensions.ts CHANGED
@@ -387,6 +387,17 @@ export function detachAll(extensionSlotName: string) {
387
387
  });
388
388
  }
389
389
 
390
+ /** Maps each ID to the index of its first occurrence, matching `Array.prototype.indexOf`. */
391
+ function indexById(ids: Array<string>) {
392
+ const index = new Map<string, number>();
393
+ ids.forEach((id, i) => {
394
+ if (!index.has(id)) {
395
+ index.set(id, i);
396
+ }
397
+ });
398
+ return index;
399
+ }
400
+
390
401
  /**
391
402
  * Get an order index for the extension. This will
392
403
  * come from either its configured order, its registered order
@@ -398,19 +409,19 @@ export function detachAll(extensionSlotName: string) {
398
409
  */
399
410
  function getOrder(
400
411
  extensionId: string,
401
- configuredOrder: Array<string>,
412
+ configuredOrder: Map<string, number>,
402
413
  registeredOrderIndex: number | undefined,
403
- attachedOrder: Array<string>,
414
+ attachedOrder: Map<string, number>,
404
415
  ) {
405
- const configuredIndex = configuredOrder.indexOf(extensionId);
406
- if (configuredIndex !== -1) {
416
+ const configuredIndex = configuredOrder.get(extensionId);
417
+ if (configuredIndex !== undefined) {
407
418
  return configuredIndex;
408
419
  } else if (registeredOrderIndex !== undefined) {
409
420
  // extensions that don't have a configured order should appear after those that do
410
421
  return 1000 + registeredOrderIndex;
411
422
  } else {
412
- const assignedIndex = attachedOrder.indexOf(extensionId);
413
- if (assignedIndex !== -1) {
423
+ const assignedIndex = attachedOrder.get(extensionId);
424
+ if (assignedIndex !== undefined) {
414
425
  // extensions that have neither a configured nor registered order should appear
415
426
  // after all others
416
427
  return 2000 + assignedIndex;
@@ -566,18 +577,19 @@ function calculateAssignedIds(config: ExtensionSlotConfig, attachedIds: Array<st
566
577
  const removedIds = config.remove || [];
567
578
  const idOrder = config.order || [];
568
579
  const { extensions } = extensionInternalStore.getState();
580
+ const removed = new Set(removedIds);
581
+ const ids = [...attachedIds, ...addedIds].filter((id) => !removed.has(id));
582
+ const configuredIndex = indexById(idOrder);
583
+ const attachedIndex = indexById(attachedIds);
584
+ // Computed once per ID: calling `getOrder` from the comparator makes the sort quadratic.
585
+ const order = new Map(
586
+ ids.map((id) => [id, getOrder(id, configuredIndex, extensions[getExtensionNameFromId(id)]?.order, attachedIndex)]),
587
+ );
569
588
 
570
- return [...attachedIds, ...addedIds]
571
- .filter((id) => !removedIds.includes(id))
572
- .sort((idA, idB) => {
573
- const ai = getOrder(idA, idOrder, extensions[getExtensionNameFromId(idA)]?.order, attachedIds);
574
- const bi = getOrder(idB, idOrder, extensions[getExtensionNameFromId(idB)]?.order, attachedIds);
575
-
576
- // Ties keep their input order — `Array.prototype.sort` is stable, and the input is
577
- // `[...attachedIds, ...addedIds]`, so two extensions the ordering rules can't separate
578
- // come out in the order the code and the configuration declared them.
579
- return ai - bi;
580
- });
589
+ // Ties keep their input order — `Array.prototype.sort` is stable, and the input is
590
+ // `[...attachedIds, ...addedIds]`, so two extensions the ordering rules can't separate
591
+ // come out in the order the code and the configuration declared them.
592
+ return ids.sort((idA, idB) => order.get(idA)! - order.get(idB)!);
581
593
  }
582
594
 
583
595
  /**