@noego/proper 0.2.1 → 0.3.0
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/bin/cli.js +90 -40
- package/bin/cli.js.map +1 -1
- package/bin/cli.mjs +103 -43
- package/bin/cli.mjs.map +1 -1
- package/bin/index.d.mts +5 -0
- package/bin/index.d.ts +5 -0
- package/bin/index.js +90 -40
- package/bin/index.js.map +1 -1
- package/bin/index.mjs +90 -40
- package/bin/index.mjs.map +1 -1
- package/package.json +1 -1
- package/readme.md +12 -0
package/bin/cli.mjs
CHANGED
|
@@ -121,7 +121,7 @@ var init_MigrationFilter = __esm({
|
|
|
121
121
|
});
|
|
122
122
|
|
|
123
123
|
// framework/errors.ts
|
|
124
|
-
var MigrationError, ConfigurationError, DatabaseConnectionError, MigrationExecutionError, PatchError, PatchValidationError, PatchIntegrityError, PatchConflictError, PatchExecutionError, CLIError;
|
|
124
|
+
var MigrationError, ConfigurationError, DatabaseConnectionError, MigrationStampError, MigrationExecutionError, PatchError, PatchValidationError, PatchIntegrityError, PatchConflictError, PatchExecutionError, CLIError;
|
|
125
125
|
var init_errors = __esm({
|
|
126
126
|
"framework/errors.ts"() {
|
|
127
127
|
MigrationError = class _MigrationError extends Error {
|
|
@@ -187,6 +187,16 @@ var init_errors = __esm({
|
|
|
187
187
|
return new _DatabaseConnectionError(`Authentication failed for ${dbType} database`);
|
|
188
188
|
}
|
|
189
189
|
};
|
|
190
|
+
MigrationStampError = class _MigrationStampError extends MigrationError {
|
|
191
|
+
constructor(migrationKey) {
|
|
192
|
+
super(
|
|
193
|
+
`Migration '${migrationKey}' cannot be migrated: its timestamp ends in "000", so it does not look like it was generated by 'proper create'. Recreate it with 'proper create <name>' and move the SQL into the generated files.`
|
|
194
|
+
);
|
|
195
|
+
this.migrationKey = migrationKey;
|
|
196
|
+
this.name = "MigrationStampError";
|
|
197
|
+
Object.setPrototypeOf(this, _MigrationStampError.prototype);
|
|
198
|
+
}
|
|
199
|
+
};
|
|
190
200
|
MigrationExecutionError = class _MigrationExecutionError extends MigrationError {
|
|
191
201
|
constructor(message, migrationName, sql, originalError) {
|
|
192
202
|
let fullMessage = `Migration Execution Error${migrationName ? ` in '${migrationName}'` : ""}: ${message}`;
|
|
@@ -317,6 +327,79 @@ ${originalError.message}` : message, patchFile, patchKey);
|
|
|
317
327
|
}
|
|
318
328
|
});
|
|
319
329
|
|
|
330
|
+
// framework/MigrationManifest.ts
|
|
331
|
+
import fs from "fs";
|
|
332
|
+
import path from "path";
|
|
333
|
+
function isMigrationFile(fileName) {
|
|
334
|
+
return MIGRATION_FILE_REGEX.test(fileName);
|
|
335
|
+
}
|
|
336
|
+
function canonicalMigrationKey(value) {
|
|
337
|
+
return value.replace(MIGRATION_FILE_REGEX, "").toLowerCase();
|
|
338
|
+
}
|
|
339
|
+
function mintMigrationStamp(now = Date.now()) {
|
|
340
|
+
return now % 10 === 0 ? now + 1 : now;
|
|
341
|
+
}
|
|
342
|
+
function isHandStampedKey(key) {
|
|
343
|
+
const stamp = key.split("_")[0];
|
|
344
|
+
return /^\d+$/.test(stamp) && /000$/.test(stamp);
|
|
345
|
+
}
|
|
346
|
+
function resolveMigrationFile(directory, baseName, direction, dialect) {
|
|
347
|
+
const dialectExt = dialect === "sql" ? "mysql" : dialect;
|
|
348
|
+
const dialectFile = path.join(directory, `${baseName}.${dialectExt}.${direction}.sql`);
|
|
349
|
+
if (fs.existsSync(dialectFile)) return dialectFile;
|
|
350
|
+
const genericFile = path.join(directory, `${baseName}.${direction}.sql`);
|
|
351
|
+
if (fs.existsSync(genericFile)) return genericFile;
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
354
|
+
function loadMigrationManifest(directory, dialect) {
|
|
355
|
+
const manifest = /* @__PURE__ */ new Map();
|
|
356
|
+
if (!fs.existsSync(directory)) return manifest;
|
|
357
|
+
const files = fs.readdirSync(directory, { withFileTypes: true }).filter((f) => f.isFile()).map((f) => f.name).filter(isMigrationFile);
|
|
358
|
+
const uniqueKeys = /* @__PURE__ */ new Set();
|
|
359
|
+
files.forEach((file) => uniqueKeys.add(canonicalMigrationKey(file)));
|
|
360
|
+
uniqueKeys.forEach((key) => {
|
|
361
|
+
manifest.set(key, {
|
|
362
|
+
key,
|
|
363
|
+
upFile: resolveMigrationFile(directory, key, "up", dialect),
|
|
364
|
+
downFile: resolveMigrationFile(directory, key, "down", dialect)
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
return manifest;
|
|
368
|
+
}
|
|
369
|
+
var MIGRATION_FILE_REGEX;
|
|
370
|
+
var init_MigrationManifest = __esm({
|
|
371
|
+
"framework/MigrationManifest.ts"() {
|
|
372
|
+
MIGRATION_FILE_REGEX = /(?:\.(mysql|sqlite|pg))?\.(up|down)\.(sql|js)$/i;
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
// framework/MigrationConfig.ts
|
|
377
|
+
function validateLegacyMigrationKeys(value) {
|
|
378
|
+
if (value === void 0) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
if (!Array.isArray(value) || value.some((key) => !isExactCanonicalMigrationKey(key))) {
|
|
382
|
+
throw new ConfigurationError(
|
|
383
|
+
"legacy_migration_keys must be an array of nonempty exact canonical migration keys; filenames, paths, wildcards, and nonstrings are not allowed"
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
function isExactCanonicalMigrationKey(value) {
|
|
388
|
+
if (typeof value !== "string" || value.length === 0 || value !== value.trim()) {
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
if (value.includes("/") || value.includes("\\") || ["*", "?", "[", "]", "{", "}"].some((token) => value.includes(token))) {
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
394
|
+
return !isMigrationFile(value) && canonicalMigrationKey(value) === value;
|
|
395
|
+
}
|
|
396
|
+
var init_MigrationConfig = __esm({
|
|
397
|
+
"framework/MigrationConfig.ts"() {
|
|
398
|
+
init_errors();
|
|
399
|
+
init_MigrationManifest();
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
|
|
320
403
|
// framework/MigrationNode.ts
|
|
321
404
|
var MigrationNode, SqlMigrationNode;
|
|
322
405
|
var init_MigrationNode = __esm({
|
|
@@ -460,45 +543,6 @@ var init_SqlMigrationBuilder = __esm({
|
|
|
460
543
|
}
|
|
461
544
|
});
|
|
462
545
|
|
|
463
|
-
// framework/MigrationManifest.ts
|
|
464
|
-
import fs from "fs";
|
|
465
|
-
import path from "path";
|
|
466
|
-
function isMigrationFile(fileName) {
|
|
467
|
-
return MIGRATION_FILE_REGEX.test(fileName);
|
|
468
|
-
}
|
|
469
|
-
function canonicalMigrationKey(value) {
|
|
470
|
-
return value.replace(MIGRATION_FILE_REGEX, "").toLowerCase();
|
|
471
|
-
}
|
|
472
|
-
function resolveMigrationFile(directory, baseName, direction, dialect) {
|
|
473
|
-
const dialectExt = dialect === "sql" ? "mysql" : dialect;
|
|
474
|
-
const dialectFile = path.join(directory, `${baseName}.${dialectExt}.${direction}.sql`);
|
|
475
|
-
if (fs.existsSync(dialectFile)) return dialectFile;
|
|
476
|
-
const genericFile = path.join(directory, `${baseName}.${direction}.sql`);
|
|
477
|
-
if (fs.existsSync(genericFile)) return genericFile;
|
|
478
|
-
return null;
|
|
479
|
-
}
|
|
480
|
-
function loadMigrationManifest(directory, dialect) {
|
|
481
|
-
const manifest = /* @__PURE__ */ new Map();
|
|
482
|
-
if (!fs.existsSync(directory)) return manifest;
|
|
483
|
-
const files = fs.readdirSync(directory, { withFileTypes: true }).filter((f) => f.isFile()).map((f) => f.name).filter(isMigrationFile);
|
|
484
|
-
const uniqueKeys = /* @__PURE__ */ new Set();
|
|
485
|
-
files.forEach((file) => uniqueKeys.add(canonicalMigrationKey(file)));
|
|
486
|
-
uniqueKeys.forEach((key) => {
|
|
487
|
-
manifest.set(key, {
|
|
488
|
-
key,
|
|
489
|
-
upFile: resolveMigrationFile(directory, key, "up", dialect),
|
|
490
|
-
downFile: resolveMigrationFile(directory, key, "down", dialect)
|
|
491
|
-
});
|
|
492
|
-
});
|
|
493
|
-
return manifest;
|
|
494
|
-
}
|
|
495
|
-
var MIGRATION_FILE_REGEX;
|
|
496
|
-
var init_MigrationManifest = __esm({
|
|
497
|
-
"framework/MigrationManifest.ts"() {
|
|
498
|
-
MIGRATION_FILE_REGEX = /(?:\.(mysql|sqlite|pg))?\.(up|down)\.(sql|js)$/i;
|
|
499
|
-
}
|
|
500
|
-
});
|
|
501
|
-
|
|
502
546
|
// framework/MigrationDirectoryReader.ts
|
|
503
547
|
import fs2 from "fs";
|
|
504
548
|
var MigrationDirectoryReader;
|
|
@@ -1375,6 +1419,7 @@ var MAX_NAME_LENGTH, SCAFFOLD, PatchCreator;
|
|
|
1375
1419
|
var init_PatchCreator = __esm({
|
|
1376
1420
|
"framework/PatchCreator.ts"() {
|
|
1377
1421
|
init_errors();
|
|
1422
|
+
init_MigrationManifest();
|
|
1378
1423
|
MAX_NAME_LENGTH = 120;
|
|
1379
1424
|
SCAFFOLD = `version: 1
|
|
1380
1425
|
description: TODO
|
|
@@ -1421,7 +1466,7 @@ operations: []
|
|
|
1421
1466
|
if (!fs5.existsSync(this.patchFolder)) {
|
|
1422
1467
|
fs5.mkdirSync(this.patchFolder, { recursive: true });
|
|
1423
1468
|
}
|
|
1424
|
-
let stamp =
|
|
1469
|
+
let stamp = mintMigrationStamp();
|
|
1425
1470
|
for (let attempt = 0; attempt < 1e3; attempt++) {
|
|
1426
1471
|
const filePath = path4.join(this.patchFolder, `${stamp}_${normalized}.yaml`);
|
|
1427
1472
|
try {
|
|
@@ -1429,7 +1474,7 @@ operations: []
|
|
|
1429
1474
|
return filePath;
|
|
1430
1475
|
} catch (error) {
|
|
1431
1476
|
if (error && error.code === "EEXIST") {
|
|
1432
|
-
stamp
|
|
1477
|
+
stamp = mintMigrationStamp(stamp + 1);
|
|
1433
1478
|
continue;
|
|
1434
1479
|
}
|
|
1435
1480
|
throw error;
|
|
@@ -1780,6 +1825,7 @@ function makeRunner(database, conn) {
|
|
|
1780
1825
|
var MigrationRunnerFactory, MySQLMigrationRunner, FileMigrationConfigReader, MigrationCreator;
|
|
1781
1826
|
var init_MigrationRunner = __esm({
|
|
1782
1827
|
"framework/MigrationRunner.ts"() {
|
|
1828
|
+
init_MigrationConfig();
|
|
1783
1829
|
init_MigrationDirectoryReader();
|
|
1784
1830
|
init_MigrationSetup();
|
|
1785
1831
|
init_MigrationFilter();
|
|
@@ -1787,6 +1833,8 @@ var init_MigrationRunner = __esm({
|
|
|
1787
1833
|
init_PatchRunner();
|
|
1788
1834
|
init_PatchCreator();
|
|
1789
1835
|
init_PatchTypes();
|
|
1836
|
+
init_MigrationManifest();
|
|
1837
|
+
init_errors();
|
|
1790
1838
|
init_SQLRunner();
|
|
1791
1839
|
init_errors();
|
|
1792
1840
|
MigrationRunnerFactory = class _MigrationRunnerFactory {
|
|
@@ -1934,6 +1982,7 @@ var init_MigrationRunner = __esm({
|
|
|
1934
1982
|
*/
|
|
1935
1983
|
this.preflightPromise = null;
|
|
1936
1984
|
this.lastPatchResults = [];
|
|
1985
|
+
validateLegacyMigrationKeys(config.legacy_migration_keys);
|
|
1937
1986
|
}
|
|
1938
1987
|
setup() {
|
|
1939
1988
|
return __async(this, null, function* () {
|
|
@@ -2039,7 +2088,17 @@ var init_MigrationRunner = __esm({
|
|
|
2039
2088
|
}
|
|
2040
2089
|
migrate(migrationNodes, forward) {
|
|
2041
2090
|
return __async(this, null, function* () {
|
|
2091
|
+
var _a;
|
|
2042
2092
|
yield this.setup();
|
|
2093
|
+
if (forward) {
|
|
2094
|
+
const legacyMigrationKeys = new Set((_a = this.config.legacy_migration_keys) != null ? _a : []);
|
|
2095
|
+
for (const node of migrationNodes) {
|
|
2096
|
+
const key = node.get_key();
|
|
2097
|
+
if (isHandStampedKey(key) && !legacyMigrationKeys.has(key) && !(yield node.status()).completed) {
|
|
2098
|
+
throw new MigrationStampError(key);
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2043
2102
|
for (let node of migrationNodes) {
|
|
2044
2103
|
try {
|
|
2045
2104
|
if (forward) {
|
|
@@ -2135,6 +2194,7 @@ var init_MigrationRunner = __esm({
|
|
|
2135
2194
|
try {
|
|
2136
2195
|
const fileContent = fs6.readFileSync(this.configFile);
|
|
2137
2196
|
const config = JSON.parse(fileContent.toString());
|
|
2197
|
+
validateLegacyMigrationKeys(config.legacy_migration_keys);
|
|
2138
2198
|
if (!config.migration_folder) {
|
|
2139
2199
|
throw ConfigurationError.missingRequiredProperty("migration_folder");
|
|
2140
2200
|
}
|
|
@@ -2177,7 +2237,7 @@ var init_MigrationRunner = __esm({
|
|
|
2177
2237
|
if (!fs6.existsSync(this.config.migration_folder)) {
|
|
2178
2238
|
fs6.mkdirSync(this.config.migration_folder, { recursive: true });
|
|
2179
2239
|
}
|
|
2180
|
-
const now_timestamp =
|
|
2240
|
+
const now_timestamp = mintMigrationStamp();
|
|
2181
2241
|
const filename_up = `${now_timestamp}_${name}.up.sql`;
|
|
2182
2242
|
const filename_down = `${now_timestamp}_${name}.down.sql`;
|
|
2183
2243
|
fs6.writeFileSync(`${this.config.migration_folder}/${filename_up}`, `
|