@fluidframework/container-runtime 1.0.0 → 1.1.0-76254
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/dist/connectionTelemetry.d.ts +19 -0
- package/dist/connectionTelemetry.d.ts.map +1 -1
- package/dist/connectionTelemetry.js +21 -21
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerRuntime.d.ts +13 -1
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +99 -11
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.d.ts.map +1 -1
- package/dist/dataStore.js +14 -3
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreRegistry.d.ts +0 -4
- package/dist/dataStoreRegistry.d.ts.map +1 -1
- package/dist/dataStoreRegistry.js +12 -1
- package/dist/dataStoreRegistry.js.map +1 -1
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +4 -4
- package/dist/dataStores.js.map +1 -1
- package/dist/garbageCollection.d.ts +20 -24
- package/dist/garbageCollection.d.ts.map +1 -1
- package/dist/garbageCollection.js +40 -117
- package/dist/garbageCollection.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/lib/connectionTelemetry.d.ts +19 -0
- package/lib/connectionTelemetry.d.ts.map +1 -1
- package/lib/connectionTelemetry.js +21 -21
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerRuntime.d.ts +13 -1
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +101 -13
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.d.ts.map +1 -1
- package/lib/dataStore.js +15 -4
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreRegistry.d.ts +0 -4
- package/lib/dataStoreRegistry.d.ts.map +1 -1
- package/lib/dataStoreRegistry.js +12 -1
- package/lib/dataStoreRegistry.js.map +1 -1
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +5 -5
- package/lib/dataStores.js.map +1 -1
- package/lib/garbageCollection.d.ts +20 -24
- package/lib/garbageCollection.d.ts.map +1 -1
- package/lib/garbageCollection.js +39 -115
- package/lib/garbageCollection.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/package.json +20 -48
- package/src/connectionTelemetry.ts +58 -37
- package/src/containerRuntime.ts +119 -26
- package/src/dataStore.ts +21 -4
- package/src/dataStoreRegistry.ts +8 -1
- package/src/dataStores.ts +6 -5
- package/src/garbageCollection.ts +66 -158
- package/src/packageVersion.ts +1 -1
package/lib/garbageCollection.js
CHANGED
|
@@ -11,7 +11,6 @@ import { mergeStats, SummaryTreeBuilder, } from "@fluidframework/runtime-utils";
|
|
|
11
11
|
import { ChildLogger, loggerToMonitoringContext, PerformanceEvent, TelemetryDataTag, } from "@fluidframework/telemetry-utils";
|
|
12
12
|
import { RuntimeHeaders } from "./containerRuntime";
|
|
13
13
|
import { getSummaryForDatastores } from "./dataStores";
|
|
14
|
-
import { pkgVersion } from "./packageVersion";
|
|
15
14
|
import { getGCVersion, metadataBlobName, dataStoreAttributesBlobName, } from "./summaryFormat";
|
|
16
15
|
/** This is the current version of garbage collection. */
|
|
17
16
|
const GCVersion = 1;
|
|
@@ -31,12 +30,8 @@ const writeAtRootKey = "Fluid.GarbageCollection.WriteDataAtRoot";
|
|
|
31
30
|
export const runSessionExpiryKey = "Fluid.GarbageCollection.RunSessionExpiry";
|
|
32
31
|
// Feature gate key to disable expiring session after a set period of time, even if expiry value is present
|
|
33
32
|
export const disableSessionExpiryKey = "Fluid.GarbageCollection.DisableSessionExpiry";
|
|
34
|
-
// Feature gate key to log error messages if GC reference validation fails.
|
|
35
|
-
export const logUnknownOutboundReferencesKey = "Fluid.GarbageCollection.LogUnknownOutboundReferences";
|
|
36
33
|
// Feature gate key to write the gc blob as a handle if the data is the same.
|
|
37
34
|
export const trackGCStateKey = "Fluid.GarbageCollection.TrackGCState";
|
|
38
|
-
// Feature gate key to limit which versions can write the gc blob as a handle if the data is the same.
|
|
39
|
-
export const trackGCStateMinimumVersionKey = "Fluid.GarbageCollection.TrackGCState.MinVersion";
|
|
40
35
|
const defaultInactiveTimeoutMs = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
41
36
|
export const defaultSessionExpiryDurationMs = 30 * 24 * 60 * 60 * 1000; // 30 days
|
|
42
37
|
/** The types of GC nodes in the GC reference graph. */
|
|
@@ -114,21 +109,12 @@ class UnreferencedStateTracker {
|
|
|
114
109
|
* NodeId = "dds1" NodeId = "dds2"
|
|
115
110
|
*/
|
|
116
111
|
export class GarbageCollector {
|
|
117
|
-
constructor(
|
|
118
|
-
/** For a given node path, returns the node's package path. */
|
|
119
|
-
getNodePackagePath,
|
|
120
|
-
/** Returns the timestamp of the last summary generated for this container. */
|
|
121
|
-
getLastSummaryTimestampMs, baseSnapshot, readAndParseBlob, baseLogger, existing, metadata, isSummarizerClient = true) {
|
|
112
|
+
constructor(createParams) {
|
|
122
113
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
123
|
-
this.runtime = runtime;
|
|
124
|
-
this.gcOptions = gcOptions;
|
|
125
|
-
this.getNodePackagePath = getNodePackagePath;
|
|
126
|
-
this.getLastSummaryTimestampMs = getLastSummaryTimestampMs;
|
|
127
|
-
this.isSummarizerClient = isSummarizerClient;
|
|
128
114
|
/**
|
|
129
115
|
* Tells whether the GC data should be written to the root of the summary tree.
|
|
130
116
|
*/
|
|
131
|
-
this._writeDataAtRoot =
|
|
117
|
+
this._writeDataAtRoot = true;
|
|
132
118
|
/**
|
|
133
119
|
* Tells whether the initial GC state needs to be reset. This can happen under 2 conditions:
|
|
134
120
|
* 1. The base snapshot contains GC state but GC is disabled. This will happen the first time GC is disabled after
|
|
@@ -154,7 +140,15 @@ export class GarbageCollector {
|
|
|
154
140
|
this.pendingEventsQueue = [];
|
|
155
141
|
// The number of times GC has successfully completed on this instance of GarbageCollector.
|
|
156
142
|
this.completedRuns = 0;
|
|
157
|
-
this.
|
|
143
|
+
this.runtime = createParams.runtime;
|
|
144
|
+
this.isSummarizerClient = createParams.isSummarizerClient;
|
|
145
|
+
this.gcOptions = createParams.gcOptions;
|
|
146
|
+
this.getNodePackagePath = createParams.getNodePackagePath;
|
|
147
|
+
this.getLastSummaryTimestampMs = createParams.getLastSummaryTimestampMs;
|
|
148
|
+
const baseSnapshot = createParams.baseSnapshot;
|
|
149
|
+
const metadata = createParams.metadata;
|
|
150
|
+
const readAndParseBlob = createParams.readAndParseBlob;
|
|
151
|
+
this.mc = loggerToMonitoringContext(ChildLogger.create(createParams.baseLogger, "GarbageCollector", { all: { completedGCRuns: () => this.completedRuns } }));
|
|
158
152
|
let prevSummaryGCVersion;
|
|
159
153
|
/**
|
|
160
154
|
* The following GC state is enabled during container creation and cannot be changed throughout its lifetime:
|
|
@@ -163,7 +157,7 @@ export class GarbageCollector {
|
|
|
163
157
|
* 3. Whether GC session expiry is enabled or not.
|
|
164
158
|
* For existing containers, we get this information from the metadata blob of its summary.
|
|
165
159
|
*/
|
|
166
|
-
if (existing) {
|
|
160
|
+
if (createParams.existing) {
|
|
167
161
|
prevSummaryGCVersion = getGCVersion(metadata);
|
|
168
162
|
// Existing documents which did not have metadata blob or had GC disabled have version as 0. For all
|
|
169
163
|
// other existing documents, GC is enabled.
|
|
@@ -174,14 +168,14 @@ export class GarbageCollector {
|
|
|
174
168
|
else {
|
|
175
169
|
// Sweep should not be enabled without enabling GC mark phase. We could silently disable sweep in this
|
|
176
170
|
// scenario but explicitly failing makes it clearer and promotes correct usage.
|
|
177
|
-
if (gcOptions.sweepAllowed && gcOptions.gcAllowed === false) {
|
|
171
|
+
if (this.gcOptions.sweepAllowed && this.gcOptions.gcAllowed === false) {
|
|
178
172
|
throw new UsageError("GC sweep phase cannot be enabled without enabling GC mark phase");
|
|
179
173
|
}
|
|
180
174
|
// For new documents, GC is enabled by default. It can be explicitly disabled by setting the gcAllowed
|
|
181
175
|
// flag in GC options to false.
|
|
182
|
-
this.gcEnabled = gcOptions.gcAllowed !== false;
|
|
176
|
+
this.gcEnabled = this.gcOptions.gcAllowed !== false;
|
|
183
177
|
// The sweep phase has to be explicitly enabled by setting the sweepAllowed flag in GC options to true.
|
|
184
|
-
this.sweepEnabled = gcOptions.sweepAllowed === true;
|
|
178
|
+
this.sweepEnabled = this.gcOptions.sweepAllowed === true;
|
|
185
179
|
// Set the Session Expiry only if the flag is enabled or the test option is set.
|
|
186
180
|
if (this.mc.config.getBoolean(runSessionExpiryKey) && this.gcEnabled) {
|
|
187
181
|
this.sessionExpiryTimeoutMs = defaultSessionExpiryDurationMs;
|
|
@@ -215,10 +209,8 @@ export class GarbageCollector {
|
|
|
215
209
|
// GC must be enabled for the document.
|
|
216
210
|
this.gcEnabled
|
|
217
211
|
// GC must not be disabled via GC options.
|
|
218
|
-
&& !gcOptions.disableGC);
|
|
219
|
-
|
|
220
|
-
const shouldTrackStateForVersion = meetsMinimumVersionRequirement(pkgVersion, minimumVersion);
|
|
221
|
-
this.trackGCState = this.mc.config.getBoolean(trackGCStateKey) === true && shouldTrackStateForVersion;
|
|
212
|
+
&& !this.gcOptions.disableGC);
|
|
213
|
+
this.trackGCState = this.mc.config.getBoolean(trackGCStateKey) === true;
|
|
222
214
|
/**
|
|
223
215
|
* Whether sweep should run or not. The following conditions have to be met to run sweep:
|
|
224
216
|
* 1. Overall GC or mark phase must be enabled (this.shouldRunGC).
|
|
@@ -230,19 +222,15 @@ export class GarbageCollector {
|
|
|
230
222
|
this.inactiveTimeoutMs =
|
|
231
223
|
(_e = (_d = this.mc.config.getNumber("Fluid.GarbageCollection.TestOverride.InactiveTimeoutMs")) !== null && _d !== void 0 ? _d : this.gcOptions.inactiveTimeoutMs) !== null && _e !== void 0 ? _e : defaultInactiveTimeoutMs;
|
|
232
224
|
// Whether we are running in test mode. In this mode, unreferenced nodes are immediately deleted.
|
|
233
|
-
this.testMode = (_f = this.mc.config.getBoolean(gcTestModeKey)) !== null && _f !== void 0 ? _f : gcOptions.runGCInTestMode === true;
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
// this.initialStateNeedsReset = gcTreePresent ? !this.shouldRunGC : this.shouldRunGC;
|
|
243
|
-
// If `writeDataAtRoot` setting is true, write the GC data into the root of the summary tree. We do this so that
|
|
244
|
-
// the roll out can be staged. Once its rolled out everywhere, we will start writing at root by default.
|
|
245
|
-
this._writeDataAtRoot = (_g = this.mc.config.getBoolean(writeAtRootKey)) !== null && _g !== void 0 ? _g : this.gcOptions.writeDataAtRoot === true;
|
|
225
|
+
this.testMode = (_f = this.mc.config.getBoolean(gcTestModeKey)) !== null && _f !== void 0 ? _f : this.gcOptions.runGCInTestMode === true;
|
|
226
|
+
// GC state is written into root of the summary tree by default. Can be overridden via feature flag for now.
|
|
227
|
+
this._writeDataAtRoot = (_g = this.mc.config.getBoolean(writeAtRootKey)) !== null && _g !== void 0 ? _g : true;
|
|
228
|
+
if (this._writeDataAtRoot) {
|
|
229
|
+
// The GC state needs to be reset if the base snapshot contains GC tree and GC is disabled or it doesn't
|
|
230
|
+
// contain GC tree and GC is enabled.
|
|
231
|
+
const gcTreePresent = (baseSnapshot === null || baseSnapshot === void 0 ? void 0 : baseSnapshot.trees[gcTreeKey]) !== undefined;
|
|
232
|
+
this.initialStateNeedsReset = gcTreePresent !== this.shouldRunGC;
|
|
233
|
+
}
|
|
246
234
|
// Get the GC state from the GC blob in the base snapshot. Use LazyPromise because we only want to do
|
|
247
235
|
// this once since it involves fetching blobs from storage which is expensive.
|
|
248
236
|
const baseSummaryStateP = new LazyPromise(async () => {
|
|
@@ -331,7 +319,7 @@ export class GarbageCollector {
|
|
|
331
319
|
// Run GC on the nodes in the base summary to get the routes used in each node in the container.
|
|
332
320
|
// This is an optimization for space (vs performance) wherein we don't need to store the used routes of
|
|
333
321
|
// each node in the summary.
|
|
334
|
-
const usedRoutes = runGarbageCollection(gcNodes, ["/"]
|
|
322
|
+
const usedRoutes = runGarbageCollection(gcNodes, ["/"]).referencedNodeIds;
|
|
335
323
|
const baseGCDetailsMap = unpackChildNodesGCDetails({ gcData: { gcNodes }, usedRoutes });
|
|
336
324
|
// Currently, the nodes may write the GC data. So, we need to update it's base GC details with the
|
|
337
325
|
// unreferenced timestamp. Once we start writing the GC data here, we won't need to do this anymore.
|
|
@@ -347,7 +335,7 @@ export class GarbageCollector {
|
|
|
347
335
|
});
|
|
348
336
|
// Log all the GC options and the state determined by the garbage collector. This is interesting only for the
|
|
349
337
|
// summarizer client since it is the only one that runs GC. It also helps keep the telemetry less noisy.
|
|
350
|
-
const gcConfigProps = JSON.stringify(Object.assign({ gcEnabled: this.gcEnabled, sweepEnabled: this.sweepEnabled, runGC: this.shouldRunGC, runSweep: this.shouldRunSweep, writeAtRoot: this._writeDataAtRoot, testMode: this.testMode, sessionExpiry: this.sessionExpiryTimeoutMs, inactiveTimeout: this.inactiveTimeoutMs, existing }, this.gcOptions));
|
|
338
|
+
const gcConfigProps = JSON.stringify(Object.assign({ gcEnabled: this.gcEnabled, sweepEnabled: this.sweepEnabled, runGC: this.shouldRunGC, runSweep: this.shouldRunSweep, writeAtRoot: this._writeDataAtRoot, testMode: this.testMode, sessionExpiry: this.sessionExpiryTimeoutMs, inactiveTimeout: this.inactiveTimeoutMs, existing: createParams.existing }, this.gcOptions));
|
|
351
339
|
if (this.isSummarizerClient) {
|
|
352
340
|
this.mc.logger.sendTelemetryEvent({
|
|
353
341
|
eventName: "GarbageCollectorLoaded",
|
|
@@ -363,8 +351,8 @@ export class GarbageCollector {
|
|
|
363
351
|
});
|
|
364
352
|
}
|
|
365
353
|
}
|
|
366
|
-
static create(
|
|
367
|
-
return new GarbageCollector(
|
|
354
|
+
static create(createParams) {
|
|
355
|
+
return new GarbageCollector(createParams);
|
|
368
356
|
}
|
|
369
357
|
/**
|
|
370
358
|
* Tells whether the GC state needs to be reset in the next summary. We need to do this if:
|
|
@@ -396,7 +384,7 @@ export class GarbageCollector {
|
|
|
396
384
|
await this.runtime.updateStateBeforeGC();
|
|
397
385
|
// Get the runtime's GC data and run GC on the reference graph in it.
|
|
398
386
|
const gcData = await this.runtime.getGCData(fullGC);
|
|
399
|
-
const gcResult = runGarbageCollection(gcData.gcNodes, ["/"]
|
|
387
|
+
const gcResult = runGarbageCollection(gcData.gcNodes, ["/"]);
|
|
400
388
|
const gcStats = this.generateStatsAndLogEvents(gcResult, logger);
|
|
401
389
|
// Update the state since the last GC run. There can be nodes that were referenced between the last and
|
|
402
390
|
// the current run. We need to identify than and update their unreferenced state if needed.
|
|
@@ -485,9 +473,6 @@ export class GarbageCollector {
|
|
|
485
473
|
* latest summary tracked.
|
|
486
474
|
*/
|
|
487
475
|
async latestSummaryStateRefreshed(result, readAndParseBlob) {
|
|
488
|
-
// After a summary is successfully submitted and ack'd by this client, the GC state should have been reset in
|
|
489
|
-
// the summary and doesn't need to be reset anymore.
|
|
490
|
-
this.initialStateNeedsReset = false;
|
|
491
476
|
if (!this.shouldRunGC || !result.latestSummaryUpdated) {
|
|
492
477
|
return;
|
|
493
478
|
}
|
|
@@ -495,6 +480,7 @@ export class GarbageCollector {
|
|
|
495
480
|
// Basically, it was written in the current GC version.
|
|
496
481
|
if (result.wasSummaryTracked) {
|
|
497
482
|
this.latestSummaryGCVersion = this.currentGCVersion;
|
|
483
|
+
this.initialStateNeedsReset = false;
|
|
498
484
|
if (this.trackGCState) {
|
|
499
485
|
this.latestSerializedSummaryState = this.pendingSerializedSummaryState;
|
|
500
486
|
this.pendingSerializedSummaryState = undefined;
|
|
@@ -617,10 +603,7 @@ export class GarbageCollector {
|
|
|
617
603
|
}
|
|
618
604
|
// Find any references that haven't been identified correctly.
|
|
619
605
|
const missingExplicitReferences = this.findMissingExplicitReferences(currentGCData, this.previousGCDataFromLastRun, this.newReferencesSinceLastRun);
|
|
620
|
-
|
|
621
|
-
// https://github.com/microsoft/FluidFramework/issues/8878.
|
|
622
|
-
if (this.mc.config.getBoolean(logUnknownOutboundReferencesKey) === true
|
|
623
|
-
&& missingExplicitReferences.length > 0) {
|
|
606
|
+
if (this.writeDataAtRoot && missingExplicitReferences.length > 0) {
|
|
624
607
|
missingExplicitReferences.forEach((missingExplicitReference) => {
|
|
625
608
|
const event = {
|
|
626
609
|
eventName: "gcUnknownOutboundReferences",
|
|
@@ -664,7 +647,7 @@ export class GarbageCollector {
|
|
|
664
647
|
* unreferenced, stop tracking them and remove from unreferenced list.
|
|
665
648
|
* Some of these nodes may be unreferenced now and if so, the current run will add unreferenced state for them.
|
|
666
649
|
*/
|
|
667
|
-
const gcResult = runGarbageCollection(gcDataSuperSet.gcNodes, ["/"]
|
|
650
|
+
const gcResult = runGarbageCollection(gcDataSuperSet.gcNodes, ["/"]);
|
|
668
651
|
for (const nodeId of gcResult.referencedNodeIds) {
|
|
669
652
|
const nodeStateTracker = this.unreferencedNodesState.get(nodeId);
|
|
670
653
|
if (nodeStateTracker !== undefined) {
|
|
@@ -744,11 +727,10 @@ export class GarbageCollector {
|
|
|
744
727
|
};
|
|
745
728
|
const updateNodeStats = (nodeId, referenced) => {
|
|
746
729
|
gcStats.nodeCount++;
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
const stateUpdated = this.unreferencedNodesState.has(nodeId) ? referenced : !referenced;
|
|
730
|
+
// If there is no previous GC data, every node's state is generated and is considered as updated.
|
|
731
|
+
// Otherwise, find out if any node went from referenced to unreferenced or vice-versa.
|
|
732
|
+
const stateUpdated = this.previousGCDataFromLastRun === undefined ||
|
|
733
|
+
this.unreferencedNodesState.has(nodeId) === referenced;
|
|
752
734
|
if (stateUpdated) {
|
|
753
735
|
gcStats.updatedNodeCount++;
|
|
754
736
|
}
|
|
@@ -824,7 +806,7 @@ export class GarbageCollector {
|
|
|
824
806
|
// next time GC runs as the package data should be available then.
|
|
825
807
|
const pkg = packagePath !== null && packagePath !== void 0 ? packagePath : this.getNodePackagePath(nodeId);
|
|
826
808
|
if (pkg !== undefined) {
|
|
827
|
-
this.mc.logger.sendErrorEvent(Object.assign(Object.assign({}, event), { pkg: { value:
|
|
809
|
+
this.mc.logger.sendErrorEvent(Object.assign(Object.assign({}, event), { pkg: { value: pkg.join("/"), tag: TelemetryDataTag.PackageData } }));
|
|
828
810
|
}
|
|
829
811
|
else {
|
|
830
812
|
this.pendingEventsQueue.push(event);
|
|
@@ -883,62 +865,4 @@ function setLongTimeout(timeoutMs, timeoutFn, setTimerFn) {
|
|
|
883
865
|
}
|
|
884
866
|
setTimerFn(timer);
|
|
885
867
|
}
|
|
886
|
-
/**
|
|
887
|
-
* meetsMinimumVersionRequirement is used determining if a feature version should be run. This is similar to feature
|
|
888
|
-
* flags. The advantage of this is that if we ship a bug in version 0.1.1 and fix it in version 0.2.1. We can keep this
|
|
889
|
-
* feature disabled for version 0.1.1 and enabled for 0.2.1. Older versions will run without the feature and new
|
|
890
|
-
* versions will run with the feature.
|
|
891
|
-
* @param currentVersion - the total time the timeout needs to last in ms
|
|
892
|
-
* @param minimumVersion - the function to execute when the timer ends
|
|
893
|
-
*/
|
|
894
|
-
function meetsMinimumVersionRequirement(currentVersion, minimumVersion) {
|
|
895
|
-
return minimumVersion === undefined || semverCompare(currentVersion, minimumVersion) >= 0;
|
|
896
|
-
}
|
|
897
|
-
/**
|
|
898
|
-
* Compare semver versions.
|
|
899
|
-
* @param currentVersion - assumed to be any valid semver version
|
|
900
|
-
* @param minimumVersion - must be [major].[minor].[patch], where major, minor, and patch are all numbers
|
|
901
|
-
* as it complicates the algorithm if we allow comparisons against minimum pre-release versions.
|
|
902
|
-
* @returns
|
|
903
|
-
* 0 if the currentVersion equals the minimumVersion
|
|
904
|
-
* 1 if the currentVersion is greater than the minimumVersion
|
|
905
|
-
* -1 if the minimumVersion is greater than the currentVersion
|
|
906
|
-
*/
|
|
907
|
-
export function semverCompare(currentVersion, minimumVersion) {
|
|
908
|
-
const minimumValues = minimumVersion.split(".").map((value) => {
|
|
909
|
-
assert(isNaN(+value) === false, "Expected real numbers in minimum version!");
|
|
910
|
-
return Number.parseInt(value, 10);
|
|
911
|
-
});
|
|
912
|
-
assert(minimumValues.length === 3, "Expected minimumVersion to be [major].[minor].[patch]");
|
|
913
|
-
const [minMajor, minMinor, minPatch] = minimumValues;
|
|
914
|
-
const currentValuesString = currentVersion.split(/\W/);
|
|
915
|
-
assert(currentValuesString.length >= 3, "Expected version to match semver rules!");
|
|
916
|
-
const currentValues = currentValuesString.slice(0, 3).map((value) => {
|
|
917
|
-
assert(isNaN(+value) === false, "Expected real numbers in minimum version!");
|
|
918
|
-
return Number.parseInt(value, 10);
|
|
919
|
-
});
|
|
920
|
-
const [cMajor, cMinor, cPatch] = currentValues;
|
|
921
|
-
if (cMajor > minMajor) {
|
|
922
|
-
return 1;
|
|
923
|
-
}
|
|
924
|
-
else if (minMajor > cMajor) {
|
|
925
|
-
return -1;
|
|
926
|
-
}
|
|
927
|
-
if (cMinor > minMinor) {
|
|
928
|
-
return 1;
|
|
929
|
-
}
|
|
930
|
-
else if (minMinor > cMinor) {
|
|
931
|
-
return -1;
|
|
932
|
-
}
|
|
933
|
-
if (cPatch > minPatch) {
|
|
934
|
-
return 1;
|
|
935
|
-
}
|
|
936
|
-
else if (minPatch > cPatch) {
|
|
937
|
-
return -1;
|
|
938
|
-
}
|
|
939
|
-
if (currentValuesString.length === 3) {
|
|
940
|
-
return 0;
|
|
941
|
-
}
|
|
942
|
-
return -1;
|
|
943
|
-
}
|
|
944
868
|
//# sourceMappingURL=garbageCollection.js.map
|