@tldraw/store
Version:
tldraw infinite canvas SDK (store).
200 lines (199 loc) • 7.25 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var migrate_exports = {};
__export(migrate_exports, {
MigrationFailureReason: () => MigrationFailureReason,
createMigrationIds: () => createMigrationIds,
createMigrationSequence: () => createMigrationSequence,
createRecordMigrationSequence: () => createRecordMigrationSequence,
parseMigrationId: () => parseMigrationId,
sortMigrations: () => sortMigrations,
validateMigrations: () => validateMigrations
});
module.exports = __toCommonJS(migrate_exports);
var import_utils = require("@tldraw/utils");
function squashDependsOn(sequence) {
const result = [];
for (let i = sequence.length - 1; i >= 0; i--) {
const elem = sequence[i];
if (!("id" in elem)) {
const dependsOn = elem.dependsOn;
const prev = result[0];
if (prev) {
result[0] = {
...prev,
dependsOn: dependsOn.concat(prev.dependsOn ?? [])
};
}
} else {
result.unshift(elem);
}
}
return result;
}
function createMigrationSequence({
sequence,
sequenceId,
retroactive = true
}) {
const migrations = {
sequenceId,
retroactive,
sequence: squashDependsOn(sequence)
};
validateMigrations(migrations);
return migrations;
}
function createMigrationIds(sequenceId, versions) {
return Object.fromEntries(
(0, import_utils.objectMapEntries)(versions).map(([key, version]) => [key, `${sequenceId}/${version}`])
);
}
function createRecordMigrationSequence(opts) {
const sequenceId = opts.sequenceId;
return createMigrationSequence({
sequenceId,
retroactive: opts.retroactive ?? true,
sequence: opts.sequence.map(
(m) => "id" in m ? {
...m,
scope: "record",
filter: (r) => r.typeName === opts.recordType && (m.filter?.(r) ?? true) && (opts.filter?.(r) ?? true)
} : m
)
});
}
function sortMigrations(migrations) {
if (migrations.length === 0) return [];
const byId = new Map(migrations.map((m) => [m.id, m]));
const dependents = /* @__PURE__ */ new Map();
const inDegree = /* @__PURE__ */ new Map();
const explicitDeps = /* @__PURE__ */ new Map();
for (const m of migrations) {
inDegree.set(m.id, 0);
dependents.set(m.id, /* @__PURE__ */ new Set());
explicitDeps.set(m.id, /* @__PURE__ */ new Set());
}
for (const m of migrations) {
const { version, sequenceId } = parseMigrationId(m.id);
const prevId = `${sequenceId}/${version - 1}`;
if (byId.has(prevId)) {
dependents.get(prevId).add(m.id);
inDegree.set(m.id, inDegree.get(m.id) + 1);
}
if (m.dependsOn) {
for (const depId of m.dependsOn) {
if (byId.has(depId)) {
dependents.get(depId).add(m.id);
explicitDeps.get(m.id).add(depId);
inDegree.set(m.id, inDegree.get(m.id) + 1);
}
}
}
}
const ready = migrations.filter((m) => inDegree.get(m.id) === 0);
const result = [];
const processed = /* @__PURE__ */ new Set();
while (ready.length > 0) {
let bestCandidate;
let bestCandidateScore = -Infinity;
for (const m of ready) {
let urgencyScore = 0;
for (const depId of dependents.get(m.id) || []) {
if (!processed.has(depId)) {
urgencyScore += 1;
if (explicitDeps.get(depId).has(m.id)) {
urgencyScore += 100;
}
}
}
if (urgencyScore > bestCandidateScore || // Tiebreaker: prefer lower sequence/version
urgencyScore === bestCandidateScore && m.id.localeCompare(bestCandidate?.id ?? "") < 0) {
bestCandidate = m;
bestCandidateScore = urgencyScore;
}
}
const nextMigration = bestCandidate;
ready.splice(ready.indexOf(nextMigration), 1);
result.push(nextMigration);
processed.add(nextMigration.id);
for (const depId of dependents.get(nextMigration.id) || []) {
if (!processed.has(depId)) {
inDegree.set(depId, inDegree.get(depId) - 1);
if (inDegree.get(depId) === 0) {
ready.push(byId.get(depId));
}
}
}
}
if (result.length !== migrations.length) {
const unprocessed = migrations.filter((m) => !processed.has(m.id));
(0, import_utils.assert)(false, `Circular dependency in migrations: ${unprocessed[0].id}`);
}
return result;
}
function parseMigrationId(id) {
const [sequenceId, version] = id.split("/");
return { sequenceId, version: parseInt(version) };
}
function validateMigrationId(id, expectedSequenceId) {
if (expectedSequenceId) {
(0, import_utils.assert)(
id.startsWith(expectedSequenceId + "/"),
`Every migration in sequence '${expectedSequenceId}' must have an id starting with '${expectedSequenceId}/'. Got invalid id: '${id}'`
);
}
(0, import_utils.assert)(id.match(/^(.*?)\/(0|[1-9]\d*)$/), `Invalid migration id: '${id}'`);
}
function validateMigrations(migrations) {
(0, import_utils.assert)(
!migrations.sequenceId.includes("/"),
`sequenceId cannot contain a '/', got ${migrations.sequenceId}`
);
(0, import_utils.assert)(migrations.sequenceId.length, "sequenceId must be a non-empty string");
if (migrations.sequence.length === 0) {
return;
}
validateMigrationId(migrations.sequence[0].id, migrations.sequenceId);
let n = parseMigrationId(migrations.sequence[0].id).version;
(0, import_utils.assert)(
n === 1,
`Expected the first migrationId to be '${migrations.sequenceId}/1' but got '${migrations.sequence[0].id}'`
);
for (let i = 1; i < migrations.sequence.length; i++) {
const id = migrations.sequence[i].id;
validateMigrationId(id, migrations.sequenceId);
const m = parseMigrationId(id).version;
(0, import_utils.assert)(
m === n + 1,
`Migration id numbers must increase in increments of 1, expected ${migrations.sequenceId}/${n + 1} but got '${migrations.sequence[i].id}'`
);
n = m;
}
}
var MigrationFailureReason = /* @__PURE__ */ ((MigrationFailureReason2) => {
MigrationFailureReason2["IncompatibleSubtype"] = "incompatible-subtype";
MigrationFailureReason2["UnknownType"] = "unknown-type";
MigrationFailureReason2["TargetVersionTooNew"] = "target-version-too-new";
MigrationFailureReason2["TargetVersionTooOld"] = "target-version-too-old";
MigrationFailureReason2["MigrationError"] = "migration-error";
MigrationFailureReason2["UnrecognizedSubtype"] = "unrecognized-subtype";
return MigrationFailureReason2;
})(MigrationFailureReason || {});
//# sourceMappingURL=migrate.js.map