@warlock.js/cascade 5.6.0 → 5.7.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.
Files changed (46) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/cjs/index.cjs +74 -36
  3. package/cjs/index.cjs.map +1 -1
  4. package/esm/database-dirty-tracker.d.mts.map +1 -1
  5. package/esm/database-dirty-tracker.mjs +4 -1
  6. package/esm/database-dirty-tracker.mjs.map +1 -1
  7. package/esm/drivers/mongodb/mongodb-migration-driver.d.mts.map +1 -1
  8. package/esm/drivers/mongodb/mongodb-migration-driver.mjs +1 -0
  9. package/esm/drivers/mongodb/mongodb-migration-driver.mjs.map +1 -1
  10. package/esm/drivers/mongodb/mongodb-query-builder.d.mts.map +1 -1
  11. package/esm/drivers/mongodb/mongodb-query-builder.mjs +2 -4
  12. package/esm/drivers/mongodb/mongodb-query-builder.mjs.map +1 -1
  13. package/esm/drivers/mongodb/mongodb-query-parser.d.mts.map +1 -1
  14. package/esm/drivers/mongodb/mongodb-query-parser.mjs +21 -7
  15. package/esm/drivers/mongodb/mongodb-query-parser.mjs.map +1 -1
  16. package/esm/drivers/postgres/postgres-blueprint.d.mts.map +1 -1
  17. package/esm/drivers/postgres/postgres-blueprint.mjs +1 -2
  18. package/esm/drivers/postgres/postgres-blueprint.mjs.map +1 -1
  19. package/esm/drivers/postgres/postgres-driver.d.mts.map +1 -1
  20. package/esm/drivers/postgres/postgres-driver.mjs +1 -1
  21. package/esm/drivers/postgres/postgres-driver.mjs.map +1 -1
  22. package/esm/drivers/postgres/postgres-migration-driver.d.mts.map +1 -1
  23. package/esm/drivers/postgres/postgres-migration-driver.mjs +1 -2
  24. package/esm/drivers/postgres/postgres-migration-driver.mjs.map +1 -1
  25. package/esm/drivers/postgres/postgres-query-builder.d.mts.map +1 -1
  26. package/esm/drivers/postgres/postgres-query-builder.mjs +5 -6
  27. package/esm/drivers/postgres/postgres-query-builder.mjs.map +1 -1
  28. package/esm/drivers/postgres/postgres-query-parser.d.mts.map +1 -1
  29. package/esm/drivers/postgres/postgres-query-parser.mjs +2 -0
  30. package/esm/drivers/postgres/postgres-query-parser.mjs.map +1 -1
  31. package/esm/drivers/postgres/postgres-sql-serializer.mjs +1 -1
  32. package/esm/drivers/postgres/postgres-sql-serializer.mjs.map +1 -1
  33. package/esm/drivers/postgres/postgres-sync-adapter.d.mts.map +1 -1
  34. package/esm/drivers/postgres/postgres-sync-adapter.mjs +2 -2
  35. package/esm/drivers/postgres/postgres-sync-adapter.mjs.map +1 -1
  36. package/esm/migration/parse-created-at.mjs +1 -0
  37. package/esm/migration/parse-created-at.mjs.map +1 -1
  38. package/esm/query-builder/query-builder.d.mts.map +1 -1
  39. package/esm/query-builder/query-builder.mjs +27 -9
  40. package/esm/query-builder/query-builder.mjs.map +1 -1
  41. package/esm/relations/relation-loader.d.mts.map +1 -1
  42. package/esm/relations/relation-loader.mjs +1 -0
  43. package/esm/relations/relation-loader.mjs.map +1 -1
  44. package/esm/utils/is-valid-date-value.mjs +4 -1
  45. package/esm/utils/is-valid-date-value.mjs.map +1 -1
  46. package/package.json +4 -4
package/CHANGELOG.md CHANGED
@@ -4,6 +4,19 @@ All notable changes to `@warlock.js/cascade` are documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). `@warlock.js/*` packages are released in lockstep — every package shares the same version number, so a version below may list only the changes that affected this package.
6
6
 
7
+ ## 5.7.0 - 2026-09-11
8
+
9
+ ### Fixed
10
+
11
+ - The Postgres query builder could quote a malformed or empty field path straight into generated SQL, producing a syntactically valid query against the wrong identifier; it now throws naming the offending field path instead.
12
+ - The MongoDB pipeline builder could build `$group`, `$lookup`, `$limit`/`$skip`/`$setWindowFields` stages from an empty operation group, producing malformed stages (e.g. `{ $limit: undefined }`, a `$lookup` with no `from`/`localField`/`foreignField`) that MongoDB rejected only at query execution. These now resolve to the documented safe defaults (`null`/skip) instead.
13
+ - The dirty-change tracker and the MongoDB migration driver could write or delete the literal key `"undefined"` on a document when a dirty-path segment was missing, instead of leaving the real field untouched.
14
+ - The query builder's count and JSON-projection handling could dereference an absent regex capture and throw, instead of falling back to the same empty result its other branches already return.
15
+
16
+ ### Changed
17
+
18
+ - Internal type-safety hardening elsewhere; no other behaviour change.
19
+
7
20
  ## 5.5.0 - 2026-09-07
8
21
 
9
22
  ### Fixed
package/cjs/index.cjs CHANGED
@@ -794,10 +794,13 @@ var DatabaseDirtyTracker = class {
794
794
  let container = this.currentRaw;
795
795
  for (let index = 0; index < segments.length - 1; index += 1) {
796
796
  if (container === void 0 || container === null) return;
797
- container = this.resolveSegment(container, segments[index]);
797
+ const segment = segments[index];
798
+ if (segment === void 0) return;
799
+ container = this.resolveSegment(container, segment);
798
800
  }
799
801
  if (container === void 0 || container === null) return;
800
802
  const lastSegment = segments[segments.length - 1];
803
+ if (lastSegment === void 0) return;
801
804
  if (Array.isArray(container)) {
802
805
  const numericIndex = Number(lastSegment);
803
806
  if (!Number.isNaN(numericIndex)) container.splice(numericIndex, 1);
@@ -1702,6 +1705,7 @@ var RelationLoader = class RelationLoader {
1702
1705
  async loadRelation(name, constraint) {
1703
1706
  const path = this.parseNestedRelation(name);
1704
1707
  const rootRelation = path[0];
1708
+ if (rootRelation === void 0) throw new Error(`Relation name "${name}" could not be parsed into a relation path on model "${this.modelClass.name}".`);
1705
1709
  const definition = this.getRelationDefinition(rootRelation);
1706
1710
  if (!definition) throw new Error(`Relation "${rootRelation}" is not defined on model "${this.modelClass.name}". Make sure to define it in the static 'relations' property.`);
1707
1711
  switch (definition.type) {
@@ -7701,7 +7705,10 @@ function isValidDateValue(value) {
7701
7705
  if (!isoRegex.test(value)) return false;
7702
7706
  const date = new Date(value);
7703
7707
  if (Number.isNaN(date.getTime())) return false;
7704
- const [y, m, d] = value.split("T")[0].split("-").map(Number);
7708
+ const datePart = value.split("T")[0];
7709
+ if (datePart === void 0) return false;
7710
+ const [y, m, d] = datePart.split("-").map(Number);
7711
+ if (y === void 0 || m === void 0 || d === void 0) return false;
7705
7712
  return date.getUTCFullYear() === y && date.getUTCMonth() + 1 === m && date.getUTCDate() === d;
7706
7713
  }
7707
7714
 
@@ -8180,6 +8187,7 @@ var MongoMigrationDriver = class {
8180
8187
  const indexSpec = {};
8181
8188
  for (let i = 0; i < index.columns.length; i++) {
8182
8189
  const column = index.columns[i];
8190
+ if (column === void 0) continue;
8183
8191
  indexSpec[column] = index.directions?.[i] === "desc" ? -1 : 1;
8184
8192
  }
8185
8193
  const options = {};
@@ -8594,12 +8602,22 @@ var QueryBuilder = class QueryBuilder {
8594
8602
  * builder.getOps("where", "orWhere", "whereIn")
8595
8603
  */
8596
8604
  getOps(...types) {
8597
- if (types.length === 1) return (this.opIndex.get(types[0]) ?? []).map((i) => this.operations[i]);
8605
+ if (types.length === 1) {
8606
+ const type = types[0];
8607
+ if (type === void 0) return [];
8608
+ return (this.opIndex.get(type) ?? []).flatMap((index) => {
8609
+ const operation = this.operations[index];
8610
+ return operation === void 0 ? [] : [operation];
8611
+ });
8612
+ }
8598
8613
  const result = [];
8599
- for (const type of types) for (const idx of this.opIndex.get(type) ?? []) result.push({
8600
- idx,
8601
- op: this.operations[idx]
8602
- });
8614
+ for (const type of types) for (const idx of this.opIndex.get(type) ?? []) {
8615
+ const operation = this.operations[idx];
8616
+ if (operation !== void 0) result.push({
8617
+ idx,
8618
+ op: operation
8619
+ });
8620
+ }
8603
8621
  return result.sort((a, b) => a.idx - b.idx).map((r) => r.op);
8604
8622
  }
8605
8623
  /**
@@ -8611,7 +8629,9 @@ var QueryBuilder = class QueryBuilder {
8611
8629
  rebuildIndex() {
8612
8630
  this.opIndex = /* @__PURE__ */ new Map();
8613
8631
  for (let i = 0; i < this.operations.length; i++) {
8614
- const type = this.operations[i].type;
8632
+ const operation = this.operations[i];
8633
+ if (operation === void 0) continue;
8634
+ const type = operation.type;
8615
8635
  const list = this.opIndex.get(type);
8616
8636
  if (list) list.push(i);
8617
8637
  else this.opIndex.set(type, [i]);
@@ -9298,9 +9318,15 @@ var QueryBuilder = class QueryBuilder {
9298
9318
  relation: trimmed,
9299
9319
  alias: `${trimmed}Count`
9300
9320
  };
9321
+ const relation = match[1];
9322
+ const alias = match[2];
9323
+ if (relation === void 0 || alias === void 0) return {
9324
+ relation: trimmed,
9325
+ alias: `${trimmed}Count`
9326
+ };
9301
9327
  return {
9302
- relation: match[1].trim(),
9303
- alias: match[2].trim()
9328
+ relation: relation.trim(),
9329
+ alias: alias.trim()
9304
9330
  };
9305
9331
  }
9306
9332
  /**
@@ -9427,7 +9453,7 @@ var QueryBuilder = class QueryBuilder {
9427
9453
  /** JSON path extraction as a projected field. */
9428
9454
  selectJson(path, alias) {
9429
9455
  const parts = path.split("->");
9430
- const column = parts[0];
9456
+ const column = parts[0] ?? "";
9431
9457
  const jsonPath = parts.slice(1).join("->");
9432
9458
  const expr = jsonPath ? `${column}->>'${jsonPath}'` : column;
9433
9459
  return alias ? this.selectAs(expr, alias) : this.selectRaw(expr);
@@ -10135,6 +10161,7 @@ var MongoQueryParser = class {
10135
10161
  trackGroupFieldNames(stage, operations, stageIndex) {
10136
10162
  if (stage === "$group") {
10137
10163
  const op = operations[0];
10164
+ if (op === void 0) return;
10138
10165
  if (op.type === "groupByWithAggregates" && op.data.fields) {
10139
10166
  const fieldNames = this.extractGroupFieldNames(op.data.fields);
10140
10167
  if (fieldNames) this.groupFieldNames.set(stageIndex, fieldNames);
@@ -10215,7 +10242,7 @@ var MongoQueryParser = class {
10215
10242
  let output = "MongoDB Aggregation Pipeline:\n";
10216
10243
  output += "═".repeat(50) + "\n";
10217
10244
  pipeline.forEach((stage, index) => {
10218
- const stageName = Object.keys(stage)[0];
10245
+ const stageName = Object.keys(stage)[0] ?? "<empty stage>";
10219
10246
  const stageData = stage[stageName];
10220
10247
  if (index > 0) output += "\n";
10221
10248
  output += `Stage ${index + 1}: ${_mongez_copper.colors.redBright(stageName)}\n`;
@@ -10272,9 +10299,18 @@ var MongoQueryParser = class {
10272
10299
  case "$sort": return this.buildSortStage(operations);
10273
10300
  case "$group": return this.buildGroupStage(operations);
10274
10301
  case "$lookup": return this.buildLookupStage(operations);
10275
- case "$limit": return { $limit: operations[0].data.value };
10276
- case "$skip": return { $skip: operations[0].data.value };
10277
- case "$setWindowFields": return { $setWindowFields: operations[0].data.spec };
10302
+ case "$limit": {
10303
+ const [first] = operations;
10304
+ return first === void 0 ? null : { $limit: first.data.value };
10305
+ }
10306
+ case "$skip": {
10307
+ const [first] = operations;
10308
+ return first === void 0 ? null : { $skip: first.data.value };
10309
+ }
10310
+ case "$setWindowFields": {
10311
+ const [first] = operations;
10312
+ return first === void 0 ? null : { $setWindowFields: first.data.spec };
10313
+ }
10278
10314
  default: return null;
10279
10315
  }
10280
10316
  }
@@ -10794,8 +10830,9 @@ var MongoQueryParser = class {
10794
10830
  return this.resolveProjectionExpression(value);
10795
10831
  }
10796
10832
  inferJsonAlias(path) {
10797
- const segments = this.normalizePath(path).split(".");
10798
- return segments[segments.length - 1];
10833
+ const normalized = this.normalizePath(path);
10834
+ const segments = normalized.split(".");
10835
+ return segments[segments.length - 1] ?? normalized;
10799
10836
  }
10800
10837
  buildConcatExpression(values) {
10801
10838
  return { $concat: values.map((value) => this.normalizeFieldReference(value)) };
@@ -10901,6 +10938,7 @@ var MongoQueryParser = class {
10901
10938
  */
10902
10939
  buildGroupStage(operations) {
10903
10940
  const op = operations[0];
10941
+ if (op === void 0) return null;
10904
10942
  switch (op.type) {
10905
10943
  case "groupBy": {
10906
10944
  const stage = this.buildGroupByStage(op.data.fields);
@@ -11086,7 +11124,9 @@ var MongoQueryParser = class {
11086
11124
  * @returns The $lookup stage or null
11087
11125
  */
11088
11126
  buildLookupStage(operations) {
11089
- const options = operations[0].data;
11127
+ const op = operations[0];
11128
+ if (op === void 0) return null;
11129
+ const options = op.data;
11090
11130
  return { $lookup: {
11091
11131
  from: options.table,
11092
11132
  localField: options.localField,
@@ -12468,8 +12508,7 @@ var MongoQueryBuilder = class MongoQueryBuilder extends QueryBuilder {
12468
12508
  * @returns the first document or null
12469
12509
  */
12470
12510
  async first() {
12471
- const results = await this.limit(1).get();
12472
- return results.length > 0 ? results[0] : null;
12511
+ return (await this.limit(1).get())[0] ?? null;
12473
12512
  }
12474
12513
  /**
12475
12514
  * Executes the query and returns the first matching document, throwing if none found.
@@ -12500,8 +12539,7 @@ var MongoQueryBuilder = class MongoQueryBuilder extends QueryBuilder {
12500
12539
  async count() {
12501
12540
  const pipeline = this.buildPipeline();
12502
12541
  pipeline.push({ $count: "total" });
12503
- const results = await this.execute(pipeline);
12504
- return results.length > 0 ? results[0].total : 0;
12542
+ return (await this.execute(pipeline))[0]?.total ?? 0;
12505
12543
  }
12506
12544
  /**
12507
12545
  * Calculates the sum of a numeric field across matching documents.
@@ -13846,8 +13884,7 @@ var PostgresBlueprint = class {
13846
13884
  AND tablename = $1`, [table])).rows.map((row) => {
13847
13885
  const isUnique = row.indexdef.includes("UNIQUE");
13848
13886
  const isPrimary = row.indexname.endsWith("_pkey");
13849
- const columnsMatch = row.indexdef.match(/\(([^)]+)\)/);
13850
- const columns = columnsMatch ? columnsMatch[1].split(",").map((c) => c.trim().replace(/"/g, "")) : [];
13887
+ const columns = (row.indexdef.match(/\(([^)]+)\)/)?.[1] ?? "").split(",").map((c) => c.trim().replace(/"/g, "")).filter(Boolean);
13851
13888
  let type = "btree";
13852
13889
  if (row.indexdef.includes("USING GIN")) type = "gin";
13853
13890
  else if (row.indexdef.includes("USING GIST")) type = "gist";
@@ -14675,8 +14712,7 @@ var PostgresMigrationDriver = class {
14675
14712
  return (await this.driver.query(`SELECT indexname, indexdef FROM pg_indexes WHERE schemaname = 'public' AND tablename = $1`, [table])).rows.map((row) => {
14676
14713
  const isUnique = row.indexdef.includes("UNIQUE");
14677
14714
  const isPrimary = row.indexname.endsWith("_pkey");
14678
- const columnsMatch = row.indexdef.match(/\(([^)]+)\)/);
14679
- const columns = columnsMatch ? columnsMatch[1].split(",").map((c) => c.trim().replace(/"/g, "")) : [];
14715
+ const columns = (row.indexdef.match(/\(([^)]+)\)/)?.[1] ?? "").split(",").map((c) => c.trim().replace(/"/g, "")).filter(Boolean);
14680
14716
  let type = "btree";
14681
14717
  if (row.indexdef.includes("USING GIN")) type = "gin";
14682
14718
  else if (row.indexdef.includes("USING GIST")) type = "gist";
@@ -15616,10 +15652,12 @@ var PostgresQueryParser = class PostgresQueryParser {
15616
15652
  if (parts.length === 1) expression = `${this.dialect.quoteIdentifier(effectiveTable)}.${this.dialect.quoteIdentifier(field)}`;
15617
15653
  else if (parts.length === 2) {
15618
15654
  const [first, second] = parts;
15655
+ if (first === void 0 || second === void 0) throw new Error(`Cannot parse field path "${field}": expected two non-empty segments.`);
15619
15656
  if (this.isTableReference(first)) expression = `${this.dialect.quoteIdentifier(first)}.${this.dialect.quoteIdentifier(second)}`;
15620
15657
  else expression = this.buildJsonbPath(effectiveTable, first, [second]);
15621
15658
  } else {
15622
15659
  const [first, second, ...rest] = parts;
15660
+ if (first === void 0 || second === void 0) throw new Error(`Cannot parse field path "${field}": expected at least three non-empty segments.`);
15623
15661
  if (this.isTableReference(first)) expression = this.buildJsonbPath(first, second, rest);
15624
15662
  else expression = this.buildJsonbPath(effectiveTable, first, [second, ...rest]);
15625
15663
  }
@@ -16116,8 +16154,7 @@ var PostgresQueryBuilder = class PostgresQueryBuilder extends QueryBuilder {
16116
16154
  const segments = path.split(".");
16117
16155
  let currentModel = this.modelClass;
16118
16156
  let currentPath = "";
16119
- for (let i = 0; i < segments.length; i++) {
16120
- const rawSeg = segments[i];
16157
+ for (const [i, rawSeg] of segments.entries()) {
16121
16158
  const colonIdx = rawSeg.indexOf(":");
16122
16159
  const segName = colonIdx === -1 ? rawSeg : rawSeg.slice(0, colonIdx);
16123
16160
  const segColumns = colonIdx === -1 ? void 0 : rawSeg.slice(colonIdx + 1).split(",").filter(Boolean);
@@ -16276,7 +16313,7 @@ var PostgresQueryBuilder = class PostgresQueryBuilder extends QueryBuilder {
16276
16313
  async distinct(field) {
16277
16314
  this.hydrateCallback = void 0;
16278
16315
  this.distinctValues(field);
16279
- return (await this.get()).map((row) => row[field]);
16316
+ return (await this.get()).map((row) => row[field]).filter((value) => value !== void 0);
16280
16317
  }
16281
16318
  /** Get array of all values for a single field. */
16282
16319
  async pluck(field) {
@@ -16503,7 +16540,7 @@ var PostgresQueryBuilder = class PostgresQueryBuilder extends QueryBuilder {
16503
16540
  }
16504
16541
  /** Pluck scalar values for a single field (alias for pluck). */
16505
16542
  async pluckOne(field) {
16506
- return (await this.select([field]).get()).map((row) => row[field]);
16543
+ return (await this.select([field]).get()).map((row) => row[field]).filter((value) => value !== void 0);
16507
16544
  }
16508
16545
  /**
16509
16546
  * Before `get()` runs the parser, consume any joinWith ops recorded by the base
@@ -16803,7 +16840,7 @@ var PostgresQueryBuilder = class PostgresQueryBuilder extends QueryBuilder {
16803
16840
  bindings: []
16804
16841
  };
16805
16842
  return {
16806
- fragment: match[1].replace(/\$\d+/g, "?"),
16843
+ fragment: (match[1] ?? "").replace(/\$\d+/g, "?"),
16807
16844
  bindings: bindings ?? []
16808
16845
  };
16809
16846
  }
@@ -16904,7 +16941,7 @@ var PostgresQueryBuilder = class PostgresQueryBuilder extends QueryBuilder {
16904
16941
  }
16905
16942
  const RelatedModel = resolveModelClass(config.model);
16906
16943
  if (!RelatedModel) continue;
16907
- const childKeys = Array.from(this.joinRelations.keys()).filter((p) => p.startsWith(`${path}.`)).map((p) => p.split(".")[path.split(".").length]);
16944
+ const childKeys = Array.from(this.joinRelations.keys()).filter((p) => p.startsWith(`${path}.`)).map((p) => p.split(".")[path.split(".").length]).filter((segment) => segment !== void 0);
16908
16945
  if (config.type === "hasMany") attachLoadedRelation(model, key, (Array.isArray(data) ? data : []).map((row) => {
16909
16946
  const rowData = { ...row };
16910
16947
  for (const childKey of childKeys) delete rowData[childKey];
@@ -17095,7 +17132,7 @@ var PostgresSQLSerializer = class extends SQLSerializer {
17095
17132
  const statements = [sql];
17096
17133
  if (column.checkConstraint) statements.push(this.addCheck(table, column.checkConstraint.name, column.checkConstraint.expression));
17097
17134
  if (column.type === "vector") return ["CREATE EXTENSION IF NOT EXISTS vector", ...statements];
17098
- return statements.length === 1 ? statements[0] : statements;
17135
+ return statements.length === 1 ? statements[0] ?? statements : statements;
17099
17136
  }
17100
17137
  dropColumn(table, column) {
17101
17138
  return `ALTER TABLE ${this.dialect.quoteIdentifier(table)} DROP COLUMN ${this.dialect.quoteIdentifier(column)}`;
@@ -17319,7 +17356,7 @@ var PostgresSyncAdapter = class {
17319
17356
  let paramIndex = 1;
17320
17357
  for (const [path, value] of Object.entries(update)) if (path.includes(".")) {
17321
17358
  const [column, ...pathParts] = path.split(".");
17322
- const quotedColumn = this.driver.dialect.quoteIdentifier(column);
17359
+ const quotedColumn = this.driver.dialect.quoteIdentifier(column ?? path);
17323
17360
  const jsonPath = `{${pathParts.join(",")}}`;
17324
17361
  const placeholder = this.driver.dialect.placeholder(paramIndex++);
17325
17362
  params.push(JSON.stringify(value));
@@ -17333,7 +17370,7 @@ var PostgresSyncAdapter = class {
17333
17370
  const whereClauses = [];
17334
17371
  for (const [key, value] of Object.entries(filter)) if (key.includes(".")) {
17335
17372
  const [column, ...pathParts] = key.split(".");
17336
- const quotedColumn = this.driver.dialect.quoteIdentifier(column);
17373
+ const quotedColumn = this.driver.dialect.quoteIdentifier(column ?? key);
17337
17374
  const intermediateExpr = pathParts.slice(0, -1).map((p) => `->'${p}'`).join("");
17338
17375
  const finalExpr = `->>'${pathParts[pathParts.length - 1]}'`;
17339
17376
  const placeholder = this.driver.dialect.placeholder(paramIndex++);
@@ -17764,7 +17801,7 @@ var PostgresDriver = class {
17764
17801
  const nums = new Array(parts.length);
17765
17802
  let isNumericVector = parts.length > 0;
17766
17803
  for (let i = 0; i < parts.length; i++) {
17767
- const n = +parts[i];
17804
+ const n = +(parts[i] ?? "");
17768
17805
  if (!Number.isFinite(n)) {
17769
17806
  isNumericVector = false;
17770
17807
  break;
@@ -22010,6 +22047,7 @@ function parseCreatedAt(createdAt) {
22010
22047
  const match = createdAt.match(/^(\d{2})-(\d{2})-(\d{4})_(\d{2})-(\d{2})-(\d{2})$/);
22011
22048
  if (match) {
22012
22049
  const [, first, second, year, hour, minute, second_time] = match;
22050
+ if (first === void 0 || second === void 0 || year === void 0 || hour === void 0 || minute === void 0 || second_time === void 0) return;
22013
22051
  const firstNum = parseInt(first);
22014
22052
  const secondNum = parseInt(second);
22015
22053
  let month, day;