datanotes 1.5.0 → 2.0.1

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.
@@ -431,9 +431,9 @@ var require_anchors = __commonJS({
431
431
  }
432
432
  return true;
433
433
  }
434
- function anchorNames(root2) {
434
+ function anchorNames(root) {
435
435
  const anchors = /* @__PURE__ */ new Set();
436
- visit.visit(root2, {
436
+ visit.visit(root, {
437
437
  Value(_key, node) {
438
438
  if (node.anchor)
439
439
  anchors.add(node.anchor);
@@ -7233,7 +7233,7 @@ var require_public_api = __commonJS({
7233
7233
  }
7234
7234
  return doc;
7235
7235
  }
7236
- function parse3(src, reviver, options) {
7236
+ function parse2(src, reviver, options) {
7237
7237
  let _reviver = void 0;
7238
7238
  if (typeof reviver === "function") {
7239
7239
  _reviver = reviver;
@@ -7274,7 +7274,7 @@ var require_public_api = __commonJS({
7274
7274
  return value.toString(options);
7275
7275
  return new Document.Document(value, _replacer, options).toString(options);
7276
7276
  }
7277
- exports2.parse = parse3;
7277
+ exports2.parse = parse2;
7278
7278
  exports2.parseAllDocuments = parseAllDocuments;
7279
7279
  exports2.parseDocument = parseDocument3;
7280
7280
  exports2.stringify = stringify2;
@@ -7413,9 +7413,6 @@ function dot(a, b) {
7413
7413
 
7414
7414
  // src/core/settings.ts
7415
7415
  var DEFAULT_SETTINGS = {
7416
- templateProperty: "template",
7417
- migrationsProperty: "_migrations",
7418
- journalFolder: "_meta/migrations",
7419
7416
  storeFolder: ".datanotes",
7420
7417
  journalRetentionDays: 90,
7421
7418
  fileLogEnabled: true,
@@ -7428,7 +7425,6 @@ var DEFAULT_SETTINGS = {
7428
7425
  telemetryHeaders: {},
7429
7426
  telemetryProtocol: "http/protobuf",
7430
7427
  autoRecompute: true,
7431
- viewNotes: true,
7432
7428
  semanticEnabled: false,
7433
7429
  semanticProvider: "ollama",
7434
7430
  semanticBaseUrl: "",
@@ -7440,9 +7436,6 @@ var DEFAULT_SETTINGS = {
7440
7436
  httpServerToken: ""
7441
7437
  };
7442
7438
  var KEYS = [
7443
- "templateProperty",
7444
- "migrationsProperty",
7445
- "journalFolder",
7446
7439
  "storeFolder",
7447
7440
  "journalRetentionDays",
7448
7441
  "fileLogEnabled",
@@ -7455,7 +7448,6 @@ var KEYS = [
7455
7448
  "telemetryHeaders",
7456
7449
  "telemetryProtocol",
7457
7450
  "autoRecompute",
7458
- "viewNotes",
7459
7451
  "semanticEnabled",
7460
7452
  "semanticProvider",
7461
7453
  "semanticBaseUrl",
@@ -7466,19 +7458,6 @@ var KEYS = [
7466
7458
  "httpServerPort",
7467
7459
  "httpServerToken"
7468
7460
  ];
7469
- var RESERVED_MIGRATIONS_KEYS = /* @__PURE__ */ new Set([
7470
- "_protected",
7471
- "_extend",
7472
- "_inherits",
7473
- "_table",
7474
- "_columns"
7475
- ]);
7476
- function normalizeMigrationsProperty(out) {
7477
- const m = out.migrationsProperty;
7478
- if (m.length === 0 || m === out.templateProperty || RESERVED_MIGRATIONS_KEYS.has(m)) {
7479
- out.migrationsProperty = DEFAULT_SETTINGS.migrationsProperty;
7480
- }
7481
- }
7482
7461
  function mergeWithDefaults(loaded) {
7483
7462
  const out = { ...DEFAULT_SETTINGS };
7484
7463
  for (const key of KEYS) {
@@ -7486,18 +7465,6 @@ function mergeWithDefaults(loaded) {
7486
7465
  const raw = loaded[key];
7487
7466
  if (raw === void 0) continue;
7488
7467
  switch (key) {
7489
- case "templateProperty": {
7490
- if (typeof raw === "string" && raw.length > 0) {
7491
- out.templateProperty = raw;
7492
- }
7493
- break;
7494
- }
7495
- case "migrationsProperty": {
7496
- if (typeof raw === "string" && raw.length > 0) {
7497
- out.migrationsProperty = raw;
7498
- }
7499
- break;
7500
- }
7501
7468
  case "telemetryEndpoint": {
7502
7469
  if (typeof raw === "string" && /^https?:\/\/\S+$/.test(raw.trim())) {
7503
7470
  out.telemetryEndpoint = raw.trim().replace(/\/+$/, "");
@@ -7544,12 +7511,6 @@ function mergeWithDefaults(loaded) {
7544
7511
  if (typeof raw === "number" && Number.isInteger(raw) && raw >= 1) out[key] = raw;
7545
7512
  break;
7546
7513
  }
7547
- case "journalFolder": {
7548
- if (typeof raw === "string" && raw.trim().replace(/^\/+|\/+$/g, "").length > 0) {
7549
- out.journalFolder = raw.trim().replace(/^\/+|\/+$/g, "");
7550
- }
7551
- break;
7552
- }
7553
7514
  case "semanticProvider": {
7554
7515
  if (typeof raw === "string" && raw in PROVIDER_PRESETS) out.semanticProvider = raw;
7555
7516
  break;
@@ -7585,8 +7546,7 @@ function mergeWithDefaults(loaded) {
7585
7546
  case "telemetryEnabled":
7586
7547
  case "fileLogEnabled":
7587
7548
  case "semanticEnabled":
7588
- case "autoRecompute":
7589
- case "viewNotes": {
7549
+ case "autoRecompute": {
7590
7550
  if (typeof raw === "boolean") {
7591
7551
  out[key] = raw;
7592
7552
  }
@@ -7594,7 +7554,6 @@ function mergeWithDefaults(loaded) {
7594
7554
  }
7595
7555
  }
7596
7556
  }
7597
- normalizeMigrationsProperty(out);
7598
7557
  return out;
7599
7558
  }
7600
7559
 
@@ -7834,14 +7793,6 @@ function valuesFromFilename(pattern, basename3) {
7834
7793
 
7835
7794
  // src/core/frontmatter.ts
7836
7795
  var import_yaml = __toESM(require_dist(), 1);
7837
- var DEFAULT_MIGRATIONS_KEY = "_migrations";
7838
- var UnsupportedNestedMappingError = class extends Error {
7839
- constructor(message, keyPath) {
7840
- super(message);
7841
- this.keyPath = keyPath;
7842
- this.name = "UnsupportedNestedMappingError";
7843
- }
7844
- };
7845
7796
  var FRONTMATTER_BLOCK = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n([\s\S]*))?$/;
7846
7797
  function splitFrontmatter(markdown) {
7847
7798
  const m = markdown.match(FRONTMATTER_BLOCK);
@@ -7850,131 +7801,6 @@ function splitFrontmatter(markdown) {
7850
7801
  if (yamlText === void 0) return null;
7851
7802
  return { yamlText, body: m[2] ?? "" };
7852
7803
  }
7853
- function normalizeFlowStyleOpKeys(entry) {
7854
- const compound = /^(op|from|to|key):(.+)$/;
7855
- const out = { ...entry };
7856
- const toDelete = [];
7857
- for (const k of Object.keys(out)) {
7858
- const m = k.match(compound);
7859
- if (m == null) continue;
7860
- const fieldRaw = m[1];
7861
- const suffixRaw = m[2];
7862
- if (fieldRaw === void 0 || suffixRaw === void 0) continue;
7863
- const field = fieldRaw;
7864
- const suffix = suffixRaw.trim();
7865
- if (suffix.length === 0) continue;
7866
- const raw = out[k];
7867
- const preferred = raw !== null && raw !== void 0 && raw !== "" ? raw : suffix;
7868
- const cur = out[field];
7869
- if (cur !== void 0 && cur !== null && String(cur) !== String(preferred)) {
7870
- continue;
7871
- }
7872
- out[field] = preferred;
7873
- toDelete.push(k);
7874
- }
7875
- for (const k of toDelete) {
7876
- delete out[k];
7877
- }
7878
- return out;
7879
- }
7880
- function migrationEntryMapToObject(map, entryPath, listRoot) {
7881
- const out = {};
7882
- for (const pair of map.items) {
7883
- const kn = pair.key;
7884
- const k = (0, import_yaml.isScalar)(kn) ? String(kn.value) : String(kn);
7885
- const v = pair.value;
7886
- if (v == null) {
7887
- out[k] = null;
7888
- continue;
7889
- }
7890
- if ((0, import_yaml.isScalar)(v)) {
7891
- out[k] = v.value;
7892
- continue;
7893
- }
7894
- throw new UnsupportedNestedMappingError(
7895
- `Invalid value in ${listRoot} entry (path: ${entryPath}.${k})`,
7896
- `${entryPath}.${k}`
7897
- );
7898
- }
7899
- return normalizeFlowStyleOpKeys(out);
7900
- }
7901
- function parseMigrationsSequence(node, listRoot) {
7902
- if (node == null) return [];
7903
- if (!(node instanceof import_yaml.YAMLSeq)) {
7904
- throw new UnsupportedNestedMappingError(
7905
- `${listRoot} must be a YAML sequence (path: ${listRoot})`,
7906
- listRoot
7907
- );
7908
- }
7909
- return node.items.map((item, i) => {
7910
- const p = `${listRoot}[${i}]`;
7911
- if (item == null || !(item instanceof import_yaml.YAMLMap)) {
7912
- throw new Error(`${p}: expected a mapping`);
7913
- }
7914
- return migrationEntryMapToObject(item, p, listRoot);
7915
- });
7916
- }
7917
- function tableEntryMapToObject(map, entryPath) {
7918
- const out = {};
7919
- for (const pair of map.items) {
7920
- const kn = pair.key;
7921
- const k = (0, import_yaml.isScalar)(kn) ? String(kn.value) : String(kn);
7922
- const v = pair.value;
7923
- if (v == null) {
7924
- out[k] = null;
7925
- } else if ((0, import_yaml.isScalar)(v)) {
7926
- out[k] = v.value;
7927
- } else if (v instanceof import_yaml.YAMLSeq) {
7928
- out[k] = v.items.map((item, i) => {
7929
- if (item == null) return null;
7930
- if ((0, import_yaml.isScalar)(item)) return item.value;
7931
- throw new UnsupportedNestedMappingError(
7932
- `Invalid list item in ${entryPath}.${k}[${i}]`,
7933
- `${entryPath}.${k}[${i}]`
7934
- );
7935
- });
7936
- } else {
7937
- throw new UnsupportedNestedMappingError(
7938
- `Invalid value in ${entryPath}.${k}`,
7939
- `${entryPath}.${k}`
7940
- );
7941
- }
7942
- }
7943
- return out;
7944
- }
7945
- function parseTableEntriesSequence(node, listRoot) {
7946
- if (node == null || (0, import_yaml.isScalar)(node) && node.value == null) return [];
7947
- if (!(node instanceof import_yaml.YAMLSeq)) {
7948
- throw new UnsupportedNestedMappingError(
7949
- `${listRoot} must be a YAML sequence (path: ${listRoot})`,
7950
- listRoot
7951
- );
7952
- }
7953
- return node.items.map((item, i) => {
7954
- const p = `${listRoot}[${i}]`;
7955
- if (item == null || !(item instanceof import_yaml.YAMLMap)) {
7956
- throw new Error(`${p}: expected a mapping`);
7957
- }
7958
- return tableEntryMapToObject(item, p);
7959
- });
7960
- }
7961
- var TABLE_SEQUENCE_KEYS = /* @__PURE__ */ new Set(["_table", "_columns"]);
7962
- function assertPlainValueAtPath(node, keyPath) {
7963
- if (node == null) return null;
7964
- if ((0, import_yaml.isScalar)(node)) return node.value;
7965
- if (node instanceof import_yaml.YAMLMap) {
7966
- throw new UnsupportedNestedMappingError(
7967
- `Nested YAML mapping is not supported in v1 (path: ${keyPath})`,
7968
- keyPath
7969
- );
7970
- }
7971
- if (node instanceof import_yaml.YAMLSeq) {
7972
- return node.items.map(
7973
- (item, i) => assertPlainValueAtPath(item, `${keyPath}[${i}]`)
7974
- );
7975
- }
7976
- throw new Error(`Unsupported YAML node at ${keyPath}`);
7977
- }
7978
7804
  function coerceMisparsedYamlWikilinkToString(value) {
7979
7805
  let cur = value;
7980
7806
  const steps = [];
@@ -7990,7 +7816,7 @@ function coerceMisparsedYamlWikilinkToString(value) {
7990
7816
  }
7991
7817
  return `[[${cur}]]`;
7992
7818
  }
7993
- function yamlNodeToPlainForChildNote(node, keyPath) {
7819
+ function yamlNodeToPlain(node, keyPath) {
7994
7820
  if (node == null) return null;
7995
7821
  if ((0, import_yaml.isScalar)(node)) return node.value;
7996
7822
  if (node instanceof import_yaml.YAMLMap) {
@@ -7998,55 +7824,34 @@ function yamlNodeToPlainForChildNote(node, keyPath) {
7998
7824
  for (const pair of node.items) {
7999
7825
  const kn = pair.key;
8000
7826
  const k = (0, import_yaml.isScalar)(kn) ? String(kn.value) : String(kn);
8001
- out[k] = yamlNodeToPlainForChildNote(pair.value, `${keyPath}.${k}`);
7827
+ out[k] = yamlNodeToPlain(pair.value, `${keyPath}.${k}`);
8002
7828
  }
8003
7829
  return out;
8004
7830
  }
8005
7831
  if (node instanceof import_yaml.YAMLSeq) {
8006
7832
  return node.items.map(
8007
- (item, i) => yamlNodeToPlainForChildNote(item, `${keyPath}[${i}]`)
7833
+ (item, i) => yamlNodeToPlain(item, `${keyPath}[${i}]`)
8008
7834
  );
8009
7835
  }
8010
7836
  throw new Error(`Unsupported YAML node at ${keyPath}`);
8011
7837
  }
8012
- function parseYamlBlockToOrdered(yamlText, migrationsKey = DEFAULT_MIGRATIONS_KEY) {
8013
- if (yamlText.trim() === "") return [];
8014
- const doc = (0, import_yaml.parseDocument)(yamlText);
8015
- if (doc.errors.length > 0) {
8016
- const first = doc.errors[0];
8017
- throw new Error(first?.message ?? "YAML parse error");
8018
- }
8019
- const root2 = doc.contents;
8020
- if (root2 == null) return [];
8021
- if (!(root2 instanceof import_yaml.YAMLMap)) {
8022
- throw new Error("Frontmatter root must be a YAML mapping (object)");
8023
- }
8024
- const entries = [];
8025
- for (const pair of root2.items) {
8026
- const kn = pair.key;
8027
- const key = (0, import_yaml.isScalar)(kn) ? String(kn.value) : String(kn);
8028
- const value = key === migrationsKey || key === "_inherits" ? parseMigrationsSequence(pair.value, key) : TABLE_SEQUENCE_KEYS.has(key) ? parseTableEntriesSequence(pair.value, key) : assertPlainValueAtPath(pair.value, key);
8029
- entries.push([key, value]);
8030
- }
8031
- return entries;
8032
- }
8033
- function parseYamlBlockToOrderedForChildNote(yamlText, migrationsKey = DEFAULT_MIGRATIONS_KEY, wikilinkStringKeys = /* @__PURE__ */ new Set(["template"])) {
7838
+ function parseYamlBlockToOrdered(yamlText, wikilinkStringKeys = /* @__PURE__ */ new Set()) {
8034
7839
  if (yamlText.trim() === "") return [];
8035
7840
  const doc = (0, import_yaml.parseDocument)(yamlText);
8036
7841
  if (doc.errors.length > 0) {
8037
7842
  const first = doc.errors[0];
8038
7843
  throw new Error(first?.message ?? "YAML parse error");
8039
7844
  }
8040
- const root2 = doc.contents;
8041
- if (root2 == null) return [];
8042
- if (!(root2 instanceof import_yaml.YAMLMap)) {
7845
+ const root = doc.contents;
7846
+ if (root == null) return [];
7847
+ if (!(root instanceof import_yaml.YAMLMap)) {
8043
7848
  throw new Error("Frontmatter root must be a YAML mapping (object)");
8044
7849
  }
8045
7850
  const entries = [];
8046
- for (const pair of root2.items) {
7851
+ for (const pair of root.items) {
8047
7852
  const kn = pair.key;
8048
7853
  const key = (0, import_yaml.isScalar)(kn) ? String(kn.value) : String(kn);
8049
- let value = key === migrationsKey || key === "_inherits" ? parseMigrationsSequence(pair.value, key) : yamlNodeToPlainForChildNote(pair.value, key);
7854
+ let value = yamlNodeToPlain(pair.value, key);
8050
7855
  if (wikilinkStringKeys.has(key)) {
8051
7856
  value = coerceMisparsedYamlWikilinkToString(value);
8052
7857
  }
@@ -8054,27 +7859,13 @@ function parseYamlBlockToOrderedForChildNote(yamlText, migrationsKey = DEFAULT_M
8054
7859
  }
8055
7860
  return entries;
8056
7861
  }
8057
- function readOrderedFromMarkdownForChildNote(markdown, migrationsKey = DEFAULT_MIGRATIONS_KEY, wikilinkStringKeys = /* @__PURE__ */ new Set(["template"])) {
8058
- const split2 = splitFrontmatter(markdown);
8059
- if (!split2) {
8060
- return { ordered: [], body: markdown };
8061
- }
8062
- return {
8063
- ordered: parseYamlBlockToOrderedForChildNote(
8064
- split2.yamlText,
8065
- migrationsKey,
8066
- wikilinkStringKeys
8067
- ),
8068
- body: split2.body
8069
- };
8070
- }
8071
- function readOrderedFromMarkdown(markdown, migrationsKey = DEFAULT_MIGRATIONS_KEY) {
7862
+ function readOrderedFromMarkdown(markdown, wikilinkStringKeys = /* @__PURE__ */ new Set()) {
8072
7863
  const split2 = splitFrontmatter(markdown);
8073
7864
  if (!split2) {
8074
7865
  return { ordered: [], body: markdown };
8075
7866
  }
8076
7867
  return {
8077
- ordered: parseYamlBlockToOrdered(split2.yamlText, migrationsKey),
7868
+ ordered: parseYamlBlockToOrdered(split2.yamlText, wikilinkStringKeys),
8078
7869
  body: split2.body
8079
7870
  };
8080
7871
  }
@@ -8149,21 +7940,9 @@ function fmReorder(ordered, keysInOrder) {
8149
7940
  }
8150
7941
  return out;
8151
7942
  }
8152
- async function writeFrontmatter(app, file, mutator, migrationsKey = DEFAULT_MIGRATIONS_KEY) {
7943
+ async function writeFrontmatter(app, file, mutator, wikilinkStringKeys = /* @__PURE__ */ new Set()) {
8153
7944
  const text2 = await app.vault.read(file);
8154
- const { ordered: before } = readOrderedFromMarkdown(text2, migrationsKey);
8155
- const after = mutator(before);
8156
- await app.fileManager.processFrontMatter(file, (fm) => {
8157
- applyOrderedFrontmatter(fm, after);
8158
- });
8159
- }
8160
- async function writeChildFrontmatter(app, file, mutator, migrationsKey = DEFAULT_MIGRATIONS_KEY, wikilinkStringKeys = /* @__PURE__ */ new Set(["template"])) {
8161
- const text2 = await app.vault.read(file);
8162
- const { ordered: before } = readOrderedFromMarkdownForChildNote(
8163
- text2,
8164
- migrationsKey,
8165
- wikilinkStringKeys
8166
- );
7945
+ const { ordered: before } = readOrderedFromMarkdown(text2, wikilinkStringKeys);
8167
7946
  const after = mutator(before);
8168
7947
  await app.fileManager.processFrontMatter(file, (fm) => {
8169
7948
  applyOrderedFrontmatter(fm, after);
@@ -8202,16 +7981,7 @@ var DEFAULT_TODAY = "{today}";
8202
7981
  var DEFAULT_SCHEMA = "public";
8203
7982
 
8204
7983
  // src/core/reserved-keys.ts
8205
- function rowReservedKeys(settings) {
8206
- return [
8207
- settings.migrationsProperty,
8208
- "_protected",
8209
- "_extend",
8210
- "_inherits",
8211
- TABLE_KEY,
8212
- COLUMNS_KEY
8213
- ];
8214
- }
7984
+ var TABLE_META_KEYS = [TABLE_KEY, COLUMNS_KEY];
8215
7985
 
8216
7986
  // src/core/validate.ts
8217
7987
  var DATE_RE = /^(\d{4})-(\d{2})-(\d{2})$/;
@@ -8344,7 +8114,7 @@ function validateRow(table, row, options, ctx = {}) {
8344
8114
  const known = /* @__PURE__ */ new Set([
8345
8115
  ...table.columns.map((c) => c.name),
8346
8116
  ...table.untypedFields,
8347
- options.templateProperty,
8117
+ options.tableProperty,
8348
8118
  ...options.extraAllowedKeys ?? []
8349
8119
  ]);
8350
8120
  for (const [k, v] of row) {
@@ -8503,7 +8273,7 @@ var COLUMN_ATTRS = /* @__PURE__ */ new Set([
8503
8273
  "vocabulary",
8504
8274
  "inverse"
8505
8275
  ]);
8506
- var TABLE_ATTRS = /* @__PURE__ */ new Set(["name", "path", "partition", "filename", "archive", "exclude", "description", "aliases"]);
8276
+ var TABLE_ATTRS = /* @__PURE__ */ new Set(["name", "partition", "filename", "archive", "exclude", "description", "aliases"]);
8507
8277
  var COLUMN_NAME_RE = /^[A-Za-z][A-Za-z0-9_-]*$/;
8508
8278
  function isScalarType(t) {
8509
8279
  return typeof t === "string" && SCALAR_COLUMN_TYPES.includes(t);
@@ -8747,43 +8517,17 @@ function parseTableOptions(raw) {
8747
8517
  }
8748
8518
  return out;
8749
8519
  }
8750
- function basenameWithoutMd(path6) {
8751
- const base = path6.split("/").pop() ?? path6;
8752
- return base.replace(/\.md$/i, "");
8753
- }
8754
- var SCHEMA_BASENAME = "_schema";
8755
8520
  var DEFAULT_DATABASE_FOLDER = "Database";
8756
- function schemaOfTable(schemaPath, databaseFolder = DEFAULT_DATABASE_FOLDER) {
8757
- const root2 = databaseFolder.replace(/^\/+|\/+$/g, "");
8758
- if (!schemaPath.startsWith(`${root2}/`)) return DEFAULT_SCHEMA;
8759
- const rel = schemaPath.slice(root2.length + 1).split("/");
8760
- return rel.length >= 3 && !rel[0].startsWith("_") ? rel[0] : DEFAULT_SCHEMA;
8761
- }
8762
- function isDatabaseTable(schemaPath, databaseFolder = DEFAULT_DATABASE_FOLDER) {
8763
- const root2 = databaseFolder.replace(/^\/+|\/+$/g, "");
8764
- if (!schemaPath.startsWith(`${root2}/`)) return false;
8765
- const rel = schemaPath.slice(root2.length + 1).split("/");
8766
- return rel[rel.length - 1] === `${SCHEMA_BASENAME}.md` && (rel.length === 2 || rel.length === 3) && !rel[0].startsWith("_");
8767
- }
8768
- function tableLayout(schemaPath, options, databaseFolder = DEFAULT_DATABASE_FOLDER) {
8769
- const cut = schemaPath.lastIndexOf("/");
8770
- const folder = cut < 0 ? "" : schemaPath.slice(0, cut);
8771
- const inDatabase = isDatabaseTable(schemaPath, databaseFolder);
8772
- const join = (a, b) => a === "" ? b : `${a}/${b}`;
8773
- let rowPath;
8774
- if (options.path) rowPath = options.path;
8775
- else if (inDatabase) rowPath = options.partition ? join(folder, options.partition) : folder;
8776
- let archive;
8777
- if (options.archive) archive = inDatabase && !options.archive.includes("/") ? join(folder, options.archive) : options.archive;
8778
- else archive = join(folder, inDatabase ? DEFAULT_ARCHIVE_FOLDER : "_archivio");
8779
- return { folder, inDatabase, ...rowPath !== void 0 ? { rowPath } : {}, archive };
8780
- }
8781
8521
  var DEFAULT_ARCHIVE_FOLDER = "_archive";
8782
- function defaultTableName(schemaPath) {
8783
- const base = basenameWithoutMd(schemaPath);
8784
- if (base !== SCHEMA_BASENAME) return base;
8785
- const parts = schemaPath.split("/");
8786
- return parts.length >= 2 ? parts[parts.length - 2] : base;
8522
+ function catalogLayout(root, ref2, options) {
8523
+ const folder = `${root}/${ref2.catalog}/${ref2.schema}/${ref2.table}`;
8524
+ const archiveName = options.archive && !options.archive.includes("/") ? options.archive : DEFAULT_ARCHIVE_FOLDER;
8525
+ return {
8526
+ folder,
8527
+ inDatabase: true,
8528
+ rowPath: options.partition ? `${folder}/${options.partition}` : folder,
8529
+ archive: options.archive && options.archive.includes("/") ? options.archive : `${folder}/${archiveName}`
8530
+ };
8787
8531
  }
8788
8532
  function checkGeneratedColumns(specs, known) {
8789
8533
  specs.forEach((c, index) => {
@@ -8811,8 +8555,8 @@ function checkGeneratedColumns(specs, known) {
8811
8555
  }
8812
8556
  });
8813
8557
  }
8814
- function tableDefinitionFromOrdered(schemaPath, ordered, settings) {
8815
- const reserved = /* @__PURE__ */ new Set([...rowReservedKeys(settings), settings.templateProperty]);
8558
+ function tableDefinitionFromOrdered(ref2, schemaPath, ordered, settings) {
8559
+ const reserved = new Set(TABLE_META_KEYS);
8816
8560
  const options = parseTableOptions(fmGet(ordered, TABLE_KEY));
8817
8561
  const specs = parseColumns(fmGet(ordered, COLUMNS_KEY), reserved);
8818
8562
  const fieldKeys = ordered.map(([k]) => k).filter((k) => !reserved.has(k));
@@ -8822,9 +8566,10 @@ function tableDefinitionFromOrdered(schemaPath, ordered, settings) {
8822
8566
  checkGeneratedColumns(specs, /* @__PURE__ */ new Set([...columnNames, ...fieldKeys]));
8823
8567
  return {
8824
8568
  schemaPath,
8825
- name: options.name ?? defaultTableName(schemaPath),
8826
- schema: schemaOfTable(schemaPath, settings.databaseFolder),
8827
- layout: tableLayout(schemaPath, options, settings.databaseFolder),
8569
+ name: ref2.table,
8570
+ schema: ref2.schema,
8571
+ catalog: ref2.catalog,
8572
+ layout: catalogLayout(settings.databaseFolder.replace(/^\/+|\/+$/g, ""), ref2, options),
8828
8573
  options,
8829
8574
  columns,
8830
8575
  untypedFields: fieldKeys.filter((k) => !columnNames.has(k))
@@ -9052,16 +8797,6 @@ function rowTableFull(model, value) {
9052
8797
  }
9053
8798
  }
9054
8799
  var TABLE_PROPERTY_KEYS = ["partition", "filename", "archive", "exclude"];
9055
- function catalogLayout(root2, ref2, options) {
9056
- const folder = `${root2}/${ref2.catalog}/${ref2.schema}/${ref2.table}`;
9057
- const archiveName = options.archive && !options.archive.includes("/") ? options.archive : "_archive";
9058
- return {
9059
- folder,
9060
- inDatabase: true,
9061
- rowPath: options.partition ? `${folder}/${options.partition}` : folder,
9062
- archive: options.archive && options.archive.includes("/") ? options.archive : `${folder}/${archiveName}`
9063
- };
9064
- }
9065
8800
  function entryToOrdered(ref2, entry, settings, model) {
9066
8801
  const columns = model ? effectiveColumns(model, ref2, entry) : entry.columns.map((c) => withSelf(c, ref2.full));
9067
8802
  const ordered = [[settings.tableProperty, ref2.full]];
@@ -9103,7 +8838,7 @@ function orderedToEntry(ordered, previous, settings, ctx) {
9103
8838
  const options = parseTableOptions(fmGet(ordered, TABLE_KEY));
9104
8839
  const columnsRaw = fmGet(ordered, COLUMNS_KEY) ?? [];
9105
8840
  const columnNames = new Set(columnsRaw.map((c) => String(c.name)));
9106
- const reserved = /* @__PURE__ */ new Set([settings.tableProperty, TABLE_KEY, COLUMNS_KEY, settings.migrationsProperty, "_protected", "_extend", "_inherits"]);
8841
+ const reserved = /* @__PURE__ */ new Set([settings.tableProperty, ...TABLE_META_KEYS]);
9107
8842
  const dense = /* @__PURE__ */ new Set();
9108
8843
  const defaults = {};
9109
8844
  for (const [k, v] of ordered) {
@@ -9314,11 +9049,11 @@ async function readHashed(app, f) {
9314
9049
  e.hash ??= contentHash(e.content);
9315
9050
  return { content: e.content, hash: e.hash };
9316
9051
  }
9317
- async function readParsed(app, f, key, parse3) {
9052
+ async function readParsed(app, f, key, parse2) {
9318
9053
  const e = await entryFor(app, f);
9319
9054
  e.parsed ??= /* @__PURE__ */ new Map();
9320
9055
  let p = e.parsed.get(key);
9321
- if (!p) e.parsed.set(key, p = parse3(e.content));
9056
+ if (!p) e.parsed.set(key, p = parse2(e.content));
9322
9057
  return { ordered: p.ordered.map(([k, v]) => [k, v]), body: p.body };
9323
9058
  }
9324
9059
  function invalidateFiles(app, paths) {
@@ -9441,24 +9176,9 @@ async function findInStore(app, settings, id) {
9441
9176
  }
9442
9177
  return entry ? { entry: await unpack(app, settings, entry), undone, path: `${path6}#${id}` } : null;
9443
9178
  }
9444
- var JSON_BLOCK = /```json\n([\s\S]*?)\n```/;
9445
- function parseLegacyNote(text2, path6) {
9446
- const m = text2.match(JSON_BLOCK);
9447
- if (!m) throw new Error(`Journal ${path6} has no JSON block`);
9448
- const entry = JSON.parse(m[1]);
9449
- const { ordered } = readOrderedFromMarkdownForChildNote(text2);
9450
- const undone = ordered.some(([k, v]) => k === "undone" && v === true);
9451
- const by = ordered.find(([k]) => k === "undone_by")?.[1];
9452
- return { entry, undone, ...typeof by === "string" ? { undoneBy: by } : {} };
9453
- }
9454
9179
  async function readJournal(app, settings, migrationId) {
9455
9180
  const hit = await findInStore(app, settings, migrationId);
9456
9181
  if (hit) return hit;
9457
- const f = app.vault.getAbstractFileByPath(`${settings.journalFolder}/${migrationId}.md`);
9458
- if (f != null && "extension" in f) {
9459
- const { entry, undone } = parseLegacyNote(await app.vault.read(f), f.path);
9460
- return { entry, undone, path: f.path };
9461
- }
9462
9182
  throw new MigrationNotFoundError(migrationId);
9463
9183
  }
9464
9184
  async function markUndone(app, settings, migrationId, undoneBy, now) {
@@ -9531,41 +9251,6 @@ async function compactJournal(app, settings, now = /* @__PURE__ */ new Date()) {
9531
9251
  }
9532
9252
  return res;
9533
9253
  }
9534
- async function importLegacyJournal(app, settings, opts = {}) {
9535
- const res = { imported: 0, skipped: 0, removed: 0, errors: [] };
9536
- const folder = settings.journalFolder.replace(/^\/+|\/+$/g, "");
9537
- if (!folder) return res;
9538
- const notes = app.vault.getMarkdownFiles().filter((f) => f.path.startsWith(`${folder}/`) && !f.path.slice(folder.length + 1).includes("/")).sort((a, b) => a.path.localeCompare(b.path));
9539
- const known = /* @__PURE__ */ new Map();
9540
- const done = [];
9541
- for (const f of notes) {
9542
- try {
9543
- const { entry, undone, undoneBy } = parseLegacyNote(await app.vault.read(f), f.path);
9544
- const file = journalFileFor(settings, entry.migration_id);
9545
- if (!known.has(file)) known.set(file, await idsIn(app, file));
9546
- if (known.get(file).has(entry.migration_id)) {
9547
- res.skipped++;
9548
- } else {
9549
- await appendEntry(app, settings, entry);
9550
- if (undone) await markUndone(app, settings, entry.migration_id, undoneBy ?? "", new Date(entry.executed_at));
9551
- known.get(file).add(entry.migration_id);
9552
- res.imported++;
9553
- }
9554
- done.push(f);
9555
- } catch (e) {
9556
- res.errors.push({ path: f.path, error: e instanceof Error ? e.message : String(e) });
9557
- }
9558
- }
9559
- if (opts.remove !== false) {
9560
- for (const f of done) {
9561
- await app.vault.delete(f);
9562
- res.removed++;
9563
- }
9564
- const dir = app.vault.getAbstractFileByPath(folder);
9565
- if (dir && Array.isArray(dir.children) && dir.children.length === 0) await app.vault.delete(dir, true);
9566
- }
9567
- return res;
9568
- }
9569
9254
 
9570
9255
  // src/core/changeset.ts
9571
9256
  function bodyChanges(e) {
@@ -9657,22 +9342,8 @@ async function ensureFolder(app, folder) {
9657
9342
  await ensureFolder(app, parentFolder(folder));
9658
9343
  await app.vault.createFolder(folder);
9659
9344
  }
9660
- async function readOrderedFor(app, file, strict, settings) {
9661
- const text2 = await app.vault.read(file);
9662
- return strict ? readOrderedFromMarkdown(text2, settings.migrationsProperty).ordered : readOrderedFromMarkdownForChildNote(text2, settings.migrationsProperty, /* @__PURE__ */ new Set([settings.templateProperty])).ordered;
9663
- }
9664
- async function writeOrderedDiff(app, file, strict, settings, mutate) {
9665
- if (strict) {
9666
- await writeFrontmatter(app, file, mutate, settings.migrationsProperty);
9667
- } else {
9668
- await writeChildFrontmatter(
9669
- app,
9670
- file,
9671
- mutate,
9672
- settings.migrationsProperty,
9673
- /* @__PURE__ */ new Set([settings.templateProperty])
9674
- );
9675
- }
9345
+ async function readOrderedFor(app, file) {
9346
+ return readOrderedFromMarkdown(await app.vault.read(file)).ordered;
9676
9347
  }
9677
9348
  async function moveFile(app, from, to) {
9678
9349
  if (from.startsWith(".")) return storeRename(app, from, to);
@@ -9733,12 +9404,11 @@ async function applyChangeSet(app, settings, cs, now = /* @__PURE__ */ new Date(
9733
9404
  const order = e.after.map(([k]) => k);
9734
9405
  const fmChanged = d.set.length > 0 || d.remove.length > 0 || !same(e.before.map(([k]) => k), order);
9735
9406
  if (fmChanged) {
9736
- await writeOrderedDiff(app, file, e.strict, settings, (fm) => applyDiff(fm, d.set, d.remove, order));
9407
+ await writeFrontmatter(app, file, (fm) => applyDiff(fm, d.set, d.remove, order));
9737
9408
  }
9738
9409
  if (bodyChanges(e)) await writeBody(app, file, e.bodyBefore, e.bodyAfter);
9739
9410
  rows.push({
9740
9411
  path: e.path,
9741
- strict: e.strict,
9742
9412
  before: d.beforeValues,
9743
9413
  before_absent: d.beforeAbsent,
9744
9414
  before_order: e.before.map(([k]) => k),
@@ -9830,7 +9500,7 @@ async function undoMigration(app, settings, migrationId, now = /* @__PURE__ */ n
9830
9500
  conflicts.push({ path: r.path, message: "note no longer exists" });
9831
9501
  continue;
9832
9502
  }
9833
- const cur = new Map(await readOrderedFor(app, f, r.strict, settings));
9503
+ const cur = new Map(await readOrderedFor(app, f));
9834
9504
  for (const [k, v] of Object.entries(r.after)) {
9835
9505
  if (!cur.has(k) || !same(cur.get(k), v)) {
9836
9506
  conflicts.push({ path: r.path, message: `"${k}" changed since the operation` });
@@ -9875,18 +9545,15 @@ async function undoMigration(app, settings, migrationId, now = /* @__PURE__ */ n
9875
9545
  for (const r of entry.rows) {
9876
9546
  const f = fileOrNull(app, currentPath(r.path));
9877
9547
  if (Object.keys(r.after).length > 0 || r.after_absent.length > 0 || Object.keys(r.before).length > 0) {
9878
- await writeOrderedDiff(
9548
+ await writeFrontmatter(
9879
9549
  app,
9880
9550
  f,
9881
- r.strict,
9882
- settings,
9883
9551
  (fm) => applyDiff(fm, Object.entries(r.before), r.before_absent, r.before_order)
9884
9552
  );
9885
9553
  }
9886
9554
  if (r.body_after !== void 0) await writeBody(app, f, r.body_after, r.body_before);
9887
9555
  undoRows.push({
9888
9556
  path: currentPath(r.path),
9889
- strict: r.strict,
9890
9557
  before: r.after,
9891
9558
  before_absent: r.after_absent,
9892
9559
  before_order: [],
@@ -10104,14 +9771,14 @@ async function readCurrentStates(app, settings, model, touched, only) {
10104
9771
  const fm = app.metadataCache.getFileCache(f)?.frontmatter;
10105
9772
  if (fm && fm[settings.tableProperty] != null) candidates.add(f.path);
10106
9773
  }
10107
- const key = `member-tolerant|${settings.migrationsProperty}`;
9774
+ const key = "member-tolerant";
10108
9775
  const resolved = /* @__PURE__ */ new Map();
10109
9776
  for (const path6 of [...candidates].sort()) {
10110
9777
  const file = app.vault.getAbstractFileByPath(path6);
10111
9778
  if (file == null || !("extension" in file)) continue;
10112
9779
  let raw;
10113
9780
  try {
10114
- const { ordered } = await readParsed(app, file, key, (c) => readOrderedFromMarkdownForChildNote(c, settings.migrationsProperty));
9781
+ const { ordered } = await readParsed(app, file, key, (c) => readOrderedFromMarkdown(c));
10115
9782
  raw = fmGet(ordered, settings.tableProperty);
10116
9783
  } catch {
10117
9784
  continue;
@@ -10307,13 +9974,13 @@ function linkTo(app, path6, source) {
10307
9974
  return `[[${clash ? path6.replace(/\.md$/i, "") : base}]]`;
10308
9975
  }
10309
9976
  function rowKey(settings) {
10310
- return `row|${settings.migrationsProperty}|${settings.templateProperty}|${settings.tableProperty}`;
9977
+ return `row|${settings.tableProperty}`;
10311
9978
  }
10312
9979
  async function readRowFrontmatter(app, settings, path6) {
10313
9980
  const f = app.vault.getAbstractFileByPath(path6);
10314
9981
  if (!f || !("extension" in f)) return null;
10315
- const keep = /* @__PURE__ */ new Set([settings.templateProperty, settings.tableProperty]);
10316
- const { ordered } = await readParsed(app, f, rowKey(settings), (t) => readOrderedFromMarkdownForChildNote(t, settings.migrationsProperty, keep));
9982
+ const keep = /* @__PURE__ */ new Set([settings.tableProperty]);
9983
+ const { ordered } = await readParsed(app, f, rowKey(settings), (t) => readOrderedFromMarkdown(t, keep));
10317
9984
  return ordered;
10318
9985
  }
10319
9986
  function inverseTargets(app, specs, ordered, source) {
@@ -10418,8 +10085,8 @@ async function inverseEditsFor(app, settings, rows, finalPath) {
10418
10085
  return planInverse(app, settings, ms.model, changes, { known, finalPath });
10419
10086
  }
10420
10087
  function withFrontmatter(content, ordered, settings) {
10421
- const keep = /* @__PURE__ */ new Set([settings.templateProperty, settings.tableProperty]);
10422
- const { body } = readOrderedFromMarkdownForChildNote(content, settings.migrationsProperty, keep);
10088
+ const keep = /* @__PURE__ */ new Set([settings.tableProperty]);
10089
+ const { body } = readOrderedFromMarkdown(content, keep);
10423
10090
  return buildMarkdownWithFrontmatter(ordered, body);
10424
10091
  }
10425
10092
  var InverseWatcher = class {
@@ -10521,14 +10188,6 @@ var TableNotFoundError = class extends Error {
10521
10188
  this.name = "TableNotFoundError";
10522
10189
  }
10523
10190
  };
10524
- var AmbiguousTableError = class extends Error {
10525
- constructor(ref2, paths) {
10526
- super(`Table name "${ref2}" matches several tables (${paths.join(", ")}); use schema.table`);
10527
- this.ref = ref2;
10528
- this.paths = paths;
10529
- this.name = "AmbiguousTableError";
10530
- }
10531
- };
10532
10191
  function frontmatterOf(app, file) {
10533
10192
  const fm = app.metadataCache.getFileCache(file)?.frontmatter;
10534
10193
  return fm && typeof fm === "object" ? fm : void 0;
@@ -10566,8 +10225,8 @@ function vocabularyOf(app, settings, table) {
10566
10225
  }
10567
10226
  const hit = entry.sets.get(table);
10568
10227
  if (hit) return hit;
10569
- const ms = cachedMetastore(app, { databaseFolder: settings.databaseFolder ?? DEFAULT_DATABASE_FOLDER });
10570
- if (!ms || !settings.tableProperty) return null;
10228
+ const ms = cachedMetastore(app, { databaseFolder: settings.databaseFolder });
10229
+ if (!ms) return null;
10571
10230
  const names = /* @__PURE__ */ new Set();
10572
10231
  for (const f of app.vault.getMarkdownFiles()) {
10573
10232
  const fm = frontmatterOf(app, f);
@@ -10586,8 +10245,8 @@ function validationContextFor(app, settings, sourcePath) {
10586
10245
  tableOfPath: (path6) => {
10587
10246
  const f = markdownFile(app, path6);
10588
10247
  if (!f) return null;
10589
- const ms = cachedMetastore(app, { databaseFolder: settings.databaseFolder ?? DEFAULT_DATABASE_FOLDER });
10590
- const full = ms && settings.tableProperty ? rowTableFull(ms, frontmatterOf(app, f)?.[settings.tableProperty]) : null;
10248
+ const ms = cachedMetastore(app, { databaseFolder: settings.databaseFolder });
10249
+ const full = ms ? rowTableFull(ms, frontmatterOf(app, f)?.[settings.tableProperty]) : null;
10591
10250
  return full ?? null;
10592
10251
  }
10593
10252
  };
@@ -10651,6 +10310,25 @@ function resolveDateTokens(where, tz, now) {
10651
10310
  const walk = (v) => Array.isArray(v) ? v.map(walk) : v && typeof v === "object" ? Object.fromEntries(Object.entries(v).map(([k, x]) => [k, walk(x)])) : resolveDateToken(v, tz, now);
10652
10311
  return walk(where);
10653
10312
  }
10313
+ function wallClock(now, tz) {
10314
+ const parts = new Intl.DateTimeFormat("en-CA", {
10315
+ timeZone: tz || "UTC",
10316
+ year: "numeric",
10317
+ month: "2-digit",
10318
+ day: "2-digit",
10319
+ hour: "2-digit",
10320
+ minute: "2-digit",
10321
+ second: "2-digit",
10322
+ hourCycle: "h23"
10323
+ }).formatToParts(now);
10324
+ const g = (type) => parts.find((p) => p.type === type)?.value ?? "00";
10325
+ return `${g("year")}-${g("month")}-${g("day")}T${g("hour")}:${g("minute")}:${g("second")}`;
10326
+ }
10327
+ function resolveDefault(value, now, tz) {
10328
+ if (value === DEFAULT_NOW) return tz === "" ? `${now.toISOString().slice(0, 19)}Z` : normalizeDatetime(wallClock(now, tz), tz);
10329
+ if (value === DEFAULT_TODAY) return wallClock(now, tz).slice(0, 10);
10330
+ return value;
10331
+ }
10654
10332
 
10655
10333
  // src/core/database.ts
10656
10334
  var DatabaseConfigError = class extends Error {
@@ -10734,7 +10412,7 @@ async function writeDatabaseConfig(app, settings, cfg) {
10734
10412
  primeMetastore(app, settings, after);
10735
10413
  }
10736
10414
  async function describeDatabase(app, settings) {
10737
- const root2 = databaseRoot(settings);
10415
+ const root = databaseRoot(settings);
10738
10416
  const config = await readDatabaseConfig(app, settings);
10739
10417
  const ms = await loadMetastore(app, settings);
10740
10418
  const catalogs = [];
@@ -10768,7 +10446,7 @@ async function describeDatabase(app, settings) {
10768
10446
  }
10769
10447
  }
10770
10448
  return {
10771
- root: root2,
10449
+ root,
10772
10450
  metastore: metastorePath(settings),
10773
10451
  journal: storePath(settings, "journal"),
10774
10452
  config,
@@ -10831,9 +10509,6 @@ async function configureDatabase(app, settings, input, saveSettings) {
10831
10509
  }
10832
10510
  }
10833
10511
  settings.databaseFolder = newRoot;
10834
- if (settings.journalFolder === oldRoot || settings.journalFolder.startsWith(`${oldRoot}/`)) {
10835
- settings.journalFolder = newRoot + settings.journalFolder.slice(oldRoot.length);
10836
- }
10837
10512
  await saveSettings();
10838
10513
  }
10839
10514
  }
@@ -10851,15 +10526,8 @@ var OperationInputError = class extends Error {
10851
10526
  function catalogLoadedTable(settings, ms, ref2) {
10852
10527
  const entry = ms.model.catalogs[ref2.catalog].schemas[ref2.schema].tables[ref2.table];
10853
10528
  const ordered = entryToOrdered(ref2, entry, settings, ms.model);
10854
- const base = tableDefinitionFromOrdered(catalogTablePath(settings, ref2.full), ordered, settings);
10855
- const def = {
10856
- ...base,
10857
- name: ref2.table,
10858
- schema: ref2.schema,
10859
- catalog: ref2.catalog,
10860
- layout: catalogLayout(settings.databaseFolder.replace(/^\/+|\/+$/g, ""), ref2, base.options)
10861
- };
10862
- return { file: ms.file, ordered, def, protectedKeys: /* @__PURE__ */ new Set(), catalog: { ref: ref2, entry, text: ms.text, model: ms.model } };
10529
+ const def = tableDefinitionFromOrdered(ref2, catalogTablePath(settings, ref2.full), ordered, settings);
10530
+ return { file: ms.file, ordered, def, catalog: { ref: ref2, entry, text: ms.text, model: ms.model } };
10863
10531
  }
10864
10532
  var INDEX_RETRY = { attempts: 8, delayMs: 150 };
10865
10533
  async function loadTable(app, settings, ref2) {
@@ -10871,23 +10539,20 @@ async function loadTable(app, settings, ref2) {
10871
10539
  await new Promise((r) => setTimeout(r, INDEX_RETRY.delayMs));
10872
10540
  }
10873
10541
  }
10874
- function memberKey(settings, t) {
10875
- return settings.tableProperty;
10876
- }
10877
10542
  function memberEntry(settings, t) {
10878
10543
  return [settings.tableProperty, t.catalog.ref.full];
10879
10544
  }
10880
10545
  async function loadRows(app, settings, t) {
10881
10546
  const out = [];
10882
10547
  const files = catalogRowFiles(app, settings, t.catalog.ref.full, t.def);
10883
- const key = `row|${settings.migrationsProperty}|${settings.templateProperty}|${settings.tableProperty}`;
10884
- const keep = /* @__PURE__ */ new Set([settings.templateProperty, settings.tableProperty]);
10548
+ const key = `row|${settings.tableProperty}`;
10549
+ const keep = /* @__PURE__ */ new Set([settings.tableProperty]);
10885
10550
  for (const f of files) {
10886
10551
  const { ordered, body } = await readParsed(
10887
10552
  app,
10888
10553
  f,
10889
10554
  key,
10890
- (text2) => readOrderedFromMarkdownForChildNote(text2, settings.migrationsProperty, keep)
10555
+ (text2) => readOrderedFromMarkdown(text2, keep)
10891
10556
  );
10892
10557
  out.push({ file: f, ordered, body });
10893
10558
  }
@@ -10916,12 +10581,7 @@ function uniqueViolations(columns, rows) {
10916
10581
  }
10917
10582
  return [...byPath.entries()].map(([path6, violations]) => ({ path: path6, violations }));
10918
10583
  }
10919
- function metaKeys(settings) {
10920
- return new Set(rowReservedKeys(settings));
10921
- }
10922
- function reservedNames(settings) {
10923
- return /* @__PURE__ */ new Set([...rowReservedKeys(settings), settings.templateProperty]);
10924
- }
10584
+ var META_KEYS = new Set(TABLE_META_KEYS);
10925
10585
  function serializeColumn(c) {
10926
10586
  const out = { name: c.name, type: c.type };
10927
10587
  if (c.items !== void 0) out.items = c.items;
@@ -10949,7 +10609,7 @@ function serializeColumn(c) {
10949
10609
  }
10950
10610
  function serializeOptions(o) {
10951
10611
  const entry = {};
10952
- for (const k of ["name", "description", "path", "partition", "filename", "archive"]) {
10612
+ for (const k of ["name", "description", "partition", "filename", "archive"]) {
10953
10613
  if (o[k] !== void 0) entry[k] = o[k];
10954
10614
  }
10955
10615
  if (o.aliases && o.aliases.length > 0) entry.aliases = [...o.aliases];
@@ -11047,11 +10707,11 @@ async function finish(app, settings, cs, conflicts, violations, opts) {
11047
10707
  var INVERSE_OPS = /* @__PURE__ */ new Set(["insert_row", "update_rows", "merge_rows", "adopt_rows", "move_rows", "recompute"]);
11048
10708
  async function addInverseEdits(app, settings, cs, conflicts) {
11049
10709
  if (cs.skipInverse || !INVERSE_OPS.has(cs.op)) return;
11050
- const keep = /* @__PURE__ */ new Set([settings.templateProperty, settings.tableProperty]);
10710
+ const keep = /* @__PURE__ */ new Set([settings.tableProperty]);
11051
10711
  const created = new Map(cs.creates.map((c) => [c.path, c]));
11052
10712
  const rows = [
11053
- ...cs.edits.filter((e) => !e.strict).map((e) => ({ path: e.path, before: e.before, after: e.after })),
11054
- ...cs.creates.map((c) => ({ path: c.path, before: [], after: readOrderedFromMarkdownForChildNote(c.content, settings.migrationsProperty, keep).ordered }))
10713
+ ...cs.edits.map((e) => ({ path: e.path, before: e.before, after: e.after })),
10714
+ ...cs.creates.map((c) => ({ path: c.path, before: [], after: readOrderedFromMarkdown(c.content, keep).ordered }))
11055
10715
  ];
11056
10716
  const moved = new Map(cs.moves.map((m) => [m.from, m.to]));
11057
10717
  const plan = await inverseEditsFor(app, settings, rows, (p) => moved.get(p) ?? p);
@@ -11062,7 +10722,7 @@ async function addInverseEdits(app, settings, cs, conflicts) {
11062
10722
  const create = created.get(path6);
11063
10723
  if (own) own.after = w.after;
11064
10724
  else if (create) create.content = withFrontmatter(create.content, w.after, settings);
11065
- else cs.edits.push({ path: path6, strict: false, before: w.before, after: w.after });
10725
+ else cs.edits.push({ path: path6, before: w.before, after: w.after });
11066
10726
  }
11067
10727
  }
11068
10728
  var DELTA_OPERATIONS = {
@@ -11151,7 +10811,7 @@ function addSchemaChange(cs, t, after, settings, target) {
11151
10811
  return !prev || prev.ref !== c.ref || prev.hierarchy !== c.hierarchy || prev.type !== c.type || prev.items !== c.items || prev.vocabulary !== c.vocabulary;
11152
10812
  });
11153
10813
  checkColumnRefs(t.catalog.model, ref2.full, touched, ref2.full);
11154
- def = tableDefinitionFromOrdered(catalogTablePath(settings, ref2.full), entryToOrdered(ref2, entry, settings, t.catalog.model), settings);
10814
+ def = tableDefinitionFromOrdered(ref2, catalogTablePath(settings, ref2.full), entryToOrdered(ref2, entry, settings, t.catalog.model), settings);
11155
10815
  } catch (e) {
11156
10816
  if (e instanceof MetastoreError) throw new OperationInputError(e.message);
11157
10817
  throw e;
@@ -11247,7 +10907,7 @@ async function createTableImpl(app, settings, input, opts = {}) {
11247
10907
  }
11248
10908
  input = { ...input, columns: [{ ...SYSTEM_ID_SPEC, dense: true }, ...input.columns.filter((c) => c.name !== SYSTEM_ID_COLUMN)] };
11249
10909
  }
11250
- const reserved = reservedNames(settings);
10910
+ const reserved = META_KEYS;
11251
10911
  const conflicts = [];
11252
10912
  const columns = input.columns.map((raw, i) => {
11253
10913
  const { dense: _dense, ...spec } = raw;
@@ -11273,10 +10933,11 @@ async function createTableImpl(app, settings, input, opts = {}) {
11273
10933
  throw new OperationInputError(`"time_column" must be a date or datetime column of the table`);
11274
10934
  }
11275
10935
  if (cfg.default_partition !== "") extra.partition = `{${tc.name}:${cfg.default_partition}}`;
11276
- extra.filename = `{${tc.name}:${cfg.filename}}`;
10936
+ const format = tc.type === "date" ? cfg.filename.replace(/\s*(\[[^\]]*\])?\s*[Hh]{1,2}.*$/, "") || "YYYY-MM-DD" : cfg.filename;
10937
+ extra.filename = `{${tc.name}:${format}}`;
11277
10938
  }
11278
10939
  const given = { ...input.options ?? {} };
11279
- if (given.path !== void 0) throw new OperationInputError(`database tables take "partition", not "path"`);
10940
+ if ("path" in given) throw new OperationInputError(`database tables take "partition", not "path"`);
11280
10941
  const catOptions = parseTableOptions(serializeOptions({ ...extra, ...given, name: ref2.table }));
11281
10942
  if (!catOptions.filename) {
11282
10943
  throw new OperationInputError(`pass "time_column" or options.filename (e.g. "{name}") so rows get file names`);
@@ -11298,7 +10959,7 @@ async function createTableImpl(app, settings, input, opts = {}) {
11298
10959
  });
11299
10960
  cat = fmSet(cat, TABLE_KEY, serializeOptions(catOptions));
11300
10961
  cat = withColumns(cat, columns);
11301
- tableDefinitionFromOrdered(pseudo, cat, settings);
10962
+ tableDefinitionFromOrdered(ref2, pseudo, cat, settings);
11302
10963
  const entry = orderedToEntry(cat, void 0, settings);
11303
10964
  if (typeof input.body === "string" && input.body.trim() !== "") entry.row_template = input.body;
11304
10965
  checkColumnRefs(model, ref2.full, entry.columns, ref2.full);
@@ -11339,21 +11000,22 @@ function columnExists(t, name) {
11339
11000
  }
11340
11001
  async function addColumnImpl(app, settings, input, opts = {}) {
11341
11002
  const t = await loadTable(app, settings, input.table);
11342
- const reserved = reservedNames(settings);
11003
+ const reserved = META_KEYS;
11343
11004
  const spec = parseColumn(input.column, t.def.columns.length, reserved);
11344
11005
  if (columnExists(t, spec.name)) {
11345
11006
  throw new OperationInputError(`column "${spec.name}" already exists in table "${t.def.name}"`);
11346
11007
  }
11347
11008
  const dense = input.dense === true;
11348
11009
  let after = withColumns(t.ordered, [...t.def.columns, spec]);
11349
- if (dense) after = addFieldBeforeMeta(after, spec.name, spec.default ?? null, metaKeys(settings));
11010
+ if (dense) after = addFieldBeforeMeta(after, spec.name, spec.default ?? null, META_KEYS);
11350
11011
  const cs = emptyChangeSet("add_column", `add column ${spec.name} to ${t.def.name}`, t.file.path);
11351
11012
  addSchemaChange(cs, t, after, settings);
11352
11013
  const violations = [];
11014
+ const fill = resolveDefault(spec.default, /* @__PURE__ */ new Date(), (await readDatabaseConfig(app, settings)).timezone);
11353
11015
  for (const r of await loadRows(app, settings, t)) {
11354
11016
  const cur = fmGet(r.ordered, spec.name);
11355
11017
  const has = r.ordered.some(([k]) => k === spec.name);
11356
- const value = has ? cur : spec.default;
11018
+ const value = has ? cur : fill;
11357
11019
  if (isEmptyValue(value)) {
11358
11020
  if (spec.required) {
11359
11021
  violations.push({
@@ -11367,9 +11029,8 @@ async function addColumnImpl(app, settings, input, opts = {}) {
11367
11029
  if (dense && !has) {
11368
11030
  cs.edits.push({
11369
11031
  path: r.file.path,
11370
- strict: false,
11371
11032
  before: r.ordered,
11372
- after: fmAdd(r.ordered, spec.name, spec.default ?? null)
11033
+ after: fmAdd(r.ordered, spec.name, fill ?? null)
11373
11034
  });
11374
11035
  }
11375
11036
  }
@@ -11382,12 +11043,11 @@ async function renameColumnImpl(app, settings, input, opts = {}) {
11382
11043
  const t = await loadTable(app, settings, input.table);
11383
11044
  const from = input.from;
11384
11045
  const to = assertColumnName(input.to, `"to"`);
11385
- const reserved = reservedNames(settings);
11046
+ const reserved = META_KEYS;
11386
11047
  if (!columnExists(t, from)) throw new OperationInputError(`column "${from}" not found in table "${t.def.name}"`);
11387
11048
  if (reserved.has(to)) throw new OperationInputError(`"${to}" is a reserved key`);
11388
11049
  if (columnExists(t, to)) throw new OperationInputError(`column "${to}" already exists in table "${t.def.name}"`);
11389
11050
  const conflicts = [];
11390
- if (t.protectedKeys.has(from)) conflicts.push({ path: t.file.path, message: `"${from}" is protected` });
11391
11051
  const columns = t.def.columns.map((c) => c.name === from ? { ...c, name: to } : c);
11392
11052
  let after = t.def.columns.some((c) => c.name === from) ? withColumns(t.ordered, columns) : t.ordered;
11393
11053
  after = fmRename(after, from, to);
@@ -11406,7 +11066,7 @@ async function renameColumnImpl(app, settings, input, opts = {}) {
11406
11066
  }
11407
11067
  next = fmDelete(next, to);
11408
11068
  }
11409
- cs.edits.push({ path: r.file.path, strict: false, before: r.ordered, after: fmRename(next, from, to) });
11069
+ cs.edits.push({ path: r.file.path, before: r.ordered, after: fmRename(next, from, to) });
11410
11070
  }
11411
11071
  return finish(app, settings, cs, conflicts, [], opts);
11412
11072
  }
@@ -11427,7 +11087,6 @@ async function renameValueImpl(app, settings, input, opts = {}) {
11427
11087
  }
11428
11088
  const conflicts = [];
11429
11089
  if (values.includes(to)) conflicts.push({ path: t.file.path, message: `"${to}" is already a value of ${col.name}` });
11430
- if (t.protectedKeys.has(col.name)) conflicts.push({ path: t.file.path, message: `"${col.name}" is protected` });
11431
11090
  const spec = {
11432
11091
  ...col,
11433
11092
  values: values.map((v) => v === from ? to : v),
@@ -11444,7 +11103,7 @@ async function renameValueImpl(app, settings, input, opts = {}) {
11444
11103
  if (isEmptyValue(v)) continue;
11445
11104
  const next = swap(v);
11446
11105
  if (JSON.stringify(next) === JSON.stringify(v)) continue;
11447
- cs.edits.push({ path: r.file.path, strict: false, before: r.ordered, after: fmSet(r.ordered, col.name, next) });
11106
+ cs.edits.push({ path: r.file.path, before: r.ordered, after: fmSet(r.ordered, col.name, next) });
11448
11107
  }
11449
11108
  return finish(app, settings, cs, conflicts, [], opts);
11450
11109
  }
@@ -11453,14 +11112,13 @@ async function dropColumnImpl(app, settings, input, opts = {}) {
11453
11112
  const name = input.name;
11454
11113
  if (!columnExists(t, name)) throw new OperationInputError(`column "${name}" not found in table "${t.def.name}"`);
11455
11114
  const conflicts = [];
11456
- if (t.protectedKeys.has(name)) conflicts.push({ path: t.file.path, message: `"${name}" is protected` });
11457
11115
  let after = t.def.columns.some((c) => c.name === name) ? withColumns(t.ordered, t.def.columns.filter((c) => c.name !== name)) : t.ordered;
11458
11116
  after = fmDelete(after, name);
11459
11117
  const cs = emptyChangeSet("drop_column", `drop column ${name} from ${t.def.name}`, t.file.path);
11460
11118
  addSchemaChange(cs, t, after, settings);
11461
11119
  for (const r of await loadRows(app, settings, t)) {
11462
11120
  if (!r.ordered.some(([k]) => k === name)) continue;
11463
- cs.edits.push({ path: r.file.path, strict: false, before: r.ordered, after: fmDelete(r.ordered, name) });
11121
+ cs.edits.push({ path: r.file.path, before: r.ordered, after: fmDelete(r.ordered, name) });
11464
11122
  }
11465
11123
  return finish(app, settings, cs, conflicts, [], opts);
11466
11124
  }
@@ -11478,12 +11136,12 @@ async function alterColumnImpl(app, settings, input, opts = {}) {
11478
11136
  if (v === null) delete merged[k];
11479
11137
  else merged[k] = v;
11480
11138
  }
11481
- const spec = parseColumn(merged, idx, reservedNames(settings));
11139
+ const spec = parseColumn(merged, idx, META_KEYS);
11482
11140
  const columns = t.def.columns.map((c, i) => i === idx ? spec : c);
11483
- const reserved = reservedNames(settings);
11141
+ const reserved = META_KEYS;
11484
11142
  let after = withColumns(t.ordered, columns);
11485
11143
  const makeDense = dense === true && !old.dense;
11486
- if (makeDense) after = addFieldBeforeMeta(after, spec.name, spec.default ?? null, metaKeys(settings));
11144
+ if (makeDense) after = addFieldBeforeMeta(after, spec.name, spec.default ?? null, META_KEYS);
11487
11145
  if (dense === false && old.dense) after = fmDelete(after, spec.name);
11488
11146
  const cs = emptyChangeSet("alter_column", `alter column ${spec.name} in ${t.def.name}`, t.file.path);
11489
11147
  addSchemaChange(cs, t, after, settings);
@@ -11491,12 +11149,13 @@ async function alterColumnImpl(app, settings, input, opts = {}) {
11491
11149
  const widen = old.type === "date" && spec.type === "datetime";
11492
11150
  const tz = widen ? (await readDatabaseConfig(app, settings)).timezone : "";
11493
11151
  const violations = spec.unique ? uniqueViolations([spec], existing.map((r) => ({ path: r.file.path, ordered: r.ordered }))) : [];
11152
+ const fill = makeDense ? resolveDefault(spec.default, /* @__PURE__ */ new Date(), (await readDatabaseConfig(app, settings)).timezone) : void 0;
11494
11153
  for (const r of existing) {
11495
11154
  const has = r.ordered.some(([k]) => k === spec.name);
11496
11155
  let v = fmGet(r.ordered, spec.name);
11497
11156
  if (widen && typeof v === "string" && /^\d{4}-\d{2}-\d{2}$/.test(v)) {
11498
11157
  const cast = normalizeDatetime(`${v}T00:00`, tz);
11499
- cs.edits.push({ path: r.file.path, strict: false, before: r.ordered, after: fmSet(r.ordered, spec.name, cast) });
11158
+ cs.edits.push({ path: r.file.path, before: r.ordered, after: fmSet(r.ordered, spec.name, cast) });
11500
11159
  v = cast;
11501
11160
  }
11502
11161
  if (isEmptyValue(v)) {
@@ -11507,7 +11166,7 @@ async function alterColumnImpl(app, settings, input, opts = {}) {
11507
11166
  violations.push({ path: r.file.path, violations: validateValue(spec, v, validationContextFor(app, settings, r.file.path)) });
11508
11167
  }
11509
11168
  if (makeDense && !has) {
11510
- cs.edits.push({ path: r.file.path, strict: false, before: r.ordered, after: fmAdd(r.ordered, spec.name, spec.default ?? null) });
11169
+ cs.edits.push({ path: r.file.path, before: r.ordered, after: fmAdd(r.ordered, spec.name, fill ?? null) });
11511
11170
  }
11512
11171
  }
11513
11172
  return finish(app, settings, cs, [], violations, opts);
@@ -11669,10 +11328,9 @@ async function loadTableAsOf(app, settings, table, asOf2) {
11669
11328
  const file = ms?.file ?? pseudoFile(metastorePath(settings));
11670
11329
  const t = catalogLoadedTable(settings, { file, text: "", model: modelWith(ref2, state, ms?.model.bases ?? {}) }, ref2);
11671
11330
  const rows = [...state.files.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([path6, f]) => {
11672
- const { ordered, body } = readOrderedFromMarkdownForChildNote(
11331
+ const { ordered, body } = readOrderedFromMarkdown(
11673
11332
  f.content,
11674
- settings.migrationsProperty,
11675
- /* @__PURE__ */ new Set([settings.templateProperty, settings.tableProperty])
11333
+ /* @__PURE__ */ new Set([settings.tableProperty])
11676
11334
  );
11677
11335
  return { file: pseudoFile(path6), ordered, body };
11678
11336
  });
@@ -11714,12 +11372,11 @@ var restoreTable = instrumented("restore_table", restoreTableImpl, (i) => ({
11714
11372
  timestamp: i.timestamp
11715
11373
  }));
11716
11374
  function rowValues(content, settings) {
11717
- const { ordered } = readOrderedFromMarkdownForChildNote(
11375
+ const { ordered } = readOrderedFromMarkdown(
11718
11376
  content,
11719
- settings.migrationsProperty,
11720
- /* @__PURE__ */ new Set([settings.templateProperty, settings.tableProperty])
11377
+ /* @__PURE__ */ new Set([settings.tableProperty])
11721
11378
  );
11722
- return Object.fromEntries(ordered.filter(([k]) => k !== settings.tableProperty && k !== settings.templateProperty));
11379
+ return Object.fromEntries(ordered.filter(([k]) => k !== settings.tableProperty));
11723
11380
  }
11724
11381
  async function tableChanges(app, settings, input) {
11725
11382
  const ref2 = await historyTableName(app, settings, input.table);
@@ -11886,82 +11543,6 @@ function resolveThisTokens(query, host) {
11886
11543
  return walk(query);
11887
11544
  }
11888
11545
 
11889
- // src/core/view-notes.ts
11890
- var VIEW_NOTE_KEY = "view";
11891
- var GENERATED_MARK = "Generated by Datanotes";
11892
- function root(settings) {
11893
- return settings.databaseFolder.replace(/^\/+|\/+$/g, "");
11894
- }
11895
- function viewNotePath(settings, ref2) {
11896
- return `${root(settings)}/${ref2.catalog}/${ref2.schema}/${ref2.table}.md`;
11897
- }
11898
- function viewNoteText(ref2, view) {
11899
- const lines = ["---", `${VIEW_NOTE_KEY}: ${ref2.full}`];
11900
- if (view.aliases && view.aliases.length > 0) {
11901
- lines.push("aliases:", ...view.aliases.map((a) => ` - ${JSON.stringify(a)}`));
11902
- }
11903
- lines.push("---", "");
11904
- if (view.comment) lines.push(...view.comment.split("\n").map((l) => `> ${l}`), "");
11905
- lines.push("```datanotes", `view: ${ref2.full}`, "```", "");
11906
- lines.push(`%% ${GENERATED_MARK} from the view in database.yaml: change the view (create_view with replace, drop_view), not this note. %%`, "");
11907
- return lines.join("\n");
11908
- }
11909
- function viewOfNote(text2) {
11910
- const m = /^---\r?\n([\s\S]*?)\r?\n---/.exec(text2);
11911
- if (!m) return null;
11912
- const line = m[1].split(/\r?\n/).find((l) => l.startsWith(`${VIEW_NOTE_KEY}:`));
11913
- return line ? line.slice(VIEW_NOTE_KEY.length + 1).trim().replace(/^["']|["']$/g, "") || null : null;
11914
- }
11915
- async function viewNoteBlocked(app, settings, ref2) {
11916
- if (settings.viewNotes === false) return null;
11917
- const path6 = viewNotePath(settings, ref2);
11918
- const f = app.vault.getAbstractFileByPath(path6);
11919
- if (f == null) return null;
11920
- if (!("extension" in f)) return path6;
11921
- return viewOfNote(await app.vault.read(f)) === ref2.full ? null : path6;
11922
- }
11923
- async function syncViewNotes(app, settings, model) {
11924
- const out = { created: [], updated: [], removed: [], skipped: [] };
11925
- const ms = model ?? (await loadMetastore(app, settings))?.model ?? null;
11926
- if (!ms) return out;
11927
- const wanted = /* @__PURE__ */ new Map();
11928
- if (settings.viewNotes !== false) {
11929
- for (const { ref: ref2, view } of catalogViews(ms)) wanted.set(viewNotePath(settings, ref2), viewNoteText(ref2, view));
11930
- }
11931
- for (const [path6, text2] of wanted) {
11932
- const f = app.vault.getAbstractFileByPath(path6);
11933
- if (f == null) {
11934
- await ensureFolder(app, parentFolder(path6));
11935
- await app.vault.create(path6, text2);
11936
- out.created.push(path6);
11937
- continue;
11938
- }
11939
- if (!("extension" in f)) {
11940
- out.skipped.push(path6);
11941
- continue;
11942
- }
11943
- const current2 = await app.vault.read(f);
11944
- const expected = viewOfNote(text2);
11945
- if (viewOfNote(current2) !== expected) {
11946
- out.skipped.push(path6);
11947
- continue;
11948
- }
11949
- if (current2 !== text2) {
11950
- await app.vault.process(f, () => text2);
11951
- out.updated.push(path6);
11952
- }
11953
- }
11954
- const depth = root(settings).split("/").length + 3;
11955
- for (const f of app.vault.getMarkdownFiles()) {
11956
- if (wanted.has(f.path) || !f.path.startsWith(`${root(settings)}/`) || f.path.split("/").length !== depth) continue;
11957
- const text2 = await app.vault.read(f);
11958
- if (viewOfNote(text2) == null || !text2.includes(GENERATED_MARK)) continue;
11959
- await trash(app, f);
11960
- out.removed.push(f.path);
11961
- }
11962
- return out;
11963
- }
11964
-
11965
11546
  // src/core/catalog-ops.ts
11966
11547
  var IDENT2 = /^[a-z][a-z0-9_]*$/;
11967
11548
  function ident(kind, value) {
@@ -12063,8 +11644,6 @@ async function createViewImpl(app, settings, input, opts = {}) {
12063
11644
  const conflicts = [];
12064
11645
  if (sch?.tables[ref2.table]) conflicts.push({ path: ref2.full, message: `${ref2.full} is a table` });
12065
11646
  if (sch?.views[ref2.table] && input.replace !== true) conflicts.push({ path: ref2.full, message: `${ref2.full} already exists (pass replace)` });
12066
- const blocked = await viewNoteBlocked(app, settings, ref2);
12067
- if (blocked) conflicts.push({ path: blocked, message: `${blocked} exists and is not this view's note: rename it or choose another view name` });
12068
11647
  if (hasThisTokens(input.query)) viewQueryToSelect(input.query);
12069
11648
  else await select(app, settings, { ...viewQueryToSelect(input.query), limit: 1 });
12070
11649
  for (const [k, v] of Object.entries(input.labels ?? {})) {
@@ -12078,11 +11657,7 @@ async function createViewImpl(app, settings, input, opts = {}) {
12078
11657
  };
12079
11658
  const cs = emptyChangeSet("create_view", `create view ${ref2.full}`, `${metastorePath(settings)}#${ref2.full}`);
12080
11659
  cs.texts.push({ path: metastorePath(settings), before: text2, after: setViewEntry(text2, ref2, view) });
12081
- return withViewNotes(app, settings, await finish(app, settings, cs, conflicts, [], opts));
12082
- }
12083
- async function withViewNotes(app, settings, r) {
12084
- if (r.ok && !r.dryRun) await syncViewNotes(app, settings);
12085
- return r;
11660
+ return finish(app, settings, cs, conflicts, [], opts);
12086
11661
  }
12087
11662
  async function dropViewImpl(app, settings, input, opts = {}) {
12088
11663
  const { text: text2, model } = await metastoreOrEmpty(app, settings);
@@ -12090,7 +11665,7 @@ async function dropViewImpl(app, settings, input, opts = {}) {
12090
11665
  if (!ref2) throw new TableNotFoundError(input.view);
12091
11666
  const cs = emptyChangeSet("drop_view", `drop view ${ref2.full}`, `${metastorePath(settings)}#${ref2.full}`);
12092
11667
  cs.texts.push({ path: metastorePath(settings), before: text2, after: setViewEntry(text2, ref2, null) });
12093
- return withViewNotes(app, settings, await finish(app, settings, cs, [], [], opts));
11668
+ return finish(app, settings, cs, [], [], opts);
12094
11669
  }
12095
11670
  var createView = instrumented("create_view", createViewImpl, (i) => ({ name: i.name, catalog: i.catalog, schema: i.schema }));
12096
11671
  var dropView = instrumented("drop_view", dropViewImpl, (i) => ({ view: i.view }));
@@ -12343,13 +11918,15 @@ async function planInheritedRows(app, settings, model, text2, refs, rewrite, cs)
12343
11918
  checkColumnRefs(model, ref2.full, effectiveColumns(model, ref2, t.catalog.entry).filter((c) => !own.has(String(c.name))), ref2.full);
12344
11919
  const old = await loadTable(app, settings, ref2.full);
12345
11920
  const dense = t.def.columns.filter((c) => c.dense);
11921
+ const now = /* @__PURE__ */ new Date();
11922
+ const tz = (await readDatabaseConfig(app, settings)).timezone;
12346
11923
  for (const r of await loadRows(app, settings, old)) {
12347
11924
  let after = rewrite(r.ordered);
12348
- for (const c of dense) if (!after.some(([k]) => k === c.name)) after = fmSet(after, c.name, c.default ?? null);
11925
+ for (const c of dense) if (!after.some(([k]) => k === c.name)) after = fmSet(after, c.name, resolveDefault(c.default, now, tz) ?? null);
12349
11926
  after = await fillIdentities(app, settings, t, after, r.file.path);
12350
- const v = validateRow(t.def, after, { templateProperty: settings.tableProperty }, validationContextFor(app, settings, r.file.path));
11927
+ const v = validateRow(t.def, after, { tableProperty: settings.tableProperty }, validationContextFor(app, settings, r.file.path));
12351
11928
  if (v.length > 0) violations.push({ path: r.file.path, violations: v });
12352
- if (JSON.stringify(after) !== JSON.stringify(r.ordered)) cs.edits.push({ path: r.file.path, strict: false, before: r.ordered, after });
11929
+ if (JSON.stringify(after) !== JSON.stringify(r.ordered)) cs.edits.push({ path: r.file.path, before: r.ordered, after });
12353
11930
  }
12354
11931
  }
12355
11932
  return violations;
@@ -12604,25 +12181,6 @@ function renderPathTemplate(template, values) {
12604
12181
  return sanitizeFileName(scalarForPath(v));
12605
12182
  });
12606
12183
  }
12607
- function wallClock(now, tz) {
12608
- const parts = new Intl.DateTimeFormat("en-CA", {
12609
- timeZone: tz || "UTC",
12610
- year: "numeric",
12611
- month: "2-digit",
12612
- day: "2-digit",
12613
- hour: "2-digit",
12614
- minute: "2-digit",
12615
- second: "2-digit",
12616
- hourCycle: "h23"
12617
- }).formatToParts(now);
12618
- const g = (type) => parts.find((p) => p.type === type)?.value ?? "00";
12619
- return `${g("year")}-${g("month")}-${g("day")}T${g("hour")}:${g("minute")}:${g("second")}`;
12620
- }
12621
- function resolveDefault(value, now, tz) {
12622
- if (value === DEFAULT_NOW) return tz === "" ? `${now.toISOString().slice(0, 19)}Z` : normalizeDatetime(wallClock(now, tz), tz);
12623
- if (value === DEFAULT_TODAY) return wallClock(now, tz).slice(0, 10);
12624
- return value;
12625
- }
12626
12184
  function computedColumnNames(t) {
12627
12185
  return new Set(t.def.columns.filter((c) => c.generated !== void 0 || c.identity !== void 0).map((c) => c.name));
12628
12186
  }
@@ -12801,7 +12359,7 @@ function knownKeys(t, settings) {
12801
12359
  return /* @__PURE__ */ new Set([
12802
12360
  ...t.def.columns.map((c) => c.name),
12803
12361
  ...t.def.untypedFields,
12804
- memberKey(settings, t),
12362
+ settings.tableProperty,
12805
12363
  "path"
12806
12364
  ]);
12807
12365
  }
@@ -12881,18 +12439,18 @@ async function resolveWithin(app, settings, t, where) {
12881
12439
  const rows = await loadRows(app, settings, target);
12882
12440
  const names = new Set(rows.map((r) => basenameOf(r.file.path)));
12883
12441
  const raw = cond.within;
12884
- let root2 = linkName(raw) ?? (typeof raw === "string" ? basenameOf(raw.trim()) : null);
12885
- if (root2 != null && !names.has(root2)) {
12442
+ let root = linkName(raw) ?? (typeof raw === "string" ? basenameOf(raw.trim()) : null);
12443
+ if (root != null && !names.has(root)) {
12886
12444
  const hit = rows.find((r) => r.ordered.some(([k, v]) => (k === "name" || k === "title") && v === raw));
12887
- root2 = hit ? basenameOf(hit.file.path) : null;
12445
+ root = hit ? basenameOf(hit.file.path) : null;
12888
12446
  }
12889
- if (root2 == null) throw new OperationInputError(`"within": no row of ${spec.ref} named ${JSON.stringify(raw)}`);
12447
+ if (root == null) throw new OperationInputError(`"within": no row of ${spec.ref} named ${JSON.stringify(raw)}`);
12890
12448
  const children = /* @__PURE__ */ new Map();
12891
12449
  for (const r of rows) {
12892
12450
  const p = linkName(fmGet(r.ordered, h.name));
12893
12451
  if (p) children.set(p, [...children.get(p) ?? [], basenameOf(r.file.path)]);
12894
12452
  }
12895
- const subtree = /* @__PURE__ */ new Set([root2]);
12453
+ const subtree = /* @__PURE__ */ new Set([root]);
12896
12454
  for (const n of subtree) for (const c of children.get(n) ?? []) subtree.add(c);
12897
12455
  const { within: _w, ...rest } = cond;
12898
12456
  out ??= { ...where };
@@ -13066,7 +12624,7 @@ async function selectOn(app, settings, input, hist) {
13066
12624
  const tz = (await readDatabaseConfig(app, settings)).timezone;
13067
12625
  const now = /* @__PURE__ */ new Date();
13068
12626
  const get = rowGetter(app, t, settings, tz);
13069
- const hidden2 = /* @__PURE__ */ new Set([settings.templateProperty, settings.tableProperty]);
12627
+ const hidden2 = /* @__PURE__ */ new Set([settings.tableProperty]);
13070
12628
  const specs = new Map(t.def.columns.map((c) => [c.name, c]));
13071
12629
  for (const c of [...input.columns ?? [], ...input.expand ?? []]) {
13072
12630
  if (!known.has(c)) throw new OperationInputError(`unknown column: "${c}"`);
@@ -13209,7 +12767,7 @@ async function checkImpl(app, settings, input) {
13209
12767
  );
13210
12768
  for (const r of rows) {
13211
12769
  const v = [
13212
- ...validateRow(t.def, r.ordered, { templateProperty: memberKey(settings, t) }, validationContextFor(app, settings, r.file.path)),
12770
+ ...validateRow(t.def, r.ordered, { tableProperty: settings.tableProperty }, validationContextFor(app, settings, r.file.path)),
13213
12771
  ...unique.get(r.file.path) ?? [],
13214
12772
  ...constraintViolations(t, settings, r.file.path, r.ordered),
13215
12773
  ...generatedMismatches(t, settings, r)
@@ -13253,11 +12811,12 @@ function rowTemplate(t, values) {
13253
12811
  function planInsert(app, settings, t, input, env) {
13254
12812
  const known = knownKeys(t, settings);
13255
12813
  known.delete("path");
13256
- known.delete(memberKey(settings, t));
12814
+ known.delete(settings.tableProperty);
13257
12815
  for (const k of Object.keys(input.values)) {
13258
12816
  if (!known.has(k)) throw new OperationInputError(`unknown column "${k}" for table "${t.def.name}"`);
13259
12817
  }
13260
12818
  const computed = computedColumnNames(t);
12819
+ for (const c of t.def.columns) if (c.identity === "filename") computed.delete(c.name);
13261
12820
  for (const k of Object.keys(input.values)) {
13262
12821
  if (computed.has(k)) throw new OperationInputError(`"${k}" is a generated column: its value is computed`);
13263
12822
  }
@@ -13286,8 +12845,8 @@ function planInsert(app, settings, t, input, env) {
13286
12845
  const values = new Map(ordered);
13287
12846
  let path6 = input.path;
13288
12847
  if (path6 == null) {
13289
- if (t.def.layout.rowPath === void 0 || !t.def.options.filename) {
13290
- throw new OperationInputError(`table "${t.def.name}" has no _table path/filename; pass "path"`);
12848
+ if (!t.def.options.filename) {
12849
+ throw new OperationInputError(`table "${t.def.name}" has no filename pattern; pass "path"`);
13291
12850
  }
13292
12851
  const base = `${renderPathTemplate(t.def.layout.rowPath, values)}/${renderPathTemplate(t.def.options.filename, values)}`;
13293
12852
  path6 = `${base}.md`;
@@ -13300,7 +12859,7 @@ function planInsert(app, settings, t, input, env) {
13300
12859
  ordered = withIdentity(t, ordered, path6, false, { now, tz });
13301
12860
  ordered = withGenerated(t, settings, ordered, path6);
13302
12861
  const violations = [
13303
- ...validateRow(t.def, ordered, { templateProperty: memberKey(settings, t) }, validationContextFor(app, settings, path6)),
12862
+ ...validateRow(t.def, ordered, { tableProperty: settings.tableProperty }, validationContextFor(app, settings, path6)),
13304
12863
  ...constraintViolations(t, settings, path6, ordered)
13305
12864
  ];
13306
12865
  return { path: path6, ordered, conflicts, violations };
@@ -13368,7 +12927,7 @@ async function mergeRowsImpl(app, settings, input, opts = {}) {
13368
12927
  let after = r.ordered;
13369
12928
  for (const [k, v] of normalized) {
13370
12929
  if (input.on.includes(k)) continue;
13371
- if (!known.has(k) || k === "path" || k === memberKey(settings, t)) throw new OperationInputError(`unknown column "${k}" for table "${t.def.name}"`);
12930
+ if (!known.has(k) || k === "path" || k === settings.tableProperty) throw new OperationInputError(`unknown column "${k}" for table "${t.def.name}"`);
13372
12931
  if (computed.has(k)) throw new OperationInputError(`"${k}" is a generated column: its value is computed`);
13373
12932
  after = fmSet(after, k, v);
13374
12933
  }
@@ -13383,7 +12942,7 @@ async function mergeRowsImpl(app, settings, input, opts = {}) {
13383
12942
  return validateValue(spec, v, ctx);
13384
12943
  });
13385
12944
  violations.push({ path: r.file.path, violations: [...rowViolations, ...constraintViolations(t, settings, r.file.path, after)] });
13386
- cs.edits.push({ path: r.file.path, strict: false, before: r.ordered, after });
12945
+ cs.edits.push({ path: r.file.path, before: r.ordered, after });
13387
12946
  continue;
13388
12947
  }
13389
12948
  if (input.whenNotMatched === "ignore") continue;
@@ -13395,7 +12954,7 @@ async function mergeRowsImpl(app, settings, input, opts = {}) {
13395
12954
  }
13396
12955
  if (t.def.columns.some((c) => c.unique)) {
13397
12956
  const afterByPath = new Map(cs.edits.map((e) => [e.path, e.after]));
13398
- const created = cs.creates.map((c) => ({ path: c.path, ordered: readOrderedFromMarkdownForChildNote(c.content, settings.migrationsProperty, /* @__PURE__ */ new Set([settings.templateProperty, settings.tableProperty])).ordered }));
12957
+ const created = cs.creates.map((c) => ({ path: c.path, ordered: readOrderedFromMarkdown(c.content, /* @__PURE__ */ new Set([settings.tableProperty])).ordered }));
13399
12958
  const touched = /* @__PURE__ */ new Set([...afterByPath.keys(), ...created.map((c) => c.path)]);
13400
12959
  violations.push(
13401
12960
  ...uniqueViolations(t.def.columns, [
@@ -13482,7 +13041,7 @@ async function recomputeImpl(app, settings, input, opts = {}) {
13482
13041
  return isEmptyValue(v) ? [] : validateValue(c, v, ctx);
13483
13042
  })
13484
13043
  });
13485
- cs.edits.push({ path: r.file.path, strict: false, before: r.ordered, after });
13044
+ cs.edits.push({ path: r.file.path, before: r.ordered, after });
13486
13045
  }
13487
13046
  }
13488
13047
  if (cs.edits.length === 0) return { ...emptyResult("recompute", opts.dryRun === true), ok: true };
@@ -13493,19 +13052,17 @@ async function updateRowsImpl(app, settings, input, opts = {}) {
13493
13052
  const t = await loadTable(app, settings, input.table);
13494
13053
  const known = knownKeys(t, settings);
13495
13054
  known.delete("path");
13496
- known.delete(memberKey(settings, t));
13055
+ known.delete(settings.tableProperty);
13497
13056
  const set = input.set ?? {};
13498
13057
  const unset = input.unset ?? [];
13499
13058
  if (Object.keys(set).length === 0 && unset.length === 0 && input.body === void 0) {
13500
13059
  throw new OperationInputError(`nothing to update: pass "set", "unset" or "body"`);
13501
13060
  }
13502
- const reservedOnRows = new Set(rowReservedKeys(settings));
13503
13061
  for (const k of Object.keys(set)) {
13504
13062
  if (!known.has(k)) throw new OperationInputError(`unknown column "${k}" for table "${t.def.name}"`);
13505
13063
  }
13506
13064
  for (const k of unset) {
13507
- if (k === memberKey(settings, t) || k === "path") throw new OperationInputError(`cannot unset "${k}"`);
13508
- void reservedOnRows;
13065
+ if (k === settings.tableProperty || k === "path") throw new OperationInputError(`cannot unset "${k}"`);
13509
13066
  }
13510
13067
  const computed = computedColumnNames(t);
13511
13068
  for (const k of [...Object.keys(set), ...unset]) {
@@ -13524,7 +13081,7 @@ async function updateRowsImpl(app, settings, input, opts = {}) {
13524
13081
  if (input.body !== void 0 && matched.length !== 1) {
13525
13082
  throw new OperationInputError(`"body" updates exactly one row; "where" matched ${matched.length}`);
13526
13083
  }
13527
- const nameTemplate = t.def.layout.rowPath !== void 0 && t.def.options.filename ? `${t.def.layout.rowPath}/${t.def.options.filename}` : null;
13084
+ const nameTemplate = t.def.options.filename ? `${t.def.layout.rowPath}/${t.def.options.filename}` : null;
13528
13085
  const nameCols = new Set([...(nameTemplate ?? "").matchAll(/\{([A-Za-z][A-Za-z0-9_-]*)(?::[^}]+)?\}/g)].map((m) => m[1]));
13529
13086
  const renames = [...Object.keys(set), ...unset].some((k) => nameCols.has(k));
13530
13087
  const movedTo = /* @__PURE__ */ new Set();
@@ -13572,7 +13129,6 @@ async function updateRowsImpl(app, settings, input, opts = {}) {
13572
13129
  violations.push({ path: r.file.path, violations: rowViolations });
13573
13130
  cs.edits.push({
13574
13131
  path: r.file.path,
13575
- strict: false,
13576
13132
  before: r.ordered,
13577
13133
  after,
13578
13134
  ...input.body !== void 0 ? { bodyBefore: r.body, bodyAfter: input.body } : {}
@@ -13673,12 +13229,23 @@ async function deleteRowsImpl(app, settings, input, opts = {}) {
13673
13229
  sources.forEach((s) => referrers.add(s));
13674
13230
  }
13675
13231
  if (policy === "set_null") {
13232
+ const model = cachedMetastore(app, settings);
13676
13233
  for (const src of [...referrers].sort()) {
13677
13234
  const f = app.vault.getAbstractFileByPath(src);
13678
13235
  if (!f || !("extension" in f) || f.extension !== "md") continue;
13679
13236
  const text2 = await app.vault.read(f);
13680
- const before = readOrderedFromMarkdownForChildNote(text2, settings.migrationsProperty, /* @__PURE__ */ new Set([settings.templateProperty])).ordered;
13681
- cs.edits.push({ path: src, strict: false, before, after: clearLinksTo(app, src, before, doomed) });
13237
+ const before = readOrderedFromMarkdown(text2).ordered;
13238
+ const after = clearLinksTo(app, src, before, doomed);
13239
+ const owner = model ? rowTableFull(model, fmGet(after, settings.tableProperty)) : null;
13240
+ const ot = owner ? await loadTable(app, settings, owner) : null;
13241
+ if (ot && !src.startsWith(`${archiveFolder(ot.def)}/`)) {
13242
+ for (const c of ot.def.columns) {
13243
+ if (c.required && !isEmptyValue(fmGet(before, c.name)) && isEmptyValue(fmGet(after, c.name))) {
13244
+ conflicts.push({ path: src, message: `"${c.name}" is required and would be left empty: change or delete this row first, or use on_referenced "ignore"` });
13245
+ }
13246
+ }
13247
+ }
13248
+ cs.edits.push({ path: src, before, after });
13682
13249
  }
13683
13250
  }
13684
13251
  const folder = archiveFolder(t.def);
@@ -13697,7 +13264,7 @@ async function deleteRowsImpl(app, settings, input, opts = {}) {
13697
13264
  }
13698
13265
  function checkRetarget(dst, settings, r) {
13699
13266
  const dstKnown = knownKeys(dst, settings);
13700
- const membership = /* @__PURE__ */ new Set([settings.templateProperty, settings.tableProperty]);
13267
+ const membership = /* @__PURE__ */ new Set([settings.tableProperty]);
13701
13268
  const computed = computedColumnNames(dst);
13702
13269
  for (const [from, to] of Object.entries(r.rename)) {
13703
13270
  if (typeof to !== "string" || !dstKnown.has(to)) {
@@ -13717,7 +13284,7 @@ function checkRetarget(dst, settings, r) {
13717
13284
  }
13718
13285
  async function retargetRows(app, settings, dst, notes, r, cs, opts) {
13719
13286
  const dstKnown = knownKeys(dst, settings);
13720
- const membership = /* @__PURE__ */ new Set([settings.templateProperty, settings.tableProperty]);
13287
+ const membership = /* @__PURE__ */ new Set([settings.tableProperty]);
13721
13288
  const tz = (await readDatabaseConfig(app, settings)).timezone;
13722
13289
  const violations = [];
13723
13290
  const conflicts = [];
@@ -13749,11 +13316,14 @@ async function retargetRows(app, settings, dst, notes, r, cs, opts) {
13749
13316
  after = withGenerated(dst, settings, after, n.path);
13750
13317
  let to = n.path;
13751
13318
  if (r.relocate) {
13752
- if (dst.def.layout.rowPath === void 0 || !dst.def.options.filename) {
13319
+ if (!dst.def.options.filename) {
13753
13320
  throw new OperationInputError(`table "${dst.def.name}" has no filename pattern: cannot relocate rows`);
13754
13321
  }
13755
13322
  try {
13756
13323
  const values = new Map(after);
13324
+ for (const c of dst.def.columns) {
13325
+ if (c.identity === "filename" && isEmptyValue(values.get(c.name))) values.set(c.name, basenameOf(n.path));
13326
+ }
13757
13327
  const base = `${renderPathTemplate(dst.def.layout.rowPath, values)}/${renderPathTemplate(dst.def.options.filename, values)}`;
13758
13328
  to = `${base}.md`;
13759
13329
  for (let k = 2; to !== n.path && (taken.has(to) || app.vault.getAbstractFileByPath(to) != null) && k <= MAX_NAME_SUFFIX; k++) {
@@ -13772,11 +13342,11 @@ async function retargetRows(app, settings, dst, notes, r, cs, opts) {
13772
13342
  violations.push({
13773
13343
  path: n.path,
13774
13344
  violations: [
13775
- ...validateRow(dst.def, after, { templateProperty: memberKey(settings, dst) }, validationContextFor(app, settings, n.path)),
13345
+ ...validateRow(dst.def, after, { tableProperty: settings.tableProperty }, validationContextFor(app, settings, n.path)),
13776
13346
  ...constraintViolations(dst, settings, n.path, after)
13777
13347
  ]
13778
13348
  });
13779
- cs.edits.push({ path: n.path, strict: false, before: n.ordered, after });
13349
+ cs.edits.push({ path: n.path, before: n.ordered, after });
13780
13350
  if (to !== n.path) cs.moves.push({ from: n.path, to });
13781
13351
  }
13782
13352
  if (dst.def.columns.some((c) => c.unique)) {
@@ -13826,10 +13396,9 @@ async function adoptRowsImpl(app, settings, input, opts = {}) {
13826
13396
  for (const p of paths) {
13827
13397
  const f = app.vault.getAbstractFileByPath(p);
13828
13398
  if (f == null || !("extension" in f)) throw new OperationInputError(`note not found: ${p}`);
13829
- const { ordered } = readOrderedFromMarkdownForChildNote(
13399
+ const { ordered } = readOrderedFromMarkdown(
13830
13400
  await app.vault.read(f),
13831
- settings.migrationsProperty,
13832
- /* @__PURE__ */ new Set([settings.templateProperty, settings.tableProperty])
13401
+ /* @__PURE__ */ new Set([settings.tableProperty])
13833
13402
  );
13834
13403
  const owner = model ? rowTableFull(model, fmGet(ordered, settings.tableProperty)) : null;
13835
13404
  if (owner) conflicts.push({ path: p, message: `already a row of ${owner}: use move_rows` });
@@ -13862,8 +13431,7 @@ async function relocateTable(app, settings, t, dest, changes, opts, properties =
13862
13431
  if (v === null) delete merged[k];
13863
13432
  else merged[k] = v;
13864
13433
  }
13865
- const tp = settings.templateProperty;
13866
- const membership = /* @__PURE__ */ new Set([tp, settings.tableProperty]);
13434
+ const membership = /* @__PURE__ */ new Set([settings.tableProperty]);
13867
13435
  let options;
13868
13436
  let layout;
13869
13437
  let member;
@@ -13871,7 +13439,6 @@ async function relocateTable(app, settings, t, dest, changes, opts, properties =
13871
13439
  let cs;
13872
13440
  {
13873
13441
  const ref2 = dest.catalogRef;
13874
- delete merged.path;
13875
13442
  options = parseTableOptions([{ ...merged, name: ref2.table }]);
13876
13443
  layout = catalogLayout(databaseRoot(settings), ref2, options);
13877
13444
  member = (o) => withRowId([[settings.tableProperty, ref2.full], ...o.filter(([k]) => !membership.has(k))]);
@@ -13933,14 +13500,14 @@ async function relocateTable(app, settings, t, dest, changes, opts, properties =
13933
13500
  if (!list2.includes(oldName)) after = fmSet(after, "aliases", [...list2, oldName]);
13934
13501
  }
13935
13502
  if (JSON.stringify(after) !== JSON.stringify(r.ordered)) {
13936
- cs.edits.push({ path: r.path, strict: false, before: r.ordered, after });
13503
+ cs.edits.push({ path: r.path, before: r.ordered, after });
13937
13504
  }
13938
13505
  if (to !== r.path) cs.moves.push({ from: r.path, to });
13939
13506
  };
13940
13507
  const excluded = (p) => (options.exclude ?? []).some((dir) => p.startsWith(`${dir.replace(/\/+$/, "")}/`));
13941
13508
  const rows = (await loadRows(app, settings, t)).filter((r) => !excluded(r.file.path));
13942
13509
  const bases = /* @__PURE__ */ new Map();
13943
- if (layout.rowPath !== void 0 && options.filename) {
13510
+ if (options.filename) {
13944
13511
  for (const r of rows) {
13945
13512
  try {
13946
13513
  const values = new Map(r.ordered);
@@ -13965,14 +13532,14 @@ async function relocateTable(app, settings, t, dest, changes, opts, properties =
13965
13532
  }
13966
13533
  for (const r of rows) {
13967
13534
  const base = bases.get(r.file.path);
13968
- if (layout.rowPath !== void 0 && options.filename && base === void 0) continue;
13535
+ if (options.filename && base === void 0) continue;
13969
13536
  const to = base === void 0 ? r.file.path : base.startsWith("\0") ? base.slice(1) : claim(base, r.file.path);
13970
13537
  relink({ path: r.file.path, ordered: r.ordered }, to);
13971
13538
  }
13972
13539
  const oldArchive = t.def.layout.archive;
13973
13540
  const newArchive = layout.archive;
13974
13541
  for (const f of archivedRowFiles(app, settings, t)) {
13975
- const { ordered } = readOrderedFromMarkdownForChildNote(await app.vault.read(f), settings.migrationsProperty, membership);
13542
+ const { ordered } = readOrderedFromMarkdown(await app.vault.read(f), membership);
13976
13543
  const to = newArchive === oldArchive ? f.path : claim(`${newArchive}/${basenameOf(f.path)}`, f.path);
13977
13544
  relink({ path: f.path, ordered }, to);
13978
13545
  }
@@ -13981,25 +13548,15 @@ async function relocateTable(app, settings, t, dest, changes, opts, properties =
13981
13548
  async function alterTableImpl(app, settings, input, opts = {}) {
13982
13549
  const t = await loadTable(app, settings, input.table);
13983
13550
  const cfg = await readDatabaseConfig(app, settings);
13984
- const schema = assertIdentifier("schema", input.schema ?? (t.def.layout.inDatabase ? t.def.schema : cfg.default_schema));
13551
+ const schema = assertIdentifier("schema", input.schema ?? t.def.schema);
13985
13552
  const name = assertIdentifier("table", input.name ?? t.def.name);
13986
- const catalog = assertIdentifier("catalog", input.catalog ?? t.def.catalog ?? cfg.default_catalog);
13553
+ const catalog = assertIdentifier("catalog", input.catalog ?? t.def.catalog);
13554
+ const changes = { name: null };
13555
+ if (input.partition !== void 0) changes.partition = input.partition ? input.partition : null;
13987
13556
  const cur = t.def.options;
13988
- const changes = { path: null, name: null };
13989
- let partition = input.partition ?? cur.partition;
13990
- if (input.partition === void 0 && cur.path) {
13991
- const own = t.def.layout.folder;
13992
- if (cur.path === own) partition = "";
13993
- else if (cur.path.startsWith(`${own}/`)) partition = cur.path.slice(own.length + 1);
13994
- else {
13995
- const brace = cur.path.indexOf("{");
13996
- partition = brace < 0 ? "" : cur.path.slice(cur.path.lastIndexOf("/", brace) + 1);
13997
- }
13998
- }
13999
- changes.partition = partition ? partition : null;
14000
13557
  if (!cur.archive || cur.archive.includes("/")) {
14001
13558
  const own = t.def.layout.archive;
14002
- changes.archive = t.def.layout.inDatabase && own.startsWith(`${t.def.layout.folder}/`) && !own.slice(t.def.layout.folder.length + 1).includes("/") ? own.slice(t.def.layout.folder.length + 1) : cfg.archive_folder;
13559
+ changes.archive = own.startsWith(`${t.def.layout.folder}/`) && !own.slice(t.def.layout.folder.length + 1).includes("/") ? own.slice(t.def.layout.folder.length + 1) : cfg.archive_folder;
14003
13560
  }
14004
13561
  if (input.filename !== void 0) changes.filename = input.filename;
14005
13562
  if (input.description !== void 0) changes.description = input.description;
@@ -14040,7 +13597,7 @@ async function syncRelations(app, settings, changes, opts = {}) {
14040
13597
  if (plan.edits.size === 0) return null;
14041
13598
  const cs = emptyChangeSet("sync_relations", `mirror links of ${changes.map((c) => c.path).join(", ")}`.slice(0, 200));
14042
13599
  cs.skipInverse = true;
14043
- for (const [path6, w] of plan.edits) cs.edits.push({ path: path6, strict: false, before: w.before, after: w.after });
13600
+ for (const [path6, w] of plan.edits) cs.edits.push({ path: path6, before: w.before, after: w.after });
14044
13601
  return finish(app, settings, cs, plan.conflicts, [], opts);
14045
13602
  }
14046
13603
  async function alignRelationsImpl(app, settings, input, opts = {}) {
@@ -14058,7 +13615,7 @@ async function alignRelationsImpl(app, settings, input, opts = {}) {
14058
13615
  const plan = await planInverse(app, settings, t.catalog.model, changes, { keepSingles: true });
14059
13616
  const cs = emptyChangeSet("align_relations", `align inverse links of ${t.catalog.ref.full}`, t.def.schemaPath);
14060
13617
  cs.skipInverse = true;
14061
- for (const [path6, w] of plan.edits) cs.edits.push({ path: path6, strict: false, before: w.before, after: w.after });
13618
+ for (const [path6, w] of plan.edits) cs.edits.push({ path: path6, before: w.before, after: w.after });
14062
13619
  return finish(app, settings, cs, plan.conflicts, [], opts);
14063
13620
  }
14064
13621
  function alignRelations(app, settings, input, opts = {}) {
@@ -14094,7 +13651,7 @@ async function adoptCreatedNote(app, settings, file) {
14094
13651
  const target = await adoptTargetFor(app, settings, file.path);
14095
13652
  if (!target) return { adopted: false };
14096
13653
  const text2 = await app.vault.read(file);
14097
- const { ordered, body } = readOrderedFromMarkdownForChildNote(text2, settings.migrationsProperty, /* @__PURE__ */ new Set([settings.tableProperty]));
13654
+ const { ordered, body } = readOrderedFromMarkdown(text2, /* @__PURE__ */ new Set([settings.tableProperty]));
14098
13655
  const declared = ordered.find(([k]) => k === settings.tableProperty)?.[1];
14099
13656
  if (declared !== void 0) {
14100
13657
  if (declared !== target.table && !target.table.endsWith(`.${String(declared)}`)) return { adopted: false };
@@ -14110,6 +13667,10 @@ async function adoptCreatedNote(app, settings, file) {
14110
13667
  const present = new Set(ordered.map(([k]) => k));
14111
13668
  const values = Object.fromEntries(Object.entries(target.values).filter(([k]) => !present.has(k)));
14112
13669
  for (const c of (await loadTable(app, settings, target.table)).def.columns) {
13670
+ if (c.generated !== void 0 || c.identity !== void 0) {
13671
+ delete values[c.name];
13672
+ continue;
13673
+ }
14113
13674
  if (c.external_default !== void 0 && !present.has(c.name) && values[c.name] === void 0) values[c.name] = c.external_default;
14114
13675
  }
14115
13676
  const r = await adoptRows(app, settings, { table: target.table, paths: [file.path], perRow: { [file.path]: values }, relocate: false });
@@ -14534,7 +14095,7 @@ function frontmatter(app, f) {
14534
14095
  }
14535
14096
  async function inferTable(app, settings, input) {
14536
14097
  const maxEnum = input.maxEnumValues ?? 12;
14537
- const skip = /* @__PURE__ */ new Set([...rowReservedKeys(settings), settings.tableProperty, settings.templateProperty, settings.migrationsProperty, "id", ...SKIP_KEYS]);
14098
+ const skip = /* @__PURE__ */ new Set([settings.tableProperty, "id", ...SKIP_KEYS]);
14538
14099
  const notes = [];
14539
14100
  if (input.table !== void 0) {
14540
14101
  const t = await loadTable(app, settings, input.table);
@@ -15429,139 +14990,6 @@ var OtlpSink = class {
15429
14990
  }
15430
14991
  };
15431
14992
 
15432
- // src/core/view-block.ts
15433
- var import_yaml3 = __toESM(require_dist(), 1);
15434
- var BLOCK_KEYS = /* @__PURE__ */ new Set(["view", "table", "columns", "where", "order_by", "limit", "join", "group_by", "aggregates", "expand", "labels", "row_link", "chart", "with_table"]);
15435
- function parseChart(raw) {
15436
- if (raw == null || typeof raw !== "object" || Array.isArray(raw)) throw new OperationInputError(`datanotes block: "chart" must be a mapping (type, x, y)`);
15437
- const c = raw;
15438
- for (const k of Object.keys(c)) {
15439
- if (!["type", "x", "y", "targets", "title"].includes(k)) throw new OperationInputError(`datanotes block: unknown chart key "${k}" (allowed: type, x, y, targets, title)`);
15440
- }
15441
- const type = c.type ?? "line";
15442
- if (type !== "line" && type !== "bar") throw new OperationInputError(`datanotes block: chart type must be line or bar`);
15443
- if (typeof c.x !== "string" || !c.x.trim()) throw new OperationInputError(`datanotes block: chart needs "x" (the column along the axis)`);
15444
- const y = typeof c.y === "string" ? [c.y] : Array.isArray(c.y) ? c.y.map(String) : [];
15445
- if (!y.length) throw new OperationInputError(`datanotes block: chart needs "y" (a column or a list of columns)`);
15446
- const targets = {};
15447
- if (c.targets != null) {
15448
- if (typeof c.targets !== "object" || Array.isArray(c.targets)) throw new OperationInputError(`datanotes block: chart "targets" must be a mapping label \u2192 number`);
15449
- for (const [k, v] of Object.entries(c.targets)) {
15450
- const n = Number(v);
15451
- if (!Number.isFinite(n)) throw new OperationInputError(`datanotes block: chart target "${k}" must be a number`);
15452
- targets[k] = n;
15453
- }
15454
- }
15455
- return { type, x: c.x.trim(), y, targets, ...typeof c.title === "string" ? { title: c.title } : {} };
15456
- }
15457
- function parseViewBlock(source) {
15458
- let raw;
15459
- try {
15460
- raw = (0, import_yaml3.parse)(source);
15461
- } catch (e) {
15462
- throw new OperationInputError(`datanotes block: invalid YAML (${e instanceof Error ? e.message : String(e)})`);
15463
- }
15464
- if (raw == null || typeof raw !== "object" || Array.isArray(raw)) {
15465
- throw new OperationInputError(`datanotes block: write "view: <catalog.schema.view>" or a query ("table: \u2026")`);
15466
- }
15467
- const b = raw;
15468
- for (const k of Object.keys(b)) {
15469
- if (!BLOCK_KEYS.has(k)) throw new OperationInputError(`datanotes block: unknown key "${k}" (allowed: ${[...BLOCK_KEYS].join(", ")})`);
15470
- }
15471
- if (b.view !== void 0 && b.table !== void 0) throw new OperationInputError(`datanotes block: pass "view" or "table", not both`);
15472
- const target = b.view ?? b.table;
15473
- if (typeof target !== "string" || target.trim() === "") throw new OperationInputError(`datanotes block needs "view" or "table"`);
15474
- const { view: _v, labels, row_link, chart, with_table, ...query } = b;
15475
- const labelMap = {};
15476
- if (labels != null) {
15477
- if (typeof labels !== "object" || Array.isArray(labels)) throw new OperationInputError(`datanotes block: "labels" must be a mapping`);
15478
- for (const [k, v] of Object.entries(labels)) labelMap[k] = String(v);
15479
- }
15480
- const select2 = viewQueryToSelect({ ...query, table: target.trim() });
15481
- return {
15482
- select: select2,
15483
- labels: labelMap,
15484
- rowLink: row_link !== false,
15485
- ...select2.columns ? { columns: select2.columns } : {},
15486
- ...chart !== void 0 ? { chart: parseChart(chart) } : {},
15487
- withTable: with_table === true
15488
- };
15489
- }
15490
- function chartValue(v) {
15491
- if (v === null || v === void 0 || v === "") return "null";
15492
- const n = Number(v);
15493
- return Number.isFinite(n) ? String(Math.round(n * 100) / 100) : "null";
15494
- }
15495
- function chartLabel(v) {
15496
- const text2 = cell(v);
15497
- const d = text2.match(/^(\d{4})-(\d{2})-(\d{2})(?: (\d{2}:\d{2}))?$/);
15498
- const shown = d ? `${d[3]}/${d[2]}${d[4] ? ` ${d[4]}` : ""}` : text2.replace(/\[\[(?:[^|\]]*\|)?([^\]]*)\]\]/g, "$1");
15499
- return JSON.stringify(shown);
15500
- }
15501
- function chartMarkdown(result, chart, labels) {
15502
- if (result.rows.length === 0) return "_No data to chart._";
15503
- const missing = [chart.x, ...chart.y].filter((c) => !(c in result.rows[0]));
15504
- if (missing.length) return `> [!warning] datanotes
15505
- > chart: no column ${missing.map((m) => `"${m}"`).join(", ")} in the rows (columns: ${Object.keys(result.rows[0]).filter((k) => k !== "path").join(", ")})`;
15506
- const lines = ["```chart", `type: ${chart.type}`, `labels: [${result.rows.map((r) => chartLabel(r[chart.x])).join(", ")}]`, "series:"];
15507
- for (const col of chart.y) {
15508
- lines.push(` - title: ${JSON.stringify(labels[col] ?? col)}`, ` data: [${result.rows.map((r) => chartValue(r[col])).join(", ")}]`);
15509
- }
15510
- for (const [label, value] of Object.entries(chart.targets)) {
15511
- lines.push(` - title: ${JSON.stringify(label)}`, ` data: [${result.rows.map(() => String(value)).join(", ")}]`);
15512
- }
15513
- lines.push("tension: 0.3", "width: 100%", "fill: false", "beginAtZero: false", "spanGaps: true", "```");
15514
- if (chart.title) lines.unshift(`**${chart.title}**`, "");
15515
- return lines.join("\n");
15516
- }
15517
- function cell(v) {
15518
- if (v === null || v === void 0) return "";
15519
- if (Array.isArray(v)) return v.map(cell).filter((x) => x !== "").join(", ");
15520
- if (typeof v === "boolean") return v ? "\u2713" : "";
15521
- if (typeof v === "object") return JSON.stringify(v).replace(/\|/g, "\\|");
15522
- const text2 = String(v);
15523
- const dt = text2.match(/^(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}):\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/);
15524
- if (dt) return `${dt[1]} ${dt[2]}`;
15525
- return text2.replace(/\r?\n/g, " ").replace(/\|/g, "\\|");
15526
- }
15527
- function viewMarkdown(result, opts) {
15528
- if (result.rows.length === 0) return "_No rows._";
15529
- const grouped = !("path" in result.rows[0]);
15530
- let columns = opts.columns ?? Object.keys(result.rows[0]).filter((k) => k !== "path");
15531
- if (grouped) columns = Object.keys(result.rows[0]);
15532
- const link = !grouped && opts.rowLink && !columns.includes("file_link");
15533
- const heads = [...link ? [opts.labels.file_link ?? "Note"] : [], ...columns.map((c) => opts.labels[c] ?? c)];
15534
- const lines = [`| ${heads.map(cell).join(" | ")} |`, `| ${heads.map(() => "---").join(" | ")} |`];
15535
- for (const r of result.rows) {
15536
- const path6 = typeof r.path === "string" ? r.path : "";
15537
- const name = path6.split("/").pop().replace(/\.md$/i, "");
15538
- const cells = [...link ? [cell(`[[${path6.replace(/\.md$/i, "")}|${name}]]`)] : [], ...columns.map((c) => cell(r[c]))];
15539
- lines.push(`| ${cells.join(" | ")} |`);
15540
- }
15541
- const shown = result.rows.length;
15542
- lines.push("", `<small>${result.total === shown ? `${shown} ${shown === 1 ? "row" : "rows"}` : `${shown} of ${result.total} rows`}${result.view ? ` \xB7 view ${result.view}` : ""}</small>`);
15543
- return lines.join("\n");
15544
- }
15545
- async function renderViewBlock(app, settings, source, host) {
15546
- try {
15547
- const block = parseViewBlock(source);
15548
- const result = await select(app, settings, { ...block.select, ...host ? { host } : {} });
15549
- let labels = block.labels;
15550
- if (result.view) {
15551
- const ms = await loadMetastore(app, settings);
15552
- const ref2 = ms ? resolveCatalogRef(ms.model, result.view, "view") : null;
15553
- const own = ref2 ? ms.model.catalogs[ref2.catalog].schemas[ref2.schema].views[ref2.table].labels : void 0;
15554
- labels = { ...own ?? {}, ...block.labels };
15555
- }
15556
- const table = () => viewMarkdown(result, { labels, rowLink: block.rowLink, ...block.select.columns ? { columns: block.select.columns } : {} });
15557
- const markdown = block.chart ? [chartMarkdown(result, block.chart, labels), ...block.withTable ? ["", table()] : []].join("\n") : table();
15558
- return { markdown, total: result.total, ...result.view ? { view: result.view } : {} };
15559
- } catch (e) {
15560
- return { markdown: `> [!warning] datanotes
15561
- > ${(e instanceof Error ? e.message : String(e)).replace(/\n/g, "\n> ")}`, total: 0 };
15562
- }
15563
- }
15564
-
15565
14993
  // src/server/rest.ts
15566
14994
  var ROUTE_PREFIX = "/datanotes";
15567
14995
  var BadRequest = class extends Error {
@@ -15630,9 +15058,8 @@ function errorResponse(e) {
15630
15058
  return { status: 404, json: { error: message } };
15631
15059
  }
15632
15060
  if (e instanceof Forbidden) return { status: 403, json: { error: message } };
15633
- if (e instanceof AmbiguousTableError) return { status: 409, json: { error: message, paths: e.paths } };
15634
15061
  if (e instanceof AmbiguousCatalogRefError) return { status: 409, json: { error: message, tables: e.candidates } };
15635
- if (e instanceof BadRequest || e instanceof OperationInputError || e instanceof MalformedColumnError || e instanceof MalformedTableOptionsError || e instanceof UnsupportedNestedMappingError || e instanceof QueryInputError || e instanceof DatabaseConfigError || e instanceof EmbeddingError || e instanceof MetastoreError) {
15062
+ if (e instanceof BadRequest || e instanceof OperationInputError || e instanceof MalformedColumnError || e instanceof MalformedTableOptionsError || e instanceof QueryInputError || e instanceof DatabaseConfigError || e instanceof EmbeddingError || e instanceof MetastoreError) {
15636
15063
  return { status: 400, json: { error: message } };
15637
15064
  }
15638
15065
  return { status: 500, json: { error: message } };
@@ -15816,16 +15243,6 @@ function createHandlers(app, getSettings, saveSettings = async () => {
15816
15243
  },
15817
15244
  "/tables/describe/": async (body) => ({ status: 200, json: await describeTable(app, s(), str(body, "table")) }),
15818
15245
  "/ddl/": ddl,
15819
- // The engine's API itself, method by method (camelCase inputs as in public-api.ts), for the
15820
- // owner: `remote-api.ts` is its client.
15821
- "/api/": async (body) => {
15822
- const method = str(body, "method");
15823
- const args = list(body, "args") ?? [];
15824
- const fn = pub[method];
15825
- if (typeof fn !== "function" || API_EXCLUDED.has(method)) throw new BadRequest(`"method" must be a method of the engine API`);
15826
- const result = await fn.apply(pub, args);
15827
- return { status: 200, json: { result: result === void 0 ? null : result } };
15828
- },
15829
15246
  "/batch/": async (body) => {
15830
15247
  const ops = list(body, "operations");
15831
15248
  if (!ops || ops.length === 0) throw new BadRequest(`"operations" must be a non-empty list`);
@@ -15907,22 +15324,6 @@ function createHandlers(app, getSettings, saveSettings = async () => {
15907
15324
  throw new BadRequest(e instanceof Error ? e.message : String(e));
15908
15325
  }
15909
15326
  },
15910
- "/views/render/": async (body) => {
15911
- const blockText = str(body, "block", false);
15912
- const view = str(body, "view", false);
15913
- if (!blockText && !view) throw new BadRequest(`pass "view" (a view name) or "block" (the text of an datanotes block)`);
15914
- const where = obj(body, "where", false);
15915
- const source = blockText ?? `view: ${view}${where ? `
15916
- where: ${JSON.stringify(where)}` : ""}`;
15917
- const notePath = str(body, "note", false);
15918
- let host;
15919
- if (notePath) {
15920
- const f = app.vault.getAbstractFileByPath(notePath);
15921
- if (!f || !("extension" in f)) throw new BadRequest(`note not found: ${notePath}`);
15922
- host = { path: notePath, frontmatter: app.metadataCache.getFileCache(f)?.frontmatter ?? {} };
15923
- }
15924
- return { status: 200, json: await renderViewBlock(app, s(), source, host) };
15925
- },
15926
15327
  "/webhooks/": async () => {
15927
15328
  try {
15928
15329
  return { status: 200, json: { webhooks: pub.listWebhooks() } };
@@ -16233,7 +15634,6 @@ where: ${JSON.stringify(where)}` : ""}`;
16233
15634
  };
16234
15635
  return handlers;
16235
15636
  }
16236
- var API_EXCLUDED = /* @__PURE__ */ new Set(["withActor"]);
16237
15637
  function batchArgs(op, args) {
16238
15638
  const out = { ...args };
16239
15639
  const move = (from, to) => {
@@ -16597,7 +15997,7 @@ var OPERATIONS = [
16597
15997
  },
16598
15998
  "path": {
16599
15999
  "type": "string",
16600
- "description": "database.yaml#catalog.schema.table (or a legacy schema note)."
16000
+ "description": "database.yaml#catalog.schema.table."
16601
16001
  },
16602
16002
  "description": {
16603
16003
  "type": "string",
@@ -16612,6 +16012,7 @@ var OPERATIONS = [
16612
16012
  },
16613
16013
  "required": [
16614
16014
  "name",
16015
+ "catalog",
16615
16016
  "schema",
16616
16017
  "qualified",
16617
16018
  "path"
@@ -16709,7 +16110,8 @@ var OPERATIONS = [
16709
16110
  "description": "Folder of the table's rows."
16710
16111
  },
16711
16112
  "inDatabase": {
16712
- "type": "boolean"
16113
+ "type": "boolean",
16114
+ "description": "Always true."
16713
16115
  },
16714
16116
  "rowPath": {
16715
16117
  "type": "string",
@@ -16723,6 +16125,7 @@ var OPERATIONS = [
16723
16125
  "required": [
16724
16126
  "folder",
16725
16127
  "inDatabase",
16128
+ "rowPath",
16726
16129
  "archive"
16727
16130
  ],
16728
16131
  "additionalProperties": true
@@ -16809,7 +16212,7 @@ var OPERATIONS = [
16809
16212
  },
16810
16213
  "dense": {
16811
16214
  "type": "boolean",
16812
- "description": "Also a top-level schema field."
16215
+ "description": "Written on every row (with its default)."
16813
16216
  }
16814
16217
  },
16815
16218
  "required": [
@@ -16828,7 +16231,7 @@ var OPERATIONS = [
16828
16231
  "items": {
16829
16232
  "type": "string"
16830
16233
  },
16831
- "description": "Top-level schema fields without a column entry."
16234
+ "description": "Table defaults without a column (written on every new row), and the table property."
16832
16235
  },
16833
16236
  "qualified": {
16834
16237
  "type": "string",
@@ -23969,7 +23372,7 @@ var OPERATIONS = [
23969
23372
  },
23970
23373
  {
23971
23374
  "name": "infer_table",
23972
- "description": "Read-only schema inference from notes' frontmatter.\n- `folder` (recursive; \"\" = whole vault) and/or `paths`: notes not yet in a table. Returns\n `columns` (type, enum `values`, link `ref` to the table most targets belong to, `required`,\n `unique`, `dense`, `from` when the property name is not a valid column name, `stats`),\n `proposal` ready for create_table (`name`, `options.filename` or `timeColumn`, `columns`) and\n `adopt` ready for adopt_rows (`paths`, `rename`, `relocate: false`), plus `notes` to read.\n Review the proposal (names, enums, required) before creating; ask the user when unsure.\n- `table`: keys the table's rows use but the table does not declare (candidates for add_column,\n or keys to drop from rows).\nA string column becomes an enum with at most `max_enum_values` distinct values (default 12).",
23375
+ "description": "Read-only schema inference from notes' frontmatter.\n- `folder` (recursive; \"\" = whole vault) and/or `paths`: notes not yet in a table. Returns\n `columns` (type, enum `values`, link `ref` to the table most targets belong to, `required`,\n `unique`, `dense`, `from` when the property name is not a valid column name, `stats`),\n `proposal` ready for create_table (`name`, `options.filename` or `timeColumn`, `columns`) and\n `adopt` ready for adopt_rows (`paths`, `rename`, `relocate: false`), plus `notes` to read.\n Review the proposal (names, enums, required) before creating; ask the user when unsure.\n- `table`: keys the table's rows use but the table does not declare (candidates for add_column,\n or keys to drop from rows).\nA string column becomes an enum when its values repeat: at least 3 notes, at most `max_enum_values`\ndistinct values (default 12), each used twice on average, short texts.",
23973
23376
  "inputSchema": {
23974
23377
  "additionalProperties": false,
23975
23378
  "properties": {
@@ -26768,7 +26171,7 @@ var OPERATIONS = [
26768
26171
  },
26769
26172
  {
26770
26173
  "name": "create_view",
26771
- "description": "Create (or `replace`) a view: a named select stored in database.yaml. Name it with the prefix\n`vw_` (e.g. `vw_open_tasks`): views share names and folders with tables. `query` takes the\nselect_rows parameters (table, columns, where, order_by, limit, join, group_by, aggregates, expand;\nrelative dates keep it current) and must run now. `comment` and `aliases` let agents find it;\n`labels` are column headings. Read it with select_rows(table=<view>). A note shows it with a\n```datanotes block containing `view: <name>` (drawn live by the client; nothing is written into\nthe note). Filters may read the note that shows the view: `{this.date}`, `{this.date+1d}` (a\nfrontmatter value, date arithmetic), `{this.link}` (a link to that note), `{this.name}`. The view\nalso gets a note in its schema folder.",
26174
+ "description": "Create (or `replace`) a view: a named select stored in database.yaml. Name it with the prefix\n`vw_` (e.g. `vw_open_tasks`): views share names and folders with tables. `query` takes the\nselect_rows parameters (table, columns, where, order_by, limit, join, group_by, aggregates, expand;\nrelative dates keep it current) and must run now. `comment` and `aliases` let agents find it;\n`labels` are column headings. Views are selected with select_rows(table=<view>), which may narrow them further\n(where, columns, order_by, limit). A view writes no note: it lives only in database.yaml.",
26772
26175
  "inputSchema": {
26773
26176
  "additionalProperties": false,
26774
26177
  "properties": {
@@ -28623,7 +28026,6 @@ var READ_ROUTES = /* @__PURE__ */ new Set([
28623
28026
  "/tables/infer/",
28624
28027
  "/select/",
28625
28028
  "/check/",
28626
- "/views/render/",
28627
28029
  "/changes/",
28628
28030
  "/search/semantic/",
28629
28031
  "/search/semantic/status/",
@@ -28902,22 +28304,6 @@ function openApiDocument(version) {
28902
28304
  body: { type: "object", properties: { rebuild: { type: "boolean", default: false } } },
28903
28305
  result: resultOf("semantic_index") ?? { type: "object" }
28904
28306
  },
28905
- {
28906
- route: "/views/render/",
28907
- operationId: "render_view",
28908
- summary: "Render a view, or the text of a ```datanotes block, as Markdown (what a note shows).",
28909
- body: {
28910
- type: "object",
28911
- properties: {
28912
- view: { type: "string", description: "A view's name." },
28913
- block: { type: "string", description: "The text of a ```datanotes block (instead of `view`)." },
28914
- where: { type: "object", description: "Extra filter (with `view`)." },
28915
- note: { type: "string", description: "The note the block is in: its frontmatter fills `{this.*}`." }
28916
- }
28917
- },
28918
- result: { type: "object", additionalProperties: true },
28919
- namesTable: true
28920
- },
28921
28307
  {
28922
28308
  route: "/sessions/identify/",
28923
28309
  operationId: "identify_session",
@@ -28939,17 +28325,6 @@ function openApiDocument(version) {
28939
28325
  result: ok,
28940
28326
  writes: true
28941
28327
  },
28942
- {
28943
- route: "/api/",
28944
- operationId: "engine_api",
28945
- summary: "Call the engine's API method by method (owner only): what the remote engine client uses.",
28946
- description: "`method` is a method of the engine's public API (camelCase, as in `src/core/public-api.ts`), `args` its positional arguments. Answers `{result}`.",
28947
- body: { type: "object", required: ["method"], properties: { method: { type: "string" }, args: { type: "array", items: {} } } },
28948
- bodyRequired: true,
28949
- result: { type: "object", properties: { result: {} } },
28950
- namesTable: true,
28951
- writes: true
28952
- },
28953
28328
  {
28954
28329
  route: "/openapi/",
28955
28330
  operationId: "openapi_post",
@@ -30360,7 +29735,7 @@ var AppRegistry = class {
30360
29735
  return null;
30361
29736
  }
30362
29737
  const keys = ROW_ROUTES[route];
30363
- if (!keys) return a.maintain && !OWNER_ADMIN_ROUTES.has(route) && route !== "/api/" ? null : `app ${a.name} may not call ${route} (reserved to the owner)`;
29738
+ if (!keys) return a.maintain && !OWNER_ADMIN_ROUTES.has(route) ? null : `app ${a.name} may not call ${route} (reserved to the owner)`;
30364
29739
  const model = (await loadMetastore(this.deps.app, this.deps.getSettings()).catch(() => null))?.model ?? null;
30365
29740
  for (const k of keys) {
30366
29741
  const ref2 = b[k];
@@ -30692,22 +30067,13 @@ var EngineRuntime = class {
30692
30067
  return this.httpServer !== null;
30693
30068
  }
30694
30069
  /**
30695
- * Housekeeping of the hidden store: journal notes of the old format are imported (and removed
30696
- * from the vault), journal entries and log files past their retention are dropped.
30070
+ * Housekeeping of the hidden store: journal entries and log files past their retention are
30071
+ * dropped.
30697
30072
  */
30698
30073
  async maintainStore() {
30699
30074
  const app = this.o.app;
30700
30075
  const s = this.o.getSettings();
30701
30076
  try {
30702
- const imported = await importLegacyJournal(app, s);
30703
- if (imported.imported > 0 || imported.errors.length > 0) {
30704
- telemetry().log(imported.errors.length > 0 ? "WARN" : "INFO", "datanotes imported journal notes into the store", {
30705
- imported: imported.imported,
30706
- skipped: imported.skipped,
30707
- removed: imported.removed,
30708
- errors: imported.errors.length
30709
- });
30710
- }
30711
30077
  const compacted = await compactJournal(app, s);
30712
30078
  const logs = await pruneLogs(app, s);
30713
30079
  if (compacted.dropped > 0 || compacted.blobsRemoved > 0 || logs.length > 0) {
@@ -30726,7 +30092,7 @@ var EngineRuntime = class {
30726
30092
  const refreshMetastore = () => loadMetastore(app, s()).then((ms) => {
30727
30093
  this.inverse.init();
30728
30094
  return ms;
30729
- }).then((ms) => syncViewNotes(app, s(), ms?.model ?? null)).catch((e) => telemetry().log("WARN", "datanotes could not read database.yaml", { error: errorText(e) }));
30095
+ }).catch((e) => telemetry().log("WARN", "datanotes could not read database.yaml", { error: errorText(e) }));
30730
30096
  const logSoon = () => {
30731
30097
  if (this.logTimer) clearTimeout(this.logTimer);
30732
30098
  this.logTimer = setTimeout(() => {
@@ -30734,7 +30100,7 @@ var EngineRuntime = class {
30734
30100
  void logExternalEdits(app, s());
30735
30101
  }, EXTERNAL_EDIT_DELAY_MS);
30736
30102
  };
30737
- const watched = (path6) => path6 === metastorePath(s()) || path6.endsWith(".md") && !path6.startsWith(`${s().journalFolder}/`);
30103
+ const watched = (path6) => path6 === metastorePath(s()) || path6.endsWith(".md");
30738
30104
  const v = app.vault;
30739
30105
  const mc = app.metadataCache;
30740
30106
  this.listen(v, "modify", (f) => {
@@ -31211,8 +30577,8 @@ var DEFAULT_VAULT_CONFIG = {
31211
30577
  trashOption: "system",
31212
30578
  userIgnoreFilters: []
31213
30579
  };
31214
- function readVaultConfig(root2) {
31215
- const file = import_node_path2.default.join(root2, ".obsidian", "app.json");
30580
+ function readVaultConfig(root) {
30581
+ const file = import_node_path2.default.join(root, ".obsidian", "app.json");
31216
30582
  let raw = {};
31217
30583
  try {
31218
30584
  raw = JSON.parse(import_node_fs2.default.readFileSync(file, "utf8"));
@@ -31230,7 +30596,6 @@ function readVaultConfig(root2) {
31230
30596
  }
31231
30597
 
31232
30598
  // src/node/node-app.ts
31233
- var KEEP_ALL = "\0";
31234
30599
  var NodeFile = class {
31235
30600
  constructor(path6, stat) {
31236
30601
  this.path = path6;
@@ -31283,19 +30648,19 @@ async function atomicWrite(abs, data) {
31283
30648
  }
31284
30649
  }
31285
30650
  }
31286
- function resolveInVault(root2, rel) {
30651
+ function resolveInVault(root, rel) {
31287
30652
  const parts = String(rel).split("/").filter((s) => s !== "" && s !== ".");
31288
30653
  for (const s of parts) {
31289
30654
  if (s === ".." || s.includes("\\") || s.includes("\0") || /^[A-Za-z]:/.test(s)) throw new Error(`path outside the vault refused: ${rel}`);
31290
30655
  }
31291
- const base = import_node_path3.default.resolve(root2);
30656
+ const base = import_node_path3.default.resolve(root);
31292
30657
  const abs = import_node_path3.default.resolve(base, ...parts);
31293
30658
  if (abs !== base && !abs.startsWith(base + import_node_path3.default.sep)) throw new Error(`path outside the vault refused: ${rel}`);
31294
30659
  return abs;
31295
30660
  }
31296
30661
  var NodeAdapter = class {
31297
- constructor(root2) {
31298
- this.root = root2;
30662
+ constructor(root) {
30663
+ this.root = root;
31299
30664
  }
31300
30665
  abs(p) {
31301
30666
  return resolveInVault(this.root, p);
@@ -31341,6 +30706,16 @@ var NodeVault = class {
31341
30706
  this.files = /* @__PURE__ */ new Map();
31342
30707
  this.folders = /* @__PURE__ */ new Map();
31343
30708
  this.root = new NodeFolder("");
30709
+ /**
30710
+ * Bring one path of the index in line with the disk (for the watcher). Emits create / modify /
30711
+ * delete when something changed; returns what happened.
30712
+ */
30713
+ /**
30714
+ * Paths the vault is writing right now (and the folders above them). Between the change on disk
30715
+ * and the index update there is an `await`: a rescan landing there must not take the vault's own
30716
+ * write for a change made outside (a moved file would be dropped as deleted and added again).
30717
+ */
30718
+ this.busy = /* @__PURE__ */ new Map();
31344
30719
  this.adapter = new NodeAdapter(basePath);
31345
30720
  this.events.setMaxListeners(0);
31346
30721
  this.folders.set("", this.root);
@@ -31426,12 +30801,25 @@ var NodeVault = class {
31426
30801
  async refreshStat(f) {
31427
30802
  f.stat = statsOf(await import_promises.default.stat(this.abs(f.path)));
31428
30803
  }
31429
- /**
31430
- * Bring one path of the index in line with the disk (for the watcher). Emits create / modify /
31431
- * delete when something changed; returns what happened.
31432
- */
30804
+ async guarded(paths, fn) {
30805
+ for (const p of paths) this.busy.set(p, (this.busy.get(p) ?? 0) + 1);
30806
+ try {
30807
+ return await fn();
30808
+ } finally {
30809
+ for (const p of paths) {
30810
+ const n = (this.busy.get(p) ?? 1) - 1;
30811
+ if (n <= 0) this.busy.delete(p);
30812
+ else this.busy.set(p, n);
30813
+ }
30814
+ }
30815
+ }
30816
+ isBusy(rel) {
30817
+ for (const p of this.busy.keys()) if (rel === p || rel.startsWith(`${p}/`) || p.startsWith(`${rel}/`)) return true;
30818
+ return false;
30819
+ }
31433
30820
  syncPath(rel) {
31434
30821
  if (rel === "" || hidden(rel)) return null;
30822
+ if (this.isBusy(rel)) return null;
31435
30823
  let st = null;
31436
30824
  try {
31437
30825
  st = import_node_fs3.default.statSync(this.abs(rel));
@@ -31523,8 +30911,10 @@ var NodeVault = class {
31523
30911
  }
31524
30912
  /** Write a file's text (internal: also used by the file manager). */
31525
30913
  async writeText(file, data) {
31526
- await atomicWrite(this.abs(file.path), data);
31527
- await this.refreshStat(file);
30914
+ await this.guarded([file.path], async () => {
30915
+ await atomicWrite(this.abs(file.path), data);
30916
+ await this.refreshStat(file);
30917
+ });
31528
30918
  this.emit("modify", file);
31529
30919
  }
31530
30920
  async process(file, fn) {
@@ -31537,9 +30927,11 @@ var NodeVault = class {
31537
30927
  async create(p, data) {
31538
30928
  const rel = p.replace(/^\/+/, "");
31539
30929
  if (import_node_fs3.default.existsSync(this.abs(rel))) throw new Error(`File already exists: ${rel}`);
31540
- await this.ensureFolder(dirname(rel));
31541
- await atomicWrite(this.abs(rel), data);
31542
- const f = this.addFile(rel, statsOf(await import_promises.default.stat(this.abs(rel))));
30930
+ const f = await this.guarded([rel], async () => {
30931
+ await this.ensureFolder(dirname(rel));
30932
+ await atomicWrite(this.abs(rel), data);
30933
+ return this.addFile(rel, statsOf(await import_promises.default.stat(this.abs(rel))));
30934
+ });
31543
30935
  this.emit("create", f);
31544
30936
  return f;
31545
30937
  }
@@ -31556,6 +30948,9 @@ var NodeVault = class {
31556
30948
  return this.folders.get(rel);
31557
30949
  }
31558
30950
  async delete(file, force) {
30951
+ return this.guarded([file.path], () => this.deleteNow(file, force));
30952
+ }
30953
+ async deleteNow(file, force) {
31559
30954
  const rel = file.path;
31560
30955
  if (this.folders.has(rel)) {
31561
30956
  const gone = [...this.files.values()].filter((f2) => f2.path.startsWith(`${rel}/`));
@@ -31570,8 +30965,11 @@ var NodeVault = class {
31570
30965
  if (f) this.emit("delete", f);
31571
30966
  }
31572
30967
  /** Move to `.trash/` (Obsidian's local trash; also for "system", which Node cannot reach) or delete. */
31573
- async trash(file, _system) {
30968
+ async trash(file, system) {
31574
30969
  if (this.config.trashOption === "none") return this.delete(file, true);
30970
+ return this.guarded([file.path], () => this.trashNow(file, system));
30971
+ }
30972
+ async trashNow(file, _system) {
31575
30973
  const target = await this.freeName(`.trash/${basename2(file.path)}`);
31576
30974
  const isFolder = this.folders.has(file.path);
31577
30975
  const gone = isFolder ? [...this.files.values()].filter((f) => f.path.startsWith(`${file.path}/`)) : [];
@@ -31603,6 +31001,9 @@ var NodeVault = class {
31603
31001
  const from = item.path;
31604
31002
  const to = newPath.replace(/^\/+|\/+$/g, "");
31605
31003
  if (from === to) return /* @__PURE__ */ new Map();
31004
+ return this.guarded([from, to], () => this.moveNow(item, from, to));
31005
+ }
31006
+ async moveNow(item, from, to) {
31606
31007
  if (import_node_fs3.default.existsSync(this.abs(to)) && from.toLowerCase() !== to.toLowerCase()) throw new Error(`Destination exists: ${to}`);
31607
31008
  await this.ensureFolder(dirname(to));
31608
31009
  await import_promises.default.rename(this.abs(from), this.abs(to));
@@ -31686,7 +31087,7 @@ var NodeMetadataCache = class {
31686
31087
  let frontmatter2;
31687
31088
  let body = text2;
31688
31089
  try {
31689
- const r = readOrderedFromMarkdownForChildNote(text2, KEEP_ALL, /* @__PURE__ */ new Set());
31090
+ const r = readOrderedFromMarkdown(text2);
31690
31091
  body = r.body;
31691
31092
  if (r.ordered.length > 0) frontmatter2 = Object.fromEntries(r.ordered);
31692
31093
  } catch {
@@ -31835,7 +31236,7 @@ var NodeFileManager = class {
31835
31236
  const f = this.vault.getAbstractFileByPath(file.path);
31836
31237
  if (!f) throw new Error(`file not found: ${file.path}`);
31837
31238
  const text2 = await this.vault.read(f);
31838
- const { ordered, body } = readOrderedFromMarkdownForChildNote(text2, KEEP_ALL, /* @__PURE__ */ new Set());
31239
+ const { ordered, body } = readOrderedFromMarkdown(text2);
31839
31240
  const fm = Object.fromEntries(ordered);
31840
31241
  const before = JSON.stringify(fm);
31841
31242
  fn(fm);
@@ -31847,8 +31248,8 @@ var NodeFileManager = class {
31847
31248
  return this.vault.trash(file, true);
31848
31249
  }
31849
31250
  };
31850
- function openNodeVault(root2, config) {
31851
- const vault = new NodeVault(import_node_path3.default.resolve(root2), { ...readVaultConfig(root2), ...config ?? {} });
31251
+ function openNodeVault(root, config) {
31252
+ const vault = new NodeVault(import_node_path3.default.resolve(root), { ...readVaultConfig(root), ...config ?? {} });
31852
31253
  vault.scanSync();
31853
31254
  const metadataCache = new NodeMetadataCache(vault);
31854
31255
  metadataCache.indexAll();
@@ -31923,7 +31324,7 @@ var NodeWatcher = class {
31923
31324
  };
31924
31325
 
31925
31326
  // src/node/service.ts
31926
- var VERSION = true ? "1.5.0" : "dev";
31327
+ var VERSION = true ? "2.0.1" : "dev";
31927
31328
  function parseArgs(argv, env = process.env) {
31928
31329
  const get = (name) => {
31929
31330
  const i = argv.indexOf(`--${name}`);
@@ -32098,7 +31499,7 @@ Docs: https://datanotes.dev`;
32098
31499
  }
32099
31500
 
32100
31501
  // src/node/cli.ts
32101
- var VERSION2 = true ? "1.5.0" : "dev";
31502
+ var VERSION2 = true ? "2.0.1" : "dev";
32102
31503
  async function main2(argv = process.argv.slice(2)) {
32103
31504
  const [command, ...rest] = argv;
32104
31505
  if (command === "--version" || command === "-v" || command === "version") return void process.stdout.write(`${VERSION2}