@backstage/backend-test-utils 0.2.2 → 0.2.3-next.2
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/CHANGELOG.md +25 -11
- package/dist/index.cjs.js +602 -20
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +78 -3
- package/package.json +10 -7
package/dist/index.cjs.js
CHANGED
|
@@ -10,6 +10,7 @@ var uuid = require('uuid');
|
|
|
10
10
|
var backendAppApi = require('@backstage/backend-app-api');
|
|
11
11
|
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
12
12
|
var express = require('express');
|
|
13
|
+
var errors = require('@backstage/errors');
|
|
13
14
|
|
|
14
15
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
15
16
|
|
|
@@ -391,26 +392,26 @@ class MockIdentityService {
|
|
|
391
392
|
}
|
|
392
393
|
}
|
|
393
394
|
|
|
394
|
-
var __accessCheck = (obj, member, msg) => {
|
|
395
|
+
var __accessCheck$3 = (obj, member, msg) => {
|
|
395
396
|
if (!member.has(obj))
|
|
396
397
|
throw TypeError("Cannot " + msg);
|
|
397
398
|
};
|
|
398
|
-
var __privateGet = (obj, member, getter) => {
|
|
399
|
-
__accessCheck(obj, member, "read from private field");
|
|
399
|
+
var __privateGet$3 = (obj, member, getter) => {
|
|
400
|
+
__accessCheck$3(obj, member, "read from private field");
|
|
400
401
|
return getter ? getter.call(obj) : member.get(obj);
|
|
401
402
|
};
|
|
402
|
-
var __privateAdd = (obj, member, value) => {
|
|
403
|
+
var __privateAdd$3 = (obj, member, value) => {
|
|
403
404
|
if (member.has(obj))
|
|
404
405
|
throw TypeError("Cannot add the same private member more than once");
|
|
405
406
|
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
406
407
|
};
|
|
407
|
-
var __privateSet = (obj, member, value, setter) => {
|
|
408
|
-
__accessCheck(obj, member, "write to private field");
|
|
408
|
+
var __privateSet$3 = (obj, member, value, setter) => {
|
|
409
|
+
__accessCheck$3(obj, member, "write to private field");
|
|
409
410
|
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
410
411
|
return value;
|
|
411
412
|
};
|
|
412
|
-
var __privateMethod = (obj, member, method) => {
|
|
413
|
-
__accessCheck(obj, member, "access private method");
|
|
413
|
+
var __privateMethod$2 = (obj, member, method) => {
|
|
414
|
+
__accessCheck$3(obj, member, "access private method");
|
|
414
415
|
return method;
|
|
415
416
|
};
|
|
416
417
|
var _level, _meta, _log, log_fn;
|
|
@@ -423,11 +424,11 @@ const levels = {
|
|
|
423
424
|
};
|
|
424
425
|
const _MockRootLoggerService = class _MockRootLoggerService {
|
|
425
426
|
constructor(level, meta) {
|
|
426
|
-
__privateAdd(this, _log);
|
|
427
|
-
__privateAdd(this, _level, void 0);
|
|
428
|
-
__privateAdd(this, _meta, void 0);
|
|
429
|
-
__privateSet(this, _level, level);
|
|
430
|
-
__privateSet(this, _meta, meta);
|
|
427
|
+
__privateAdd$3(this, _log);
|
|
428
|
+
__privateAdd$3(this, _level, void 0);
|
|
429
|
+
__privateAdd$3(this, _meta, void 0);
|
|
430
|
+
__privateSet$3(this, _level, level);
|
|
431
|
+
__privateSet$3(this, _meta, meta);
|
|
431
432
|
}
|
|
432
433
|
static create(options) {
|
|
433
434
|
var _a;
|
|
@@ -438,19 +439,19 @@ const _MockRootLoggerService = class _MockRootLoggerService {
|
|
|
438
439
|
return new _MockRootLoggerService(levels[level], {});
|
|
439
440
|
}
|
|
440
441
|
error(message, meta) {
|
|
441
|
-
__privateMethod(this, _log, log_fn).call(this, "error", message, meta);
|
|
442
|
+
__privateMethod$2(this, _log, log_fn).call(this, "error", message, meta);
|
|
442
443
|
}
|
|
443
444
|
warn(message, meta) {
|
|
444
|
-
__privateMethod(this, _log, log_fn).call(this, "warn", message, meta);
|
|
445
|
+
__privateMethod$2(this, _log, log_fn).call(this, "warn", message, meta);
|
|
445
446
|
}
|
|
446
447
|
info(message, meta) {
|
|
447
|
-
__privateMethod(this, _log, log_fn).call(this, "info", message, meta);
|
|
448
|
+
__privateMethod$2(this, _log, log_fn).call(this, "info", message, meta);
|
|
448
449
|
}
|
|
449
450
|
debug(message, meta) {
|
|
450
|
-
__privateMethod(this, _log, log_fn).call(this, "debug", message, meta);
|
|
451
|
+
__privateMethod$2(this, _log, log_fn).call(this, "debug", message, meta);
|
|
451
452
|
}
|
|
452
453
|
child(meta) {
|
|
453
|
-
return new _MockRootLoggerService(__privateGet(this, _level), { ...__privateGet(this, _meta), ...meta });
|
|
454
|
+
return new _MockRootLoggerService(__privateGet$3(this, _level), { ...__privateGet$3(this, _meta), ...meta });
|
|
454
455
|
}
|
|
455
456
|
};
|
|
456
457
|
_level = new WeakMap();
|
|
@@ -459,8 +460,8 @@ _log = new WeakSet();
|
|
|
459
460
|
log_fn = function(level, message, meta) {
|
|
460
461
|
var _a;
|
|
461
462
|
const levelValue = (_a = levels[level]) != null ? _a : 0;
|
|
462
|
-
if (levelValue <= __privateGet(this, _level)) {
|
|
463
|
-
const labels = Object.entries(__privateGet(this, _meta)).map(([key, value]) => `${key}=${value}`).join(",");
|
|
463
|
+
if (levelValue <= __privateGet$3(this, _level)) {
|
|
464
|
+
const labels = Object.entries(__privateGet$3(this, _meta)).map(([key, value]) => `${key}=${value}`).join(",");
|
|
464
465
|
console[level](`${labels} ${message}`, meta);
|
|
465
466
|
}
|
|
466
467
|
};
|
|
@@ -475,6 +476,27 @@ function simpleFactory(ref, factory) {
|
|
|
475
476
|
}
|
|
476
477
|
}));
|
|
477
478
|
}
|
|
479
|
+
function simpleMock(ref, mockFactory) {
|
|
480
|
+
return (partialImpl) => {
|
|
481
|
+
const mock = mockFactory();
|
|
482
|
+
if (partialImpl) {
|
|
483
|
+
for (const [key, impl] of Object.entries(partialImpl)) {
|
|
484
|
+
if (typeof impl === "function") {
|
|
485
|
+
mock[key].mockImplementation(impl);
|
|
486
|
+
} else {
|
|
487
|
+
mock[key] = impl;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
return Object.assign(mock, {
|
|
492
|
+
factory: backendPluginApi.createServiceFactory({
|
|
493
|
+
service: ref,
|
|
494
|
+
deps: {},
|
|
495
|
+
factory: () => mock
|
|
496
|
+
})()
|
|
497
|
+
});
|
|
498
|
+
};
|
|
499
|
+
}
|
|
478
500
|
exports.mockServices = void 0;
|
|
479
501
|
((mockServices2) => {
|
|
480
502
|
function rootConfig(options) {
|
|
@@ -490,6 +512,13 @@ exports.mockServices = void 0;
|
|
|
490
512
|
mockServices2.rootLogger = rootLogger;
|
|
491
513
|
((rootLogger2) => {
|
|
492
514
|
rootLogger2.factory = simpleFactory(backendPluginApi.coreServices.rootLogger, rootLogger2);
|
|
515
|
+
rootLogger2.mock = simpleMock(backendPluginApi.coreServices.rootLogger, () => ({
|
|
516
|
+
child: jest.fn(),
|
|
517
|
+
debug: jest.fn(),
|
|
518
|
+
error: jest.fn(),
|
|
519
|
+
info: jest.fn(),
|
|
520
|
+
warn: jest.fn()
|
|
521
|
+
}));
|
|
493
522
|
})(rootLogger = mockServices2.rootLogger || (mockServices2.rootLogger = {}));
|
|
494
523
|
function tokenManager() {
|
|
495
524
|
return {
|
|
@@ -509,6 +538,10 @@ exports.mockServices = void 0;
|
|
|
509
538
|
backendPluginApi.coreServices.tokenManager,
|
|
510
539
|
tokenManager2
|
|
511
540
|
);
|
|
541
|
+
tokenManager2.mock = simpleMock(backendPluginApi.coreServices.tokenManager, () => ({
|
|
542
|
+
authenticate: jest.fn(),
|
|
543
|
+
getToken: jest.fn()
|
|
544
|
+
}));
|
|
512
545
|
})(tokenManager = mockServices2.tokenManager || (mockServices2.tokenManager = {}));
|
|
513
546
|
function identity() {
|
|
514
547
|
return new MockIdentityService();
|
|
@@ -516,33 +549,84 @@ exports.mockServices = void 0;
|
|
|
516
549
|
mockServices2.identity = identity;
|
|
517
550
|
((identity2) => {
|
|
518
551
|
identity2.factory = simpleFactory(backendPluginApi.coreServices.identity, identity2);
|
|
552
|
+
identity2.mock = simpleMock(backendPluginApi.coreServices.identity, () => ({
|
|
553
|
+
getIdentity: jest.fn()
|
|
554
|
+
}));
|
|
519
555
|
})(identity = mockServices2.identity || (mockServices2.identity = {}));
|
|
520
556
|
((cache2) => {
|
|
521
557
|
cache2.factory = backendAppApi.cacheServiceFactory;
|
|
558
|
+
cache2.mock = simpleMock(backendPluginApi.coreServices.cache, () => ({
|
|
559
|
+
delete: jest.fn(),
|
|
560
|
+
get: jest.fn(),
|
|
561
|
+
set: jest.fn(),
|
|
562
|
+
withOptions: jest.fn()
|
|
563
|
+
}));
|
|
522
564
|
})(mockServices2.cache || (mockServices2.cache = {}));
|
|
523
565
|
((database2) => {
|
|
524
566
|
database2.factory = backendAppApi.databaseServiceFactory;
|
|
567
|
+
database2.mock = simpleMock(backendPluginApi.coreServices.database, () => ({
|
|
568
|
+
getClient: jest.fn()
|
|
569
|
+
}));
|
|
525
570
|
})(mockServices2.database || (mockServices2.database = {}));
|
|
526
571
|
((httpRouter2) => {
|
|
527
572
|
httpRouter2.factory = backendAppApi.httpRouterServiceFactory;
|
|
573
|
+
httpRouter2.mock = simpleMock(backendPluginApi.coreServices.httpRouter, () => ({
|
|
574
|
+
use: jest.fn()
|
|
575
|
+
}));
|
|
528
576
|
})(mockServices2.httpRouter || (mockServices2.httpRouter = {}));
|
|
577
|
+
((rootHttpRouter2) => {
|
|
578
|
+
rootHttpRouter2.factory = backendAppApi.rootHttpRouterServiceFactory;
|
|
579
|
+
rootHttpRouter2.mock = simpleMock(backendPluginApi.coreServices.rootHttpRouter, () => ({
|
|
580
|
+
use: jest.fn()
|
|
581
|
+
}));
|
|
582
|
+
})(mockServices2.rootHttpRouter || (mockServices2.rootHttpRouter = {}));
|
|
529
583
|
((lifecycle2) => {
|
|
530
584
|
lifecycle2.factory = backendAppApi.lifecycleServiceFactory;
|
|
585
|
+
lifecycle2.mock = simpleMock(backendPluginApi.coreServices.lifecycle, () => ({
|
|
586
|
+
addShutdownHook: jest.fn(),
|
|
587
|
+
addStartupHook: jest.fn()
|
|
588
|
+
}));
|
|
531
589
|
})(mockServices2.lifecycle || (mockServices2.lifecycle = {}));
|
|
532
590
|
((logger2) => {
|
|
533
591
|
logger2.factory = backendAppApi.loggerServiceFactory;
|
|
592
|
+
logger2.mock = simpleMock(backendPluginApi.coreServices.logger, () => ({
|
|
593
|
+
child: jest.fn(),
|
|
594
|
+
debug: jest.fn(),
|
|
595
|
+
error: jest.fn(),
|
|
596
|
+
info: jest.fn(),
|
|
597
|
+
warn: jest.fn()
|
|
598
|
+
}));
|
|
534
599
|
})(mockServices2.logger || (mockServices2.logger = {}));
|
|
535
600
|
((permissions2) => {
|
|
536
601
|
permissions2.factory = backendAppApi.permissionsServiceFactory;
|
|
602
|
+
permissions2.mock = simpleMock(backendPluginApi.coreServices.permissions, () => ({
|
|
603
|
+
authorize: jest.fn(),
|
|
604
|
+
authorizeConditional: jest.fn()
|
|
605
|
+
}));
|
|
537
606
|
})(mockServices2.permissions || (mockServices2.permissions = {}));
|
|
538
607
|
((rootLifecycle2) => {
|
|
539
608
|
rootLifecycle2.factory = backendAppApi.rootLifecycleServiceFactory;
|
|
609
|
+
rootLifecycle2.mock = simpleMock(backendPluginApi.coreServices.rootLifecycle, () => ({
|
|
610
|
+
addShutdownHook: jest.fn(),
|
|
611
|
+
addStartupHook: jest.fn()
|
|
612
|
+
}));
|
|
540
613
|
})(mockServices2.rootLifecycle || (mockServices2.rootLifecycle = {}));
|
|
541
614
|
((scheduler2) => {
|
|
542
615
|
scheduler2.factory = backendAppApi.schedulerServiceFactory;
|
|
616
|
+
scheduler2.mock = simpleMock(backendPluginApi.coreServices.scheduler, () => ({
|
|
617
|
+
createScheduledTaskRunner: jest.fn(),
|
|
618
|
+
getScheduledTasks: jest.fn(),
|
|
619
|
+
scheduleTask: jest.fn(),
|
|
620
|
+
triggerTask: jest.fn()
|
|
621
|
+
}));
|
|
543
622
|
})(mockServices2.scheduler || (mockServices2.scheduler = {}));
|
|
544
623
|
((urlReader2) => {
|
|
545
624
|
urlReader2.factory = backendAppApi.urlReaderServiceFactory;
|
|
625
|
+
urlReader2.mock = simpleMock(backendPluginApi.coreServices.urlReader, () => ({
|
|
626
|
+
readTree: jest.fn(),
|
|
627
|
+
readUrl: jest.fn(),
|
|
628
|
+
search: jest.fn()
|
|
629
|
+
}));
|
|
546
630
|
})(mockServices2.urlReader || (mockServices2.urlReader = {}));
|
|
547
631
|
})(exports.mockServices || (exports.mockServices = {}));
|
|
548
632
|
|
|
@@ -729,6 +813,504 @@ function isInternalBackendFeature(feature) {
|
|
|
729
813
|
return typeof feature.getRegistrations === "function";
|
|
730
814
|
}
|
|
731
815
|
|
|
816
|
+
var __accessCheck$2 = (obj, member, msg) => {
|
|
817
|
+
if (!member.has(obj))
|
|
818
|
+
throw TypeError("Cannot " + msg);
|
|
819
|
+
};
|
|
820
|
+
var __privateGet$2 = (obj, member, getter) => {
|
|
821
|
+
__accessCheck$2(obj, member, "read from private field");
|
|
822
|
+
return getter ? getter.call(obj) : member.get(obj);
|
|
823
|
+
};
|
|
824
|
+
var __privateAdd$2 = (obj, member, value) => {
|
|
825
|
+
if (member.has(obj))
|
|
826
|
+
throw TypeError("Cannot add the same private member more than once");
|
|
827
|
+
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
828
|
+
};
|
|
829
|
+
var __privateSet$2 = (obj, member, value, setter) => {
|
|
830
|
+
__accessCheck$2(obj, member, "write to private field");
|
|
831
|
+
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
832
|
+
return value;
|
|
833
|
+
};
|
|
834
|
+
var __privateMethod$1 = (obj, member, method) => {
|
|
835
|
+
__accessCheck$2(obj, member, "access private method");
|
|
836
|
+
return method;
|
|
837
|
+
};
|
|
838
|
+
var _nodeIds, _cycleKeys, _getCycleKey, getCycleKey_fn, _nodes, _allProvided;
|
|
839
|
+
class Node {
|
|
840
|
+
constructor(value, consumes, provides) {
|
|
841
|
+
this.value = value;
|
|
842
|
+
this.consumes = consumes;
|
|
843
|
+
this.provides = provides;
|
|
844
|
+
}
|
|
845
|
+
static from(input) {
|
|
846
|
+
return new Node(
|
|
847
|
+
input.value,
|
|
848
|
+
input.consumes ? new Set(input.consumes) : /* @__PURE__ */ new Set(),
|
|
849
|
+
input.provides ? new Set(input.provides) : /* @__PURE__ */ new Set()
|
|
850
|
+
);
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
const _CycleKeySet = class _CycleKeySet {
|
|
854
|
+
constructor(nodes) {
|
|
855
|
+
__privateAdd$2(this, _getCycleKey);
|
|
856
|
+
__privateAdd$2(this, _nodeIds, void 0);
|
|
857
|
+
__privateAdd$2(this, _cycleKeys, void 0);
|
|
858
|
+
__privateSet$2(this, _nodeIds, new Map(nodes.map((n, i) => [n.value, i])));
|
|
859
|
+
__privateSet$2(this, _cycleKeys, /* @__PURE__ */ new Set());
|
|
860
|
+
}
|
|
861
|
+
static from(nodes) {
|
|
862
|
+
return new _CycleKeySet(nodes);
|
|
863
|
+
}
|
|
864
|
+
tryAdd(path) {
|
|
865
|
+
const cycleKey = __privateMethod$1(this, _getCycleKey, getCycleKey_fn).call(this, path);
|
|
866
|
+
if (__privateGet$2(this, _cycleKeys).has(cycleKey)) {
|
|
867
|
+
return false;
|
|
868
|
+
}
|
|
869
|
+
__privateGet$2(this, _cycleKeys).add(cycleKey);
|
|
870
|
+
return true;
|
|
871
|
+
}
|
|
872
|
+
};
|
|
873
|
+
_nodeIds = new WeakMap();
|
|
874
|
+
_cycleKeys = new WeakMap();
|
|
875
|
+
_getCycleKey = new WeakSet();
|
|
876
|
+
getCycleKey_fn = function(path) {
|
|
877
|
+
return path.map((n) => __privateGet$2(this, _nodeIds).get(n)).sort().join(",");
|
|
878
|
+
};
|
|
879
|
+
let CycleKeySet = _CycleKeySet;
|
|
880
|
+
const _DependencyGraph = class _DependencyGraph {
|
|
881
|
+
constructor(nodes) {
|
|
882
|
+
__privateAdd$2(this, _nodes, void 0);
|
|
883
|
+
__privateAdd$2(this, _allProvided, void 0);
|
|
884
|
+
__privateSet$2(this, _nodes, nodes);
|
|
885
|
+
__privateSet$2(this, _allProvided, /* @__PURE__ */ new Set());
|
|
886
|
+
for (const node of __privateGet$2(this, _nodes).values()) {
|
|
887
|
+
for (const produced of node.provides) {
|
|
888
|
+
__privateGet$2(this, _allProvided).add(produced);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
static fromMap(nodes) {
|
|
893
|
+
return this.fromIterable(
|
|
894
|
+
Object.entries(nodes).map(([key, node]) => ({
|
|
895
|
+
value: String(key),
|
|
896
|
+
...node
|
|
897
|
+
}))
|
|
898
|
+
);
|
|
899
|
+
}
|
|
900
|
+
static fromIterable(nodeInputs) {
|
|
901
|
+
const nodes = new Array();
|
|
902
|
+
for (const nodeInput of nodeInputs) {
|
|
903
|
+
nodes.push(Node.from(nodeInput));
|
|
904
|
+
}
|
|
905
|
+
return new _DependencyGraph(nodes);
|
|
906
|
+
}
|
|
907
|
+
/**
|
|
908
|
+
* Find all nodes that consume dependencies that are not provided by any other node.
|
|
909
|
+
*/
|
|
910
|
+
findUnsatisfiedDeps() {
|
|
911
|
+
const unsatisfiedDependencies = [];
|
|
912
|
+
for (const node of __privateGet$2(this, _nodes).values()) {
|
|
913
|
+
const unsatisfied = Array.from(node.consumes).filter(
|
|
914
|
+
(id) => !__privateGet$2(this, _allProvided).has(id)
|
|
915
|
+
);
|
|
916
|
+
if (unsatisfied.length > 0) {
|
|
917
|
+
unsatisfiedDependencies.push({ value: node.value, unsatisfied });
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
return unsatisfiedDependencies;
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* Detect the first circular dependency within the graph, returning the path of nodes that
|
|
924
|
+
* form a cycle, with the same node as the first and last element of the array.
|
|
925
|
+
*/
|
|
926
|
+
detectCircularDependency() {
|
|
927
|
+
return this.detectCircularDependencies().next().value;
|
|
928
|
+
}
|
|
929
|
+
/**
|
|
930
|
+
* Detect circular dependencies within the graph, returning the path of nodes that
|
|
931
|
+
* form a cycle, with the same node as the first and last element of the array.
|
|
932
|
+
*/
|
|
933
|
+
*detectCircularDependencies() {
|
|
934
|
+
const cycleKeys = CycleKeySet.from(__privateGet$2(this, _nodes));
|
|
935
|
+
for (const startNode of __privateGet$2(this, _nodes)) {
|
|
936
|
+
const visited = /* @__PURE__ */ new Set();
|
|
937
|
+
const stack = new Array([
|
|
938
|
+
startNode,
|
|
939
|
+
[startNode.value]
|
|
940
|
+
]);
|
|
941
|
+
while (stack.length > 0) {
|
|
942
|
+
const [node, path] = stack.pop();
|
|
943
|
+
if (visited.has(node)) {
|
|
944
|
+
continue;
|
|
945
|
+
}
|
|
946
|
+
visited.add(node);
|
|
947
|
+
for (const consumed of node.consumes) {
|
|
948
|
+
const providerNodes = __privateGet$2(this, _nodes).filter(
|
|
949
|
+
(other) => other.provides.has(consumed)
|
|
950
|
+
);
|
|
951
|
+
for (const provider of providerNodes) {
|
|
952
|
+
if (provider === startNode) {
|
|
953
|
+
if (cycleKeys.tryAdd(path)) {
|
|
954
|
+
yield [...path, startNode.value];
|
|
955
|
+
}
|
|
956
|
+
break;
|
|
957
|
+
}
|
|
958
|
+
if (!visited.has(provider)) {
|
|
959
|
+
stack.push([provider, [...path, provider.value]]);
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
return void 0;
|
|
966
|
+
}
|
|
967
|
+
/**
|
|
968
|
+
* Traverses the dependency graph in topological order, calling the provided
|
|
969
|
+
* function for each node and waiting for it to resolve.
|
|
970
|
+
*
|
|
971
|
+
* The nodes are traversed in parallel, but in such a way that no node is
|
|
972
|
+
* visited before all of its dependencies.
|
|
973
|
+
*
|
|
974
|
+
* Dependencies of nodes that are not produced by any other nodes will be ignored.
|
|
975
|
+
*/
|
|
976
|
+
async parallelTopologicalTraversal(fn) {
|
|
977
|
+
const allProvided = __privateGet$2(this, _allProvided);
|
|
978
|
+
const producedSoFar = /* @__PURE__ */ new Set();
|
|
979
|
+
const waiting = new Set(__privateGet$2(this, _nodes).values());
|
|
980
|
+
const visited = /* @__PURE__ */ new Set();
|
|
981
|
+
const results = new Array();
|
|
982
|
+
let inFlight = 0;
|
|
983
|
+
async function processMoreNodes() {
|
|
984
|
+
if (waiting.size === 0) {
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
const nodesToProcess = [];
|
|
988
|
+
for (const node of waiting) {
|
|
989
|
+
let ready = true;
|
|
990
|
+
for (const consumed of node.consumes) {
|
|
991
|
+
if (allProvided.has(consumed) && !producedSoFar.has(consumed)) {
|
|
992
|
+
ready = false;
|
|
993
|
+
continue;
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
if (ready) {
|
|
997
|
+
nodesToProcess.push(node);
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
for (const node of nodesToProcess) {
|
|
1001
|
+
waiting.delete(node);
|
|
1002
|
+
}
|
|
1003
|
+
if (nodesToProcess.length === 0 && inFlight === 0) {
|
|
1004
|
+
throw new Error("Circular dependency detected");
|
|
1005
|
+
}
|
|
1006
|
+
await Promise.all(nodesToProcess.map(processNode));
|
|
1007
|
+
}
|
|
1008
|
+
async function processNode(node) {
|
|
1009
|
+
visited.add(node);
|
|
1010
|
+
inFlight += 1;
|
|
1011
|
+
const result = await fn(node.value);
|
|
1012
|
+
results.push(result);
|
|
1013
|
+
node.provides.forEach((produced) => producedSoFar.add(produced));
|
|
1014
|
+
inFlight -= 1;
|
|
1015
|
+
await processMoreNodes();
|
|
1016
|
+
}
|
|
1017
|
+
await processMoreNodes();
|
|
1018
|
+
return results;
|
|
1019
|
+
}
|
|
1020
|
+
};
|
|
1021
|
+
_nodes = new WeakMap();
|
|
1022
|
+
_allProvided = new WeakMap();
|
|
1023
|
+
let DependencyGraph = _DependencyGraph;
|
|
1024
|
+
|
|
1025
|
+
var __accessCheck$1 = (obj, member, msg) => {
|
|
1026
|
+
if (!member.has(obj))
|
|
1027
|
+
throw TypeError("Cannot " + msg);
|
|
1028
|
+
};
|
|
1029
|
+
var __privateGet$1 = (obj, member, getter) => {
|
|
1030
|
+
__accessCheck$1(obj, member, "read from private field");
|
|
1031
|
+
return getter ? getter.call(obj) : member.get(obj);
|
|
1032
|
+
};
|
|
1033
|
+
var __privateAdd$1 = (obj, member, value) => {
|
|
1034
|
+
if (member.has(obj))
|
|
1035
|
+
throw TypeError("Cannot add the same private member more than once");
|
|
1036
|
+
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
1037
|
+
};
|
|
1038
|
+
var __privateSet$1 = (obj, member, value, setter) => {
|
|
1039
|
+
__accessCheck$1(obj, member, "write to private field");
|
|
1040
|
+
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
1041
|
+
return value;
|
|
1042
|
+
};
|
|
1043
|
+
var __privateMethod = (obj, member, method) => {
|
|
1044
|
+
__accessCheck$1(obj, member, "access private method");
|
|
1045
|
+
return method;
|
|
1046
|
+
};
|
|
1047
|
+
var _providedFactories, _loadedDefaultFactories, _implementations, _rootServiceImplementations, _resolveFactory, resolveFactory_fn, _checkForMissingDeps, checkForMissingDeps_fn, _checkForCircularDeps, checkForCircularDeps_fn;
|
|
1048
|
+
function toInternalServiceFactory(factory) {
|
|
1049
|
+
const f = factory;
|
|
1050
|
+
if (f.$$type !== "@backstage/BackendFeature") {
|
|
1051
|
+
throw new Error(`Invalid service factory, bad type '${f.$$type}'`);
|
|
1052
|
+
}
|
|
1053
|
+
if (f.version !== "v1") {
|
|
1054
|
+
throw new Error(`Invalid service factory, bad version '${f.version}'`);
|
|
1055
|
+
}
|
|
1056
|
+
return f;
|
|
1057
|
+
}
|
|
1058
|
+
const pluginMetadataServiceFactory = backendPluginApi.createServiceFactory(
|
|
1059
|
+
(options) => ({
|
|
1060
|
+
service: backendPluginApi.coreServices.pluginMetadata,
|
|
1061
|
+
deps: {},
|
|
1062
|
+
factory: async () => ({ getId: () => options == null ? void 0 : options.pluginId })
|
|
1063
|
+
})
|
|
1064
|
+
);
|
|
1065
|
+
const _ServiceRegistry = class _ServiceRegistry {
|
|
1066
|
+
constructor(factories) {
|
|
1067
|
+
__privateAdd$1(this, _resolveFactory);
|
|
1068
|
+
__privateAdd$1(this, _checkForMissingDeps);
|
|
1069
|
+
__privateAdd$1(this, _checkForCircularDeps);
|
|
1070
|
+
__privateAdd$1(this, _providedFactories, void 0);
|
|
1071
|
+
__privateAdd$1(this, _loadedDefaultFactories, void 0);
|
|
1072
|
+
__privateAdd$1(this, _implementations, void 0);
|
|
1073
|
+
__privateAdd$1(this, _rootServiceImplementations, /* @__PURE__ */ new Map());
|
|
1074
|
+
__privateSet$1(this, _providedFactories, new Map(
|
|
1075
|
+
factories.map((sf) => [sf.service.id, toInternalServiceFactory(sf)])
|
|
1076
|
+
));
|
|
1077
|
+
__privateSet$1(this, _loadedDefaultFactories, /* @__PURE__ */ new Map());
|
|
1078
|
+
__privateSet$1(this, _implementations, /* @__PURE__ */ new Map());
|
|
1079
|
+
}
|
|
1080
|
+
static create(factories) {
|
|
1081
|
+
var _a;
|
|
1082
|
+
const registry = new _ServiceRegistry(factories);
|
|
1083
|
+
__privateMethod(_a = registry, _checkForCircularDeps, checkForCircularDeps_fn).call(_a);
|
|
1084
|
+
return registry;
|
|
1085
|
+
}
|
|
1086
|
+
getServiceRefs() {
|
|
1087
|
+
return Array.from(__privateGet$1(this, _providedFactories).values()).map((f) => f.service);
|
|
1088
|
+
}
|
|
1089
|
+
get(ref, pluginId) {
|
|
1090
|
+
var _a;
|
|
1091
|
+
return (_a = __privateMethod(this, _resolveFactory, resolveFactory_fn).call(this, ref, pluginId)) == null ? void 0 : _a.then((factory) => {
|
|
1092
|
+
if (factory.service.scope === "root") {
|
|
1093
|
+
let existing = __privateGet$1(this, _rootServiceImplementations).get(factory);
|
|
1094
|
+
if (!existing) {
|
|
1095
|
+
__privateMethod(this, _checkForMissingDeps, checkForMissingDeps_fn).call(this, factory, pluginId);
|
|
1096
|
+
const rootDeps = new Array();
|
|
1097
|
+
for (const [name, serviceRef] of Object.entries(factory.deps)) {
|
|
1098
|
+
if (serviceRef.scope !== "root") {
|
|
1099
|
+
throw new Error(
|
|
1100
|
+
`Failed to instantiate 'root' scoped service '${ref.id}' because it depends on '${serviceRef.scope}' scoped service '${serviceRef.id}'.`
|
|
1101
|
+
);
|
|
1102
|
+
}
|
|
1103
|
+
const target = this.get(serviceRef, pluginId);
|
|
1104
|
+
rootDeps.push(target.then((impl) => [name, impl]));
|
|
1105
|
+
}
|
|
1106
|
+
existing = Promise.all(rootDeps).then(
|
|
1107
|
+
(entries) => factory.factory(Object.fromEntries(entries), void 0)
|
|
1108
|
+
);
|
|
1109
|
+
__privateGet$1(this, _rootServiceImplementations).set(factory, existing);
|
|
1110
|
+
}
|
|
1111
|
+
return existing;
|
|
1112
|
+
}
|
|
1113
|
+
let implementation = __privateGet$1(this, _implementations).get(factory);
|
|
1114
|
+
if (!implementation) {
|
|
1115
|
+
__privateMethod(this, _checkForMissingDeps, checkForMissingDeps_fn).call(this, factory, pluginId);
|
|
1116
|
+
const rootDeps = new Array();
|
|
1117
|
+
for (const [name, serviceRef] of Object.entries(factory.deps)) {
|
|
1118
|
+
if (serviceRef.scope === "root") {
|
|
1119
|
+
const target = this.get(serviceRef, pluginId);
|
|
1120
|
+
rootDeps.push(target.then((impl) => [name, impl]));
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
implementation = {
|
|
1124
|
+
context: Promise.all(rootDeps).then(
|
|
1125
|
+
(entries) => {
|
|
1126
|
+
var _a2;
|
|
1127
|
+
return (_a2 = factory.createRootContext) == null ? void 0 : _a2.call(factory, Object.fromEntries(entries));
|
|
1128
|
+
}
|
|
1129
|
+
).catch((error) => {
|
|
1130
|
+
const cause = errors.stringifyError(error);
|
|
1131
|
+
throw new Error(
|
|
1132
|
+
`Failed to instantiate service '${ref.id}' because createRootContext threw an error, ${cause}`
|
|
1133
|
+
);
|
|
1134
|
+
}),
|
|
1135
|
+
byPlugin: /* @__PURE__ */ new Map()
|
|
1136
|
+
};
|
|
1137
|
+
__privateGet$1(this, _implementations).set(factory, implementation);
|
|
1138
|
+
}
|
|
1139
|
+
let result = implementation.byPlugin.get(pluginId);
|
|
1140
|
+
if (!result) {
|
|
1141
|
+
const allDeps = new Array();
|
|
1142
|
+
for (const [name, serviceRef] of Object.entries(factory.deps)) {
|
|
1143
|
+
const target = this.get(serviceRef, pluginId);
|
|
1144
|
+
allDeps.push(target.then((impl) => [name, impl]));
|
|
1145
|
+
}
|
|
1146
|
+
result = implementation.context.then(
|
|
1147
|
+
(context) => Promise.all(allDeps).then(
|
|
1148
|
+
(entries) => factory.factory(Object.fromEntries(entries), context)
|
|
1149
|
+
)
|
|
1150
|
+
).catch((error) => {
|
|
1151
|
+
const cause = errors.stringifyError(error);
|
|
1152
|
+
throw new Error(
|
|
1153
|
+
`Failed to instantiate service '${ref.id}' for '${pluginId}' because the factory function threw an error, ${cause}`
|
|
1154
|
+
);
|
|
1155
|
+
});
|
|
1156
|
+
implementation.byPlugin.set(pluginId, result);
|
|
1157
|
+
}
|
|
1158
|
+
return result;
|
|
1159
|
+
});
|
|
1160
|
+
}
|
|
1161
|
+
};
|
|
1162
|
+
_providedFactories = new WeakMap();
|
|
1163
|
+
_loadedDefaultFactories = new WeakMap();
|
|
1164
|
+
_implementations = new WeakMap();
|
|
1165
|
+
_rootServiceImplementations = new WeakMap();
|
|
1166
|
+
_resolveFactory = new WeakSet();
|
|
1167
|
+
resolveFactory_fn = function(ref, pluginId) {
|
|
1168
|
+
if (ref.id === backendPluginApi.coreServices.pluginMetadata.id) {
|
|
1169
|
+
return Promise.resolve(
|
|
1170
|
+
toInternalServiceFactory(pluginMetadataServiceFactory({ pluginId }))
|
|
1171
|
+
);
|
|
1172
|
+
}
|
|
1173
|
+
let resolvedFactory = __privateGet$1(this, _providedFactories).get(ref.id);
|
|
1174
|
+
const { __defaultFactory: defaultFactory } = ref;
|
|
1175
|
+
if (!resolvedFactory && !defaultFactory) {
|
|
1176
|
+
return void 0;
|
|
1177
|
+
}
|
|
1178
|
+
if (!resolvedFactory) {
|
|
1179
|
+
let loadedFactory = __privateGet$1(this, _loadedDefaultFactories).get(defaultFactory);
|
|
1180
|
+
if (!loadedFactory) {
|
|
1181
|
+
loadedFactory = Promise.resolve().then(() => defaultFactory(ref)).then(
|
|
1182
|
+
(f) => toInternalServiceFactory(typeof f === "function" ? f() : f)
|
|
1183
|
+
);
|
|
1184
|
+
__privateGet$1(this, _loadedDefaultFactories).set(defaultFactory, loadedFactory);
|
|
1185
|
+
}
|
|
1186
|
+
resolvedFactory = loadedFactory.catch((error) => {
|
|
1187
|
+
throw new Error(
|
|
1188
|
+
`Failed to instantiate service '${ref.id}' because the default factory loader threw an error, ${errors.stringifyError(
|
|
1189
|
+
error
|
|
1190
|
+
)}`
|
|
1191
|
+
);
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
return Promise.resolve(resolvedFactory);
|
|
1195
|
+
};
|
|
1196
|
+
_checkForMissingDeps = new WeakSet();
|
|
1197
|
+
checkForMissingDeps_fn = function(factory, pluginId) {
|
|
1198
|
+
const missingDeps = Object.values(factory.deps).filter((ref) => {
|
|
1199
|
+
if (ref.id === backendPluginApi.coreServices.pluginMetadata.id) {
|
|
1200
|
+
return false;
|
|
1201
|
+
}
|
|
1202
|
+
if (__privateGet$1(this, _providedFactories).get(ref.id)) {
|
|
1203
|
+
return false;
|
|
1204
|
+
}
|
|
1205
|
+
return !ref.__defaultFactory;
|
|
1206
|
+
});
|
|
1207
|
+
if (missingDeps.length) {
|
|
1208
|
+
const missing = missingDeps.map((r) => `'${r.id}'`).join(", ");
|
|
1209
|
+
throw new Error(
|
|
1210
|
+
`Failed to instantiate service '${factory.service.id}' for '${pluginId}' because the following dependent services are missing: ${missing}`
|
|
1211
|
+
);
|
|
1212
|
+
}
|
|
1213
|
+
};
|
|
1214
|
+
_checkForCircularDeps = new WeakSet();
|
|
1215
|
+
checkForCircularDeps_fn = function() {
|
|
1216
|
+
const graph = DependencyGraph.fromIterable(
|
|
1217
|
+
Array.from(__privateGet$1(this, _providedFactories)).map(
|
|
1218
|
+
([serviceId, serviceFactory]) => ({
|
|
1219
|
+
value: serviceId,
|
|
1220
|
+
provides: [serviceId],
|
|
1221
|
+
consumes: Object.values(serviceFactory.deps).map((d) => d.id)
|
|
1222
|
+
})
|
|
1223
|
+
)
|
|
1224
|
+
);
|
|
1225
|
+
const circularDependencies = Array.from(graph.detectCircularDependencies());
|
|
1226
|
+
if (circularDependencies.length) {
|
|
1227
|
+
const cycles = circularDependencies.map((c) => c.map((id) => `'${id}'`).join(" -> ")).join("\n ");
|
|
1228
|
+
throw new errors.ConflictError(`Circular dependencies detected:
|
|
1229
|
+
${cycles}`);
|
|
1230
|
+
}
|
|
1231
|
+
};
|
|
1232
|
+
let ServiceRegistry = _ServiceRegistry;
|
|
1233
|
+
|
|
1234
|
+
var __accessCheck = (obj, member, msg) => {
|
|
1235
|
+
if (!member.has(obj))
|
|
1236
|
+
throw TypeError("Cannot " + msg);
|
|
1237
|
+
};
|
|
1238
|
+
var __privateGet = (obj, member, getter) => {
|
|
1239
|
+
__accessCheck(obj, member, "read from private field");
|
|
1240
|
+
return getter ? getter.call(obj) : member.get(obj);
|
|
1241
|
+
};
|
|
1242
|
+
var __privateAdd = (obj, member, value) => {
|
|
1243
|
+
if (member.has(obj))
|
|
1244
|
+
throw TypeError("Cannot add the same private member more than once");
|
|
1245
|
+
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
1246
|
+
};
|
|
1247
|
+
var __privateSet = (obj, member, value, setter) => {
|
|
1248
|
+
__accessCheck(obj, member, "write to private field");
|
|
1249
|
+
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
1250
|
+
return value;
|
|
1251
|
+
};
|
|
1252
|
+
var _subject, _registry;
|
|
1253
|
+
const _ServiceFactoryTester = class _ServiceFactoryTester {
|
|
1254
|
+
constructor(subject, registry) {
|
|
1255
|
+
__privateAdd(this, _subject, void 0);
|
|
1256
|
+
__privateAdd(this, _registry, void 0);
|
|
1257
|
+
__privateSet(this, _subject, subject);
|
|
1258
|
+
__privateSet(this, _registry, registry);
|
|
1259
|
+
}
|
|
1260
|
+
/**
|
|
1261
|
+
* Creates a new {@link ServiceFactoryTester} used to test the provided subject.
|
|
1262
|
+
*
|
|
1263
|
+
* @param subject - The service factory to test.
|
|
1264
|
+
* @param options - Additional options
|
|
1265
|
+
* @returns A new tester instance for the provided subject.
|
|
1266
|
+
*/
|
|
1267
|
+
static from(subject, options) {
|
|
1268
|
+
var _a, _b;
|
|
1269
|
+
const subjectFactory = typeof subject === "function" ? subject() : subject;
|
|
1270
|
+
const registry = ServiceRegistry.create([
|
|
1271
|
+
...defaultServiceFactories,
|
|
1272
|
+
...(_b = (_a = options == null ? void 0 : options.dependencies) == null ? void 0 : _a.map(
|
|
1273
|
+
(f) => typeof f === "function" ? f() : f
|
|
1274
|
+
)) != null ? _b : [],
|
|
1275
|
+
subjectFactory
|
|
1276
|
+
]);
|
|
1277
|
+
return new _ServiceFactoryTester(subjectFactory.service, registry);
|
|
1278
|
+
}
|
|
1279
|
+
/**
|
|
1280
|
+
* Returns the service instance for the subject.
|
|
1281
|
+
*
|
|
1282
|
+
* @remarks
|
|
1283
|
+
*
|
|
1284
|
+
* If the subject is a plugin scoped service factory a plugin ID
|
|
1285
|
+
* can be provided to instantiate the service for a specific plugin.
|
|
1286
|
+
*
|
|
1287
|
+
* By default the plugin ID 'test' is used.
|
|
1288
|
+
*/
|
|
1289
|
+
async get(...args) {
|
|
1290
|
+
const [pluginId] = args;
|
|
1291
|
+
return __privateGet(this, _registry).get(__privateGet(this, _subject), pluginId != null ? pluginId : "test");
|
|
1292
|
+
}
|
|
1293
|
+
/**
|
|
1294
|
+
* Return the service instance for any of the provided dependencies or built-in services.
|
|
1295
|
+
*
|
|
1296
|
+
* @remarks
|
|
1297
|
+
*
|
|
1298
|
+
* A plugin ID can optionally be provided for plugin scoped services, otherwise the plugin ID 'test' is used.
|
|
1299
|
+
*/
|
|
1300
|
+
async getService(service, ...args) {
|
|
1301
|
+
const [pluginId] = args;
|
|
1302
|
+
const instance = await __privateGet(this, _registry).get(service, pluginId != null ? pluginId : "test");
|
|
1303
|
+
if (instance === void 0) {
|
|
1304
|
+
throw new Error(`Service '${service.id}' not found`);
|
|
1305
|
+
}
|
|
1306
|
+
return instance;
|
|
1307
|
+
}
|
|
1308
|
+
};
|
|
1309
|
+
_subject = new WeakMap();
|
|
1310
|
+
_registry = new WeakMap();
|
|
1311
|
+
let ServiceFactoryTester = _ServiceFactoryTester;
|
|
1312
|
+
|
|
1313
|
+
exports.ServiceFactoryTester = ServiceFactoryTester;
|
|
732
1314
|
exports.TestDatabases = TestDatabases;
|
|
733
1315
|
exports.isDockerDisabledForTests = isDockerDisabledForTests;
|
|
734
1316
|
exports.setupRequestMockHandlers = setupRequestMockHandlers;
|