@im-nobsidian/core 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -542,8 +542,14 @@ declare class NotionBlockBuilder {
542
542
  }
543
543
 
544
544
  type NotionPropertyValue = Record<string, unknown>;
545
+ interface WikilinkResolver$1 {
546
+ resolve(title: string): string | null;
547
+ resolvePageId(pageId: string): string | null;
548
+ }
545
549
  declare class PropertyMapper {
546
550
  private schema;
551
+ private wikilinkResolver;
552
+ setWikilinkResolver(resolver: WikilinkResolver$1): void;
547
553
  loadSchema(properties: Record<string, {
548
554
  id: string;
549
555
  type: string;
@@ -698,6 +704,8 @@ declare class BlockConverter {
698
704
  private registerTocTransformer;
699
705
  private registerBreadcrumbTransformer;
700
706
  private registerLinkPreviewTransformer;
707
+ private registerPdfTransformer;
708
+ private registerEmbedTransformer;
701
709
  private registerCalloutTransformer;
702
710
  markdownToNotionBlocks(markdown: string): unknown[];
703
711
  private toggleContents;
package/dist/index.js CHANGED
@@ -453,8 +453,13 @@ var StateDB = class _StateDB {
453
453
 
454
454
  // src/notion/property-mapper.ts
455
455
  var DATE_REGEX = /^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2})?/;
456
+ var WIKILINK_REGEX = /^\[\[(.+?)(?:\|.+?)?\]\]$/;
456
457
  var PropertyMapper = class {
457
458
  schema = /* @__PURE__ */ new Map();
459
+ wikilinkResolver = null;
460
+ setWikilinkResolver(resolver) {
461
+ this.wikilinkResolver = resolver;
462
+ }
458
463
  loadSchema(properties) {
459
464
  this.schema.clear();
460
465
  for (const [name, prop] of Object.entries(properties)) {
@@ -506,9 +511,13 @@ var PropertyMapper = class {
506
511
  case "checkbox":
507
512
  return { checkbox: Boolean(value) };
508
513
  case "date": {
514
+ if (typeof value === "object" && value !== null && "start" in value) {
515
+ const obj = value;
516
+ return { date: { start: obj.start, end: obj.end ?? null } };
517
+ }
509
518
  const dateStr = String(value);
510
519
  if (DATE_REGEX.test(dateStr)) {
511
- return { date: { start: dateStr } };
520
+ return { date: { start: dateStr, end: null } };
512
521
  }
513
522
  return null;
514
523
  }
@@ -520,6 +529,45 @@ var PropertyMapper = class {
520
529
  return { phone_number: String(value) };
521
530
  case "status":
522
531
  return { status: { name: String(value) } };
532
+ case "relation": {
533
+ const items = Array.isArray(value) ? value : [value];
534
+ const ids = [];
535
+ for (const item of items) {
536
+ const str = String(item);
537
+ const match = str.match(WIKILINK_REGEX);
538
+ if (match?.[1] && this.wikilinkResolver) {
539
+ const pageId = this.wikilinkResolver.resolve(match[1]);
540
+ if (pageId) ids.push({ id: pageId });
541
+ } else if (str.match(/^[0-9a-f-]{32,36}$/)) {
542
+ ids.push({ id: str });
543
+ }
544
+ }
545
+ return ids.length > 0 ? { relation: ids } : null;
546
+ }
547
+ case "people": {
548
+ const users = Array.isArray(value) ? value : [value];
549
+ const peopleArr = users.map((u) => {
550
+ const s = String(u);
551
+ if (s.match(/^[0-9a-f-]{32,36}$/)) return { object: "user", id: s };
552
+ return null;
553
+ }).filter(Boolean);
554
+ return peopleArr.length > 0 ? { people: peopleArr } : null;
555
+ }
556
+ case "files": {
557
+ const fileList = Array.isArray(value) ? value : [value];
558
+ const filesArr = fileList.map((f) => {
559
+ if (typeof f === "object" && f !== null && "url" in f) {
560
+ const obj = f;
561
+ return { type: "external", name: obj.name ?? "file", external: { url: obj.url } };
562
+ }
563
+ return {
564
+ type: "external",
565
+ name: String(f),
566
+ external: { url: String(f) }
567
+ };
568
+ });
569
+ return { files: filesArr };
570
+ }
523
571
  default:
524
572
  return { rich_text: [{ text: { content: String(value) } }] };
525
573
  }
@@ -538,7 +586,7 @@ var PropertyMapper = class {
538
586
  }
539
587
  if (typeof value === "string") {
540
588
  if (DATE_REGEX.test(value)) {
541
- return { date: { start: value } };
589
+ return { date: { start: value, end: null } };
542
590
  }
543
591
  if (value.startsWith("http://") || value.startsWith("https://")) {
544
592
  return { url: value };
@@ -565,8 +613,12 @@ var PropertyMapper = class {
565
613
  }
566
614
  case "checkbox":
567
615
  return prop.checkbox;
568
- case "date":
569
- return prop.date ?? null;
616
+ case "date": {
617
+ const dateObj = prop.date;
618
+ if (!dateObj) return null;
619
+ if (dateObj.end) return { start: dateObj.start, end: dateObj.end };
620
+ return dateObj.start;
621
+ }
570
622
  case "url":
571
623
  return prop.url;
572
624
  case "email":
@@ -599,7 +651,14 @@ var PropertyMapper = class {
599
651
  }
600
652
  case "relation": {
601
653
  const rel = prop.relation;
602
- return rel?.map((r) => r.id) ?? [];
654
+ if (!rel || rel.length === 0) return [];
655
+ return rel.map((r) => {
656
+ if (this.wikilinkResolver) {
657
+ const title = this.wikilinkResolver.resolvePageId(r.id);
658
+ if (title) return `[[${title}]]`;
659
+ }
660
+ return r.id;
661
+ });
603
662
  }
604
663
  case "rollup": {
605
664
  const rollup = prop.rollup;
@@ -1398,7 +1457,7 @@ var FrontmatterExtractor = class {
1398
1457
  };
1399
1458
 
1400
1459
  // src/converter/pre-processors/wikilink.ts
1401
- var WIKILINK_REGEX = /(?<!!)\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g;
1460
+ var WIKILINK_REGEX2 = /(?<!!)\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g;
1402
1461
  var WikilinkResolver = class {
1403
1462
  constructor(resolve) {
1404
1463
  this.resolve = resolve;
@@ -1412,7 +1471,7 @@ var WikilinkResolver = class {
1412
1471
  }
1413
1472
  const preserveMarkers = input.metadata.preserveMarkers ? [...input.metadata.preserveMarkers] : [];
1414
1473
  const resolved = input.content.replace(
1415
- WIKILINK_REGEX,
1474
+ WIKILINK_REGEX2,
1416
1475
  (_match, target, display) => {
1417
1476
  const label = display ?? target;
1418
1477
  if (this.resolve) {
@@ -1784,13 +1843,45 @@ var FrontmatterGenerator = class {
1784
1843
  if (!properties || Object.keys(properties).length === 0) {
1785
1844
  return { content: input.content, metadata: input.metadata };
1786
1845
  }
1787
- const content = matter.stringify(input.content, properties);
1846
+ const normalized = normalizeProperties(properties);
1847
+ const content = matter.stringify(input.content, normalized);
1788
1848
  return {
1789
1849
  content,
1790
1850
  metadata: input.metadata
1791
1851
  };
1792
1852
  }
1793
1853
  };
1854
+ function normalizeProperties(props) {
1855
+ const result = {};
1856
+ for (const [key, value] of Object.entries(props)) {
1857
+ result[key] = normalizeValue(value);
1858
+ }
1859
+ return result;
1860
+ }
1861
+ function normalizeValue(value) {
1862
+ if (typeof value === "string") {
1863
+ return normalizeDate(value);
1864
+ }
1865
+ if (typeof value === "object" && value !== null && "start" in value) {
1866
+ const dateObj = value;
1867
+ const normalized = {
1868
+ start: normalizeDate(dateObj.start),
1869
+ ...dateObj.end ? { end: normalizeDate(dateObj.end) } : {}
1870
+ };
1871
+ return normalized;
1872
+ }
1873
+ return value;
1874
+ }
1875
+ function normalizeDate(dateStr) {
1876
+ if (typeof dateStr !== "string") return dateStr;
1877
+ if (dateStr.match(/T00:00:00\.000[Z+]/)) {
1878
+ return dateStr.split("T")[0] ?? dateStr;
1879
+ }
1880
+ if (dateStr.match(/T00:00:00[Z+]/)) {
1881
+ return dateStr.split("T")[0] ?? dateStr;
1882
+ }
1883
+ return dateStr;
1884
+ }
1794
1885
 
1795
1886
  // src/converter/post-processors/local-image-restorer.ts
1796
1887
  var LOCAL_IMAGE_MARKER_REGEX = />\s*📎\s*[^\n]*\n>\s*%%\s*im-nobsidian:local-image:([^\s]+)\s*%%/g;
@@ -2029,6 +2120,8 @@ var BlockConverter = class {
2029
2120
  this.registerTocTransformer();
2030
2121
  this.registerBreadcrumbTransformer();
2031
2122
  this.registerLinkPreviewTransformer();
2123
+ this.registerPdfTransformer();
2124
+ this.registerEmbedTransformer();
2032
2125
  this.registerCalloutTransformer();
2033
2126
  this.registerToggleHeadingTransformers();
2034
2127
  }
@@ -2201,6 +2294,24 @@ ${COLUMN_LIST_END}`;
2201
2294
  return `[${url}](${url})`;
2202
2295
  });
2203
2296
  }
2297
+ registerPdfTransformer() {
2298
+ if (!this.n2m) return;
2299
+ this.n2m.setCustomTransformer("pdf", async (block) => {
2300
+ const b = block;
2301
+ const url = b.pdf?.type === "file" ? b.pdf.file?.url ?? "" : b.pdf?.external?.url ?? "";
2302
+ const caption = b.pdf?.caption ? richTextToMarkdown(b.pdf.caption) : "";
2303
+ return `[\u{1F4C4} ${caption || "PDF"}](${url})`;
2304
+ });
2305
+ }
2306
+ registerEmbedTransformer() {
2307
+ if (!this.n2m) return;
2308
+ this.n2m.setCustomTransformer("embed", async (block) => {
2309
+ const b = block;
2310
+ const url = b.embed?.url ?? "";
2311
+ const caption = b.embed?.caption ? richTextToMarkdown(b.embed.caption) : "";
2312
+ return `[${caption || url}](${url})`;
2313
+ });
2314
+ }
2204
2315
  registerCalloutTransformer() {
2205
2316
  if (!this.n2m) return;
2206
2317
  const n2m = this.n2m;
@@ -3003,6 +3114,10 @@ var SyncOrchestrator = class {
3003
3114
  this.blockConverter = new BlockConverter();
3004
3115
  this.imageHandler = new ImageHandler(vaultFs, config.paths.attachments, notionClient);
3005
3116
  this.propertyMapper = new PropertyMapper();
3117
+ this.propertyMapper.setWikilinkResolver({
3118
+ resolve: (title) => stateDb.resolveWikilink(title)?.notionPageId ?? null,
3119
+ resolvePageId: (pageId) => stateDb.resolvePageId(pageId)?.title ?? null
3120
+ });
3006
3121
  this.blockConverter.initNotionToMd(this.notionClient.getInternalClient());
3007
3122
  }
3008
3123
  config;