ocean-brain 0.5.0 → 0.6.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.
- package/dist/mcp.js +660 -31
- package/package.json +2 -1
- package/server/client/dist/assets/{Calendar-BU9XgX2N.js → Calendar-BJHLksEZ.js} +1 -1
- package/server/client/dist/assets/{Callout-C6tVCxOT.js → Callout-wFx9oCas.js} +1 -1
- package/server/client/dist/assets/Graph-9piERaNR.js +1 -0
- package/server/client/dist/assets/{Image-DxWhlIDG.js → Image-DK0lnaK2.js} +1 -1
- package/server/client/dist/assets/{Image.es-BjGK7y6Y.js → Image.es-Be7par_j.js} +1 -1
- package/server/client/dist/assets/Note-CC9ybxXL.js +21 -0
- package/server/client/dist/assets/{Plus.es-EcmtS_uw.js → Plus.es-BKm7uDYu.js} +1 -1
- package/server/client/dist/assets/Reminders-DRxA8v98.js +1 -0
- package/server/client/dist/assets/Search-BunSQrqv.js +1 -0
- package/server/client/dist/assets/{SurfaceCard-CO0oVxeL.js → SurfaceCard-FhlC8VSR.js} +1 -1
- package/server/client/dist/assets/Tag-z_crJ5JP.js +1 -0
- package/server/client/dist/assets/TagNotes-D7wIJ4jy.js +1 -0
- package/server/client/dist/assets/{Trash.es-DmwfSy3l.js → Trash.es-ByMVwx0d.js} +1 -1
- package/server/client/dist/assets/ViewNotes-Duo9XmcJ.js +1 -0
- package/server/client/dist/assets/Views-D4Z_O9Kd.js +1 -0
- package/server/client/dist/assets/{image.api-DeF9ck7g.js → image.api-B5Qi-Txv.js} +1 -1
- package/server/client/dist/assets/{index-BZUGWdOU.css → index-Cd81UxEh.css} +1 -1
- package/server/client/dist/assets/index-cHJQCo8V.js +1 -0
- package/server/client/dist/assets/index-nYj7BL3a.js +327 -0
- package/server/client/dist/assets/manage-image-detail-DcZggB1M.js +1 -0
- package/server/client/dist/assets/manage-image-glbtBibn.js +1 -0
- package/server/client/dist/assets/{mcp-Bh743HBz.js → mcp-BBUpQdS9.js} +1 -1
- package/server/client/dist/assets/{note-core-Z6kqulGB.js → note-core-DMZcZ4yV.js} +53 -53
- package/server/client/dist/assets/{note-vendor-i1M2FSI2.js → note-vendor-uuJO2MTD.js} +1 -1
- package/server/client/dist/assets/{placeholder-XQqo1Fvr.js → placeholder-B_qb_qkc.js} +5 -5
- package/server/client/dist/assets/properties-CiyQv6Tb.js +1 -0
- package/server/client/dist/assets/trash-CQnj4Rmv.js +1 -0
- package/server/client/dist/assets/{useReminderMutate-D21PurIS.js → useReminderMutate-CSKliBcc.js} +1 -1
- package/server/client/dist/assets/view-dashboard-B5fKgvk_.js +99 -0
- package/server/client/dist/index.html +4 -4
- package/server/dist/features/note/graphql/note.field.resolver.js +2 -0
- package/server/dist/features/note/graphql/note.field.resolver.js.map +1 -1
- package/server/dist/features/note/graphql/note.mutation.resolver.js +119 -0
- package/server/dist/features/note/graphql/note.mutation.resolver.js.map +1 -1
- package/server/dist/features/note/graphql/note.query.resolver.js +14 -0
- package/server/dist/features/note/graphql/note.query.resolver.js.map +1 -1
- package/server/dist/features/note/graphql/note.type-defs.js +100 -0
- package/server/dist/features/note/graphql/note.type-defs.js.map +1 -1
- package/server/dist/features/note/http/mcp.js +394 -1
- package/server/dist/features/note/http/mcp.js.map +1 -1
- package/server/dist/features/note/services/markdown-intent-write.js +495 -0
- package/server/dist/features/note/services/markdown-intent-write.js.map +1 -0
- package/server/dist/features/note/services/markdown-patch.js +601 -0
- package/server/dist/features/note/services/markdown-patch.js.map +1 -0
- package/server/dist/features/note/services/properties.js +874 -0
- package/server/dist/features/note/services/properties.js.map +1 -0
- package/server/dist/features/note/services/snapshot.js +94 -12
- package/server/dist/features/note/services/snapshot.js.map +1 -1
- package/server/dist/features/note/services/trash.js +70 -2
- package/server/dist/features/note/services/trash.js.map +1 -1
- package/server/dist/features/note/services/write.js +21 -7
- package/server/dist/features/note/services/write.js.map +1 -1
- package/server/dist/features/view/graphql/view.query.resolver.js +31 -1
- package/server/dist/features/view/graphql/view.query.resolver.js.map +1 -1
- package/server/dist/features/view/graphql/view.type-defs.js +57 -1
- package/server/dist/features/view/graphql/view.type-defs.js.map +1 -1
- package/server/dist/features/view/services/workspace.js +367 -43
- package/server/dist/features/view/services/workspace.js.map +1 -1
- package/server/dist/modules/blocknote.js +367 -7
- package/server/dist/modules/blocknote.js.map +1 -1
- package/server/dist/routes/mcp.js +21 -1
- package/server/dist/routes/mcp.js.map +1 -1
- package/server/prisma/migrations/20260527073000_0017_note_properties/migration.sql +105 -0
- package/server/prisma/migrations/20260531073000_0018_view_query/migration.sql +3 -0
- package/server/prisma/schema.prisma +226 -130
- package/server/client/dist/assets/Graph-Dond2hGK.js +0 -1
- package/server/client/dist/assets/Note-Cr6GtXUM.js +0 -21
- package/server/client/dist/assets/Reminders-BlLLT_x0.js +0 -1
- package/server/client/dist/assets/Search-CrZ0ap8x.js +0 -1
- package/server/client/dist/assets/Tag-vws5AfNW.js +0 -1
- package/server/client/dist/assets/TagNotes-Fmf1Kgim.js +0 -1
- package/server/client/dist/assets/ViewNotes-BALN7IfH.js +0 -1
- package/server/client/dist/assets/Views-Ccc_Ml5U.js +0 -1
- package/server/client/dist/assets/index-BSVE2cGd.js +0 -1
- package/server/client/dist/assets/index-BvKBTjQq.js +0 -246
- package/server/client/dist/assets/manage-image-IoTXaMBP.js +0 -1
- package/server/client/dist/assets/manage-image-detail-BRTXwOsh.js +0 -1
- package/server/client/dist/assets/trash-hiJIg6-c.js +0 -1
- package/server/client/dist/assets/view-dashboard-BuaZ4MvI.js +0 -90
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/features/view/services/workspace.ts"],"sourcesContent":["import type { Note, Prisma } from '@prisma/client';\nimport { buildNoteTagNamesWhere, type NoteTagMatchMode } from '~/features/note/services/tag-filter.js';\nimport models from '~/models.js';\n\nexport type ViewTagMatchMode = NoteTagMatchMode;\n\nexport interface ViewSectionRecord {\n id: string;\n tabId: string;\n title: string;\n tagNames: string[];\n mode: ViewTagMatchMode;\n limit: number;\n order: number;\n}\n\nexport interface ViewTabRecord {\n id: string;\n title: string;\n order: number;\n sections: ViewSectionRecord[];\n}\n\nexport interface ViewWorkspaceRecord {\n activeTabId: string | null;\n tabs: ViewTabRecord[];\n}\n\nexport interface ViewSectionInput {\n title?: string;\n tagNames: string[];\n mode?: ViewTagMatchMode;\n limit?: number;\n}\n\nexport interface ViewSectionNotesResult {\n totalCount: number;\n notes: Note[];\n}\n\nconst VIEW_WORKSPACE_ID = 1;\n\nexport const DEFAULT_VIEW_SECTION_LIMIT = 5;\nexport const MIN_VIEW_SECTION_LIMIT = 1;\nexport const MAX_VIEW_SECTION_LIMIT = 20;\n\ntype ViewDbClient = typeof models | Prisma.TransactionClient;\n\nconst orderedViewSectionTagsInclude = {\n tags: {\n orderBy: [{ order: 'asc' }, { createdAt: 'asc' }],\n },\n} satisfies Prisma.ViewSectionInclude;\n\nconst orderedViewTabSectionsInclude = {\n sections: {\n orderBy: [{ order: 'asc' }, { createdAt: 'asc' }],\n include: orderedViewSectionTagsInclude,\n },\n} satisfies Prisma.ViewTabInclude;\n\ntype DbViewSection = Prisma.ViewSectionGetPayload<{\n include: typeof orderedViewSectionTagsInclude;\n}>;\n\ntype DbViewTab = Prisma.ViewTabGetPayload<{\n include: typeof orderedViewTabSectionsInclude;\n}>;\n\nconst normalizeTagName = (value: string) => {\n const trimmedValue = value.trim();\n\n if (!trimmedValue) {\n return '';\n }\n\n if (trimmedValue.startsWith('@')) {\n return trimmedValue;\n }\n\n if (trimmedValue.startsWith('#')) {\n return `@${trimmedValue.slice(1)}`;\n }\n\n return `@${trimmedValue}`;\n};\n\nexport const normalizeViewTagNames = (values: string[]) => {\n const normalizedTagNames = values.flatMap((value) => value.split(','));\n\n return Array.from(new Set(normalizedTagNames.map(normalizeTagName).filter(Boolean)));\n};\n\nexport const clampViewSectionLimit = (value: number | undefined) => {\n const numericValue = typeof value === 'number' ? value : Number.NaN;\n\n if (!Number.isInteger(numericValue)) {\n return DEFAULT_VIEW_SECTION_LIMIT;\n }\n\n return Math.min(MAX_VIEW_SECTION_LIMIT, Math.max(MIN_VIEW_SECTION_LIMIT, numericValue));\n};\n\nexport const normalizeViewTabTitle = (title: string) => {\n const trimmedTitle = title.trim();\n\n return trimmedTitle || 'Untitled View';\n};\n\nconst buildDefaultSectionTitle = (tagNames: string[]) => {\n if (tagNames.length === 0) {\n return 'Tagged notes';\n }\n\n return tagNames.slice(0, 2).join(' + ');\n};\n\nexport const normalizeViewSectionInput = (input: ViewSectionInput) => {\n const tagNames = normalizeViewTagNames(input.tagNames);\n\n if (tagNames.length === 0) {\n throw new Error('A view section requires at least one tag.');\n }\n\n const trimmedTitle = input.title?.trim() ?? '';\n\n return {\n title: trimmedTitle || buildDefaultSectionTitle(tagNames),\n tagNames,\n mode: input.mode === 'or' ? 'or' : 'and',\n limit: clampViewSectionLimit(input.limit),\n } satisfies {\n title: string;\n tagNames: string[];\n mode: ViewTagMatchMode;\n limit: number;\n };\n};\n\nexport const pickNextActiveViewTabId = (tabIds: number[], deletedTabId: number, currentActiveTabId: number | null) => {\n const remainingTabIds = tabIds.filter((tabId) => tabId !== deletedTabId);\n\n if (remainingTabIds.length === 0) {\n return null;\n }\n\n if (currentActiveTabId !== deletedTabId) {\n return currentActiveTabId;\n }\n\n return remainingTabIds[0] ?? null;\n};\n\nconst ensureValidReorderIds = (currentIds: number[], nextIds: number[]) => {\n if (currentIds.length !== nextIds.length) {\n throw new Error('Reorder payload must include every item exactly once.');\n }\n\n const currentIdSet = new Set(currentIds);\n const nextIdSet = new Set(nextIds);\n\n if (currentIdSet.size !== currentIds.length || nextIdSet.size !== nextIds.length) {\n throw new Error('Reorder payload contains duplicate ids.');\n }\n\n for (const id of currentIdSet) {\n if (!nextIdSet.has(id)) {\n throw new Error('Reorder payload must match the current item set.');\n }\n }\n};\n\nconst parseViewId = (id: string) => {\n const numericId = Number(id);\n\n if (!Number.isInteger(numericId) || numericId <= 0) {\n throw new Error('A valid id is required.');\n }\n\n return numericId;\n};\n\nconst serializeViewSection = (section: DbViewSection): ViewSectionRecord => ({\n id: String(section.id),\n tabId: String(section.tabId),\n title: section.title,\n tagNames: section.tags.map((tag) => tag.name),\n mode: section.mode as ViewTagMatchMode,\n limit: section.limit,\n order: section.order,\n});\n\nconst serializeViewTab = (tab: DbViewTab): ViewTabRecord => ({\n id: String(tab.id),\n title: tab.title,\n order: tab.order,\n sections: tab.sections.map(serializeViewSection),\n});\n\nconst getOrderedViewTabs = async (db: ViewDbClient) => {\n return db.viewTab.findMany({\n orderBy: [{ order: 'asc' }, { createdAt: 'asc' }],\n include: orderedViewTabSectionsInclude,\n });\n};\n\nconst ensureViewWorkspace = async (db: ViewDbClient) => {\n return db.viewWorkspace.upsert({\n where: { id: VIEW_WORKSPACE_ID },\n update: {},\n create: { id: VIEW_WORKSPACE_ID },\n });\n};\n\nconst readViewWorkspace = async (db: ViewDbClient): Promise<ViewWorkspaceRecord> => {\n const [workspace, tabs] = await Promise.all([ensureViewWorkspace(db), getOrderedViewTabs(db)]);\n\n const activeTabId =\n workspace.activeTabId !== null && tabs.some((tab) => tab.id === workspace.activeTabId)\n ? String(workspace.activeTabId)\n : tabs[0]\n ? String(tabs[0].id)\n : null;\n\n return {\n activeTabId,\n tabs: tabs.map(serializeViewTab),\n };\n};\n\nconst readViewSection = async (db: ViewDbClient, id: number): Promise<ViewSectionRecord | null> => {\n const section = await db.viewSection.findUnique({\n where: { id },\n include: orderedViewSectionTagsInclude,\n });\n\n return section ? serializeViewSection(section) : null;\n};\n\nconst getNextTabOrder = async (db: ViewDbClient) => {\n const lastTab = await db.viewTab.findFirst({\n orderBy: [{ order: 'desc' }, { createdAt: 'desc' }],\n select: { order: true },\n });\n\n return lastTab ? lastTab.order + 1 : 0;\n};\n\nconst getNextSectionOrder = async (db: ViewDbClient, tabId: number) => {\n const lastSection = await db.viewSection.findFirst({\n where: { tabId },\n orderBy: [{ order: 'desc' }, { createdAt: 'desc' }],\n select: { order: true },\n });\n\n return lastSection ? lastSection.order + 1 : 0;\n};\n\nconst resequenceViewTabs = async (db: ViewDbClient) => {\n const tabs = await db.viewTab.findMany({\n orderBy: [{ order: 'asc' }, { createdAt: 'asc' }],\n select: { id: true },\n });\n\n await Promise.all(\n tabs.map((tab, index) =>\n db.viewTab.update({\n where: { id: tab.id },\n data: { order: index },\n }),\n ),\n );\n};\n\nconst resequenceViewSections = async (db: ViewDbClient, tabId: number) => {\n const sections = await db.viewSection.findMany({\n where: { tabId },\n orderBy: [{ order: 'asc' }, { createdAt: 'asc' }],\n select: { id: true },\n });\n\n await Promise.all(\n sections.map((section, index) =>\n db.viewSection.update({\n where: { id: section.id },\n data: { order: index },\n }),\n ),\n );\n};\n\nexport const getViewWorkspace = async () => {\n return readViewWorkspace(models);\n};\n\nexport const getViewSectionById = async (id: string) => {\n return readViewSection(models, parseViewId(id));\n};\n\nexport const getViewSectionNotes = async (\n id: string,\n pagination: {\n limit: number;\n offset: number;\n },\n): Promise<ViewSectionNotesResult | null> => {\n const section = await models.viewSection.findUnique({\n where: { id: parseViewId(id) },\n include: orderedViewSectionTagsInclude,\n });\n\n if (!section) {\n return null;\n }\n\n const tagNames = section.tags.map((tag) => tag.name);\n\n if (tagNames.length === 0) {\n return {\n totalCount: 0,\n notes: [],\n };\n }\n\n const where = buildNoteTagNamesWhere(tagNames, section.mode as NoteTagMatchMode);\n\n const [totalCount, notes] = await Promise.all([\n models.note.count({ where }),\n models.note.findMany({\n orderBy: { updatedAt: 'desc' },\n where,\n take: Number(pagination.limit),\n skip: Number(pagination.offset),\n }),\n ]);\n\n return {\n totalCount,\n notes,\n };\n};\n\nexport const createViewTab = async (title: string) => {\n return models.$transaction(async (tx) => {\n const workspace = await ensureViewWorkspace(tx);\n const nextTabOrder = await getNextTabOrder(tx);\n const createdTab = await tx.viewTab.create({\n data: {\n title: normalizeViewTabTitle(title),\n order: nextTabOrder,\n },\n include: orderedViewTabSectionsInclude,\n });\n\n if (workspace.activeTabId === null) {\n await tx.viewWorkspace.update({\n where: { id: VIEW_WORKSPACE_ID },\n data: { activeTabId: createdTab.id },\n });\n }\n\n return serializeViewTab(createdTab);\n });\n};\n\nexport const updateViewTab = async (id: string, title: string) => {\n const updatedTab = await models.viewTab.update({\n where: { id: parseViewId(id) },\n data: {\n title: normalizeViewTabTitle(title),\n },\n include: orderedViewTabSectionsInclude,\n });\n\n return serializeViewTab(updatedTab);\n};\n\nexport const deleteViewTab = async (id: string) => {\n const tabId = parseViewId(id);\n\n return models.$transaction(async (tx) => {\n const workspace = await ensureViewWorkspace(tx);\n const tabs = await tx.viewTab.findMany({\n orderBy: [{ order: 'asc' }, { createdAt: 'asc' }],\n select: { id: true },\n });\n\n if (!tabs.some((tab) => tab.id === tabId)) {\n return false;\n }\n\n await tx.viewTab.delete({ where: { id: tabId } });\n await resequenceViewTabs(tx);\n\n const nextActiveTabId = pickNextActiveViewTabId(\n tabs.map((tab) => tab.id),\n tabId,\n workspace.activeTabId,\n );\n\n await tx.viewWorkspace.update({\n where: { id: VIEW_WORKSPACE_ID },\n data: { activeTabId: nextActiveTabId },\n });\n\n return true;\n });\n};\n\nexport const setActiveViewTab = async (id: string) => {\n const tabId = parseViewId(id);\n\n return models.$transaction(async (tx) => {\n const workspace = await ensureViewWorkspace(tx);\n const tab = await tx.viewTab.findUnique({\n where: { id: tabId },\n select: { id: true },\n });\n\n if (!tab) {\n throw new Error('View tab not found.');\n }\n\n await tx.viewWorkspace.update({\n where: { id: workspace.id },\n data: { activeTabId: tabId },\n });\n\n return readViewWorkspace(tx);\n });\n};\n\nexport const reorderViewTabs = async (tabIds: string[]) => {\n const nextTabIds = tabIds.map(parseViewId);\n\n return models.$transaction(async (tx) => {\n const tabs = await tx.viewTab.findMany({\n orderBy: [{ order: 'asc' }, { createdAt: 'asc' }],\n select: { id: true },\n });\n const currentTabIds = tabs.map((tab) => tab.id);\n\n ensureValidReorderIds(currentTabIds, nextTabIds);\n\n await Promise.all(\n nextTabIds.map((tabId, index) =>\n tx.viewTab.update({\n where: { id: tabId },\n data: { order: index },\n }),\n ),\n );\n\n const reorderedTabs = await getOrderedViewTabs(tx);\n return reorderedTabs.map(serializeViewTab);\n });\n};\n\nexport const createViewSection = async (tabId: string, input: ViewSectionInput) => {\n const numericTabId = parseViewId(tabId);\n const nextSection = normalizeViewSectionInput(input);\n\n return models.$transaction(async (tx) => {\n const tab = await tx.viewTab.findUnique({\n where: { id: numericTabId },\n select: { id: true },\n });\n\n if (!tab) {\n throw new Error('View tab not found.');\n }\n\n const nextSectionOrder = await getNextSectionOrder(tx, numericTabId);\n\n const createdSection = await tx.viewSection.create({\n data: {\n tabId: numericTabId,\n title: nextSection.title,\n mode: nextSection.mode,\n limit: nextSection.limit,\n order: nextSectionOrder,\n tags: {\n create: nextSection.tagNames.map((tagName, index) => ({\n name: tagName,\n order: index,\n })),\n },\n },\n include: orderedViewSectionTagsInclude,\n });\n\n return serializeViewSection(createdSection);\n });\n};\n\nexport const updateViewSection = async (id: string, input: ViewSectionInput) => {\n const sectionId = parseViewId(id);\n const nextSection = normalizeViewSectionInput(input);\n\n const updatedSection = await models.viewSection.update({\n where: { id: sectionId },\n data: {\n title: nextSection.title,\n mode: nextSection.mode,\n limit: nextSection.limit,\n tags: {\n deleteMany: {},\n create: nextSection.tagNames.map((tagName, index) => ({\n name: tagName,\n order: index,\n })),\n },\n },\n include: orderedViewSectionTagsInclude,\n });\n\n return serializeViewSection(updatedSection);\n};\n\nexport const deleteViewSection = async (id: string) => {\n const sectionId = parseViewId(id);\n\n return models.$transaction(async (tx) => {\n const section = await tx.viewSection.findUnique({\n where: { id: sectionId },\n select: { id: true, tabId: true },\n });\n\n if (!section) {\n return false;\n }\n\n await tx.viewSection.delete({\n where: { id: sectionId },\n });\n await resequenceViewSections(tx, section.tabId);\n\n return true;\n });\n};\n\nexport const reorderViewSections = async (tabId: string, sectionIds: string[]) => {\n const numericTabId = parseViewId(tabId);\n const nextSectionIds = sectionIds.map(parseViewId);\n\n return models.$transaction(async (tx) => {\n const sections = await tx.viewSection.findMany({\n where: { tabId: numericTabId },\n orderBy: [{ order: 'asc' }, { createdAt: 'asc' }],\n select: { id: true },\n });\n const currentSectionIds = sections.map((section) => section.id);\n\n ensureValidReorderIds(currentSectionIds, nextSectionIds);\n\n await Promise.all(\n nextSectionIds.map((sectionId, index) =>\n tx.viewSection.update({\n where: { id: sectionId },\n data: { order: index },\n }),\n ),\n );\n\n const reorderedSections = await tx.viewSection.findMany({\n where: { tabId: numericTabId },\n orderBy: [{ order: 'asc' }, { createdAt: 'asc' }],\n include: orderedViewSectionTagsInclude,\n });\n\n return reorderedSections.map(serializeViewSection);\n });\n};\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/features/view/services/workspace.ts"],"sourcesContent":["import type { Note, Prisma, PropertyValueType } from '@prisma/client';\nimport {\n InvalidNotePropertyInputError,\n normalizePropertyKey,\n normalizeUrlValue,\n} from '~/features/note/services/properties.js';\nimport { buildNoteTagNamesWhere, type NoteTagMatchMode } from '~/features/note/services/tag-filter.js';\nimport models from '~/models.js';\n\nexport type ViewTagMatchMode = NoteTagMatchMode;\nexport type ViewDisplayType = 'list' | 'calendar';\nexport type ViewPropertyFilterOperator = 'equals' | 'before' | 'after' | 'exists' | 'notExists';\nexport type ViewSortBy = 'updatedAt' | 'createdAt' | 'title';\nexport type ViewSortOrder = 'asc' | 'desc';\n\nexport interface ViewPropertyFilterRecord {\n key: string;\n name: string;\n valueType: PropertyValueType;\n operator: ViewPropertyFilterOperator;\n value: string | null;\n}\n\nexport interface ViewSectionRecord {\n id: string;\n tabId: string;\n title: string;\n displayType: ViewDisplayType;\n tagNames: string[];\n mode: ViewTagMatchMode;\n propertyFilters: ViewPropertyFilterRecord[];\n sortBy: ViewSortBy;\n sortOrder: ViewSortOrder;\n limit: number;\n order: number;\n}\n\nexport interface ViewTabRecord {\n id: string;\n title: string;\n order: number;\n sections: ViewSectionRecord[];\n}\n\nexport interface ViewWorkspaceRecord {\n activeTabId: string | null;\n tabs: ViewTabRecord[];\n}\n\nexport interface ViewSectionInput {\n title?: string;\n displayType?: ViewDisplayType;\n tagNames?: string[] | null;\n mode?: ViewTagMatchMode;\n propertyFilters?: ViewPropertyFilterInput[] | null;\n sortBy?: ViewSortBy;\n sortOrder?: ViewSortOrder;\n limit?: number;\n}\n\nexport interface ViewNotesQueryInput {\n tagNames?: string[] | null;\n mode?: ViewTagMatchMode;\n propertyFilters?: ViewPropertyFilterInput[] | null;\n sortBy?: ViewSortBy;\n sortOrder?: ViewSortOrder;\n}\n\nexport interface ViewNotesQueryRecord {\n tagNames: string[];\n mode: ViewTagMatchMode;\n propertyFilters: ViewPropertyFilterRecord[];\n sortBy: ViewSortBy;\n sortOrder: ViewSortOrder;\n}\n\nexport interface ViewPropertyFilterInput {\n key: string;\n operator: ViewPropertyFilterOperator;\n value?: string | null;\n valueType?: PropertyValueType | null;\n}\n\nexport interface ViewSectionNotesResult {\n totalCount: number;\n notes: Note[];\n}\n\nconst VIEW_WORKSPACE_ID = 1;\n\nexport const DEFAULT_VIEW_SECTION_LIMIT = 5;\nexport const MIN_VIEW_SECTION_LIMIT = 1;\nexport const MAX_VIEW_SECTION_LIMIT = 20;\nexport const DEFAULT_VIEW_NOTES_QUERY_LIMIT = 20;\nexport const MAX_VIEW_NOTES_QUERY_LIMIT = 50;\nconst MAX_VIEW_PROPERTY_FILTERS = 10;\nconst DEFAULT_VIEW_DISPLAY_TYPE: ViewDisplayType = 'list';\nconst DEFAULT_VIEW_SORT_BY: ViewSortBy = 'updatedAt';\nconst DEFAULT_VIEW_SORT_ORDER: ViewSortOrder = 'desc';\n\ntype ViewDbClient = typeof models | Prisma.TransactionClient;\n\nconst orderedViewSectionTagsInclude = {\n tags: {\n orderBy: [{ order: 'asc' }, { createdAt: 'asc' }],\n },\n} satisfies Prisma.ViewSectionInclude;\n\nconst orderedViewTabSectionsInclude = {\n sections: {\n orderBy: [{ order: 'asc' }, { createdAt: 'asc' }],\n include: orderedViewSectionTagsInclude,\n },\n} satisfies Prisma.ViewTabInclude;\n\ntype DbViewSection = Prisma.ViewSectionGetPayload<{\n include: typeof orderedViewSectionTagsInclude;\n}>;\n\ntype DbViewTab = Prisma.ViewTabGetPayload<{\n include: typeof orderedViewTabSectionsInclude;\n}>;\n\nconst normalizeTagName = (value: string) => {\n const trimmedValue = value.trim();\n\n if (!trimmedValue) {\n return '';\n }\n\n if (trimmedValue.startsWith('@')) {\n return trimmedValue;\n }\n\n if (trimmedValue.startsWith('#')) {\n return `@${trimmedValue.slice(1)}`;\n }\n\n return `@${trimmedValue}`;\n};\n\nexport const normalizeViewTagNames = (values: string[]) => {\n const normalizedTagNames = values.flatMap((value) => value.split(','));\n\n return Array.from(new Set(normalizedTagNames.map(normalizeTagName).filter(Boolean)));\n};\n\ninterface StoredViewQuery {\n propertyFilters?: ViewPropertyFilterRecord[];\n sortBy?: ViewSortBy;\n sortOrder?: ViewSortOrder;\n}\n\nconst isViewPropertyFilterOperator = (value: unknown): value is ViewPropertyFilterOperator => {\n return value === 'equals' || value === 'before' || value === 'after' || value === 'exists' || value === 'notExists';\n};\n\nconst isPropertyValueType = (value: unknown): value is PropertyValueType => {\n return (\n value === 'text' ||\n value === 'url' ||\n value === 'number' ||\n value === 'date' ||\n value === 'boolean' ||\n value === 'select'\n );\n};\n\nconst normalizeViewDisplayType = (value: ViewDisplayType | undefined): ViewDisplayType => {\n return value === 'calendar' ? 'calendar' : DEFAULT_VIEW_DISPLAY_TYPE;\n};\n\nconst normalizeViewSortBy = (value: ViewSortBy | undefined): ViewSortBy => {\n return value === 'createdAt' || value === 'title' ? value : DEFAULT_VIEW_SORT_BY;\n};\n\nconst normalizeViewSortOrder = (value: ViewSortOrder | undefined): ViewSortOrder => {\n return value === 'asc' ? 'asc' : DEFAULT_VIEW_SORT_ORDER;\n};\n\nconst normalizeFilterValue = ({\n value,\n valueType,\n operator,\n}: {\n value?: string | null;\n valueType: PropertyValueType;\n operator: ViewPropertyFilterOperator;\n}) => {\n if (operator === 'exists' || operator === 'notExists') {\n return null;\n }\n\n const normalizedValue = String(value ?? '').trim();\n\n if (!normalizedValue) {\n throw new InvalidNotePropertyInputError('Property filter value is required.');\n }\n\n if (valueType === 'number' && !Number.isFinite(Number(normalizedValue))) {\n throw new InvalidNotePropertyInputError('Number property filter value must be finite.');\n }\n\n if (valueType === 'boolean' && normalizedValue !== 'true' && normalizedValue !== 'false') {\n throw new InvalidNotePropertyInputError('Boolean property filter value must be true or false.');\n }\n\n if (valueType === 'date') {\n if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(normalizedValue)) {\n throw new InvalidNotePropertyInputError('Date property filter values must use YYYY-MM-DD.');\n }\n\n const date = new Date(`${normalizedValue}T00:00:00.000Z`);\n\n if (Number.isNaN(date.getTime()) || date.toISOString().slice(0, 10) !== normalizedValue) {\n throw new InvalidNotePropertyInputError('Date property filter value is invalid.');\n }\n }\n\n if ((operator === 'before' || operator === 'after') && valueType !== 'date' && valueType !== 'number') {\n throw new InvalidNotePropertyInputError('Before and after filters require date or number properties.');\n }\n\n if (valueType === 'url') {\n return normalizeUrlValue(normalizedValue);\n }\n\n return normalizedValue;\n};\n\nexport const normalizeViewPropertyFilters = (filters: ViewPropertyFilterInput[] | null | undefined) => {\n const normalizedFilters = filters ?? [];\n\n if (normalizedFilters.length > MAX_VIEW_PROPERTY_FILTERS) {\n throw new InvalidNotePropertyInputError(`A view can have up to ${MAX_VIEW_PROPERTY_FILTERS} property filters.`);\n }\n\n return normalizedFilters\n .map((filter): ViewPropertyFilterRecord | null => {\n const key = normalizePropertyKey(filter.key);\n const valueType = filter.valueType;\n const operator = filter.operator;\n\n if (!isPropertyValueType(valueType)) {\n throw new InvalidNotePropertyInputError('Property filter value type is required.');\n }\n\n if (!isViewPropertyFilterOperator(operator)) {\n throw new InvalidNotePropertyInputError('Property filter operator is invalid.');\n }\n\n const storedName = (filter as { name?: unknown }).name;\n const name = typeof storedName === 'string' && storedName.trim() ? storedName.trim() : key;\n\n return {\n key,\n name,\n valueType,\n operator,\n value: normalizeFilterValue({\n value: filter.value,\n valueType,\n operator,\n }),\n };\n })\n .filter((filter): filter is ViewPropertyFilterRecord => filter !== null);\n};\n\nconst parseStoredViewQuery = (value: string | null): Required<StoredViewQuery> => {\n if (!value) {\n return {\n propertyFilters: [],\n sortBy: DEFAULT_VIEW_SORT_BY,\n sortOrder: DEFAULT_VIEW_SORT_ORDER,\n };\n }\n\n try {\n const parsed = JSON.parse(value) as Partial<StoredViewQuery>;\n\n return {\n propertyFilters: normalizeViewPropertyFilters(parsed.propertyFilters ?? []),\n sortBy: normalizeViewSortBy(parsed.sortBy),\n sortOrder: normalizeViewSortOrder(parsed.sortOrder),\n };\n } catch {\n return {\n propertyFilters: [],\n sortBy: DEFAULT_VIEW_SORT_BY,\n sortOrder: DEFAULT_VIEW_SORT_ORDER,\n };\n }\n};\n\nconst serializeStoredViewQuery = ({ propertyFilters, sortBy, sortOrder }: Required<StoredViewQuery>) => {\n return JSON.stringify({\n propertyFilters,\n sortBy,\n sortOrder,\n });\n};\n\nexport const clampViewSectionLimit = (value: number | undefined) => {\n const numericValue = typeof value === 'number' ? value : Number.NaN;\n\n if (!Number.isInteger(numericValue)) {\n return DEFAULT_VIEW_SECTION_LIMIT;\n }\n\n return Math.min(MAX_VIEW_SECTION_LIMIT, Math.max(MIN_VIEW_SECTION_LIMIT, numericValue));\n};\n\nexport const normalizeViewTabTitle = (title: string) => {\n const trimmedTitle = title.trim();\n\n return trimmedTitle || 'Untitled View';\n};\n\nconst buildDefaultSectionTitle = (tagNames: string[], propertyFilters: ViewPropertyFilterRecord[]) => {\n if (tagNames.length > 0) {\n return tagNames.slice(0, 2).join(' + ');\n }\n\n if (propertyFilters.length > 0) {\n return propertyFilters\n .slice(0, 2)\n .map((filter) => filter.name)\n .join(' + ');\n }\n\n return 'All notes';\n};\n\nexport const normalizeViewSectionInput = (input: ViewSectionInput) => {\n const tagNames = normalizeViewTagNames(input.tagNames ?? []);\n const propertyFilters = normalizeViewPropertyFilters(input.propertyFilters);\n const trimmedTitle = input.title?.trim() ?? '';\n const sortBy = normalizeViewSortBy(input.sortBy);\n const sortOrder = normalizeViewSortOrder(input.sortOrder);\n\n return {\n title: trimmedTitle || buildDefaultSectionTitle(tagNames, propertyFilters),\n displayType: normalizeViewDisplayType(input.displayType),\n tagNames,\n mode: input.mode === 'or' ? 'or' : 'and',\n propertyFilters,\n sortBy,\n sortOrder,\n limit: clampViewSectionLimit(input.limit),\n } satisfies {\n title: string;\n displayType: ViewDisplayType;\n tagNames: string[];\n mode: ViewTagMatchMode;\n propertyFilters: ViewPropertyFilterRecord[];\n sortBy: ViewSortBy;\n sortOrder: ViewSortOrder;\n limit: number;\n };\n};\n\nexport const normalizeViewNotesQueryInput = (input: ViewNotesQueryInput): ViewNotesQueryRecord => {\n return {\n tagNames: normalizeViewTagNames(input.tagNames ?? []),\n mode: input.mode === 'or' ? 'or' : 'and',\n propertyFilters: normalizeViewPropertyFilters(input.propertyFilters),\n sortBy: normalizeViewSortBy(input.sortBy),\n sortOrder: normalizeViewSortOrder(input.sortOrder),\n };\n};\n\nexport const normalizeViewNotesPagination = (pagination?: { limit?: number; offset?: number }) => {\n const numericLimit = Number(pagination?.limit ?? DEFAULT_VIEW_NOTES_QUERY_LIMIT);\n const limit = Number.isInteger(numericLimit)\n ? Math.min(MAX_VIEW_NOTES_QUERY_LIMIT, Math.max(1, numericLimit))\n : DEFAULT_VIEW_NOTES_QUERY_LIMIT;\n const numericOffset = Number(pagination?.offset ?? 0);\n const offset = Number.isInteger(numericOffset) ? Math.max(0, numericOffset) : 0;\n\n return { limit, offset };\n};\n\nexport const pickNextActiveViewTabId = (tabIds: number[], deletedTabId: number, currentActiveTabId: number | null) => {\n const remainingTabIds = tabIds.filter((tabId) => tabId !== deletedTabId);\n\n if (remainingTabIds.length === 0) {\n return null;\n }\n\n if (currentActiveTabId !== deletedTabId) {\n return currentActiveTabId;\n }\n\n return remainingTabIds[0] ?? null;\n};\n\nconst ensureValidReorderIds = (currentIds: number[], nextIds: number[]) => {\n if (currentIds.length !== nextIds.length) {\n throw new Error('Reorder payload must include every item exactly once.');\n }\n\n const currentIdSet = new Set(currentIds);\n const nextIdSet = new Set(nextIds);\n\n if (currentIdSet.size !== currentIds.length || nextIdSet.size !== nextIds.length) {\n throw new Error('Reorder payload contains duplicate ids.');\n }\n\n for (const id of currentIdSet) {\n if (!nextIdSet.has(id)) {\n throw new Error('Reorder payload must match the current item set.');\n }\n }\n};\n\nconst parseViewId = (id: string) => {\n const numericId = Number(id);\n\n if (!Number.isInteger(numericId) || numericId <= 0) {\n throw new Error('A valid id is required.');\n }\n\n return numericId;\n};\n\nconst serializeViewSection = (section: DbViewSection): ViewSectionRecord => {\n const query = parseStoredViewQuery(section.query);\n\n return {\n id: String(section.id),\n tabId: String(section.tabId),\n title: section.title,\n displayType: normalizeViewDisplayType(section.displayType as ViewDisplayType),\n tagNames: section.tags.map((tag) => tag.name),\n mode: section.mode as ViewTagMatchMode,\n propertyFilters: query.propertyFilters,\n sortBy: query.sortBy,\n sortOrder: query.sortOrder,\n limit: section.limit,\n order: section.order,\n };\n};\n\nconst serializeViewTab = (tab: DbViewTab): ViewTabRecord => ({\n id: String(tab.id),\n title: tab.title,\n order: tab.order,\n sections: tab.sections.map(serializeViewSection),\n});\n\nconst getOrderedViewTabs = async (db: ViewDbClient) => {\n return db.viewTab.findMany({\n orderBy: [{ order: 'asc' }, { createdAt: 'asc' }],\n include: orderedViewTabSectionsInclude,\n });\n};\n\nconst ensureViewWorkspace = async (db: ViewDbClient) => {\n return db.viewWorkspace.upsert({\n where: { id: VIEW_WORKSPACE_ID },\n update: {},\n create: { id: VIEW_WORKSPACE_ID },\n });\n};\n\nconst readViewWorkspace = async (db: ViewDbClient): Promise<ViewWorkspaceRecord> => {\n const [workspace, tabs] = await Promise.all([ensureViewWorkspace(db), getOrderedViewTabs(db)]);\n\n const activeTabId =\n workspace.activeTabId !== null && tabs.some((tab) => tab.id === workspace.activeTabId)\n ? String(workspace.activeTabId)\n : tabs[0]\n ? String(tabs[0].id)\n : null;\n\n return {\n activeTabId,\n tabs: tabs.map(serializeViewTab),\n };\n};\n\nconst readViewSection = async (db: ViewDbClient, id: number): Promise<ViewSectionRecord | null> => {\n const section = await db.viewSection.findUnique({\n where: { id },\n include: orderedViewSectionTagsInclude,\n });\n\n return section ? serializeViewSection(section) : null;\n};\n\nexport const hydratePropertyFilters = async (\n db: ViewDbClient,\n filters: ViewPropertyFilterRecord[],\n options: { validateSelectOptions?: boolean } = {},\n) => {\n if (filters.length === 0) {\n return [];\n }\n\n const definitions = await db.propertyDefinition.findMany({\n where: { key: { in: filters.map((filter) => filter.key) } },\n select: {\n key: true,\n name: true,\n valueType: true,\n options: {\n select: {\n value: true,\n },\n },\n },\n });\n const definitionByKey = new Map(definitions.map((definition) => [definition.key, definition]));\n\n return filters.map((filter) => {\n const definition = definitionByKey.get(filter.key);\n\n if (!definition) {\n throw new InvalidNotePropertyInputError(`Property ${filter.key} is not defined.`);\n }\n\n if (definition.valueType !== filter.valueType) {\n throw new InvalidNotePropertyInputError(`Property ${filter.key} uses ${definition.valueType} values.`);\n }\n\n if (\n options.validateSelectOptions &&\n filter.valueType === 'select' &&\n filter.operator !== 'exists' &&\n filter.operator !== 'notExists'\n ) {\n const optionValue = normalizeSelectFilterValue(filter.value ?? '');\n\n if (!definition.options.some((option) => option.value === optionValue)) {\n throw new InvalidNotePropertyInputError(`Property ${filter.key} option ${optionValue} is not defined.`);\n }\n }\n\n return {\n ...filter,\n name: definition.name,\n };\n });\n};\n\nconst buildStoredViewQuery = async (db: ViewDbClient, section: ReturnType<typeof normalizeViewSectionInput>) => {\n const propertyFilters = await hydratePropertyFilters(db, section.propertyFilters, { validateSelectOptions: true });\n\n return serializeStoredViewQuery({\n propertyFilters,\n sortBy: section.sortBy,\n sortOrder: section.sortOrder,\n });\n};\n\nconst getNextTabOrder = async (db: ViewDbClient) => {\n const lastTab = await db.viewTab.findFirst({\n orderBy: [{ order: 'desc' }, { createdAt: 'desc' }],\n select: { order: true },\n });\n\n return lastTab ? lastTab.order + 1 : 0;\n};\n\nconst getNextSectionOrder = async (db: ViewDbClient, tabId: number) => {\n const lastSection = await db.viewSection.findFirst({\n where: { tabId },\n orderBy: [{ order: 'desc' }, { createdAt: 'desc' }],\n select: { order: true },\n });\n\n return lastSection ? lastSection.order + 1 : 0;\n};\n\nconst resequenceViewTabs = async (db: ViewDbClient) => {\n const tabs = await db.viewTab.findMany({\n orderBy: [{ order: 'asc' }, { createdAt: 'asc' }],\n select: { id: true },\n });\n\n await Promise.all(\n tabs.map((tab, index) =>\n db.viewTab.update({\n where: { id: tab.id },\n data: { order: index },\n }),\n ),\n );\n};\n\nconst resequenceViewSections = async (db: ViewDbClient, tabId: number) => {\n const sections = await db.viewSection.findMany({\n where: { tabId },\n orderBy: [{ order: 'asc' }, { createdAt: 'asc' }],\n select: { id: true },\n });\n\n await Promise.all(\n sections.map((section, index) =>\n db.viewSection.update({\n where: { id: section.id },\n data: { order: index },\n }),\n ),\n );\n};\n\nexport const getViewWorkspace = async () => {\n return readViewWorkspace(models);\n};\n\nexport const getViewSectionById = async (id: string) => {\n return readViewSection(models, parseViewId(id));\n};\n\nconst normalizeSelectFilterValue = (value: string) => {\n return value.trim().toLowerCase().replace(/\\s+/g, '-');\n};\n\nconst buildPropertyFilterValueWhere = (filter: ViewPropertyFilterRecord): Prisma.NotePropertyWhereInput => {\n switch (filter.valueType) {\n case 'number': {\n const numberValue = Number(filter.value);\n\n if (filter.operator === 'before') {\n return { numberValue: { lt: numberValue } };\n }\n\n if (filter.operator === 'after') {\n return { numberValue: { gt: numberValue } };\n }\n\n return { numberValue };\n }\n case 'date': {\n const dateValue = new Date(`${filter.value}T00:00:00.000Z`);\n\n if (filter.operator === 'before') {\n return { dateValue: { lt: dateValue } };\n }\n\n if (filter.operator === 'after') {\n return { dateValue: { gt: dateValue } };\n }\n\n return { dateValue };\n }\n case 'boolean':\n return { boolValue: filter.value === 'true' };\n case 'select':\n return { option: { is: { value: normalizeSelectFilterValue(filter.value ?? '') } } };\n case 'url':\n case 'text':\n default:\n return { textValueNormalized: filter.value?.toLowerCase() ?? '' };\n }\n};\n\nexport const buildPropertyFilterWhere = (filter: ViewPropertyFilterRecord): Prisma.NoteWhereInput => {\n const definitionWhere = {\n definition: {\n is: {\n key: filter.key,\n },\n },\n } satisfies Prisma.NotePropertyWhereInput;\n\n if (filter.operator === 'notExists') {\n return {\n properties: {\n none: definitionWhere,\n },\n };\n }\n\n if (filter.operator === 'exists') {\n return {\n properties: {\n some: definitionWhere,\n },\n };\n }\n\n return {\n properties: {\n some: {\n ...definitionWhere,\n ...buildPropertyFilterValueWhere(filter),\n },\n },\n };\n};\n\nexport const buildViewNotesWhere = (\n query: Pick<ViewNotesQueryRecord, 'tagNames' | 'mode' | 'propertyFilters'>,\n): Prisma.NoteWhereInput => {\n const clauses: Prisma.NoteWhereInput[] = [];\n\n if (query.tagNames.length > 0) {\n clauses.push(buildNoteTagNamesWhere(query.tagNames, query.mode as NoteTagMatchMode));\n }\n\n for (const filter of query.propertyFilters) {\n clauses.push(buildPropertyFilterWhere(filter));\n }\n\n if (clauses.length === 0) {\n return {};\n }\n\n return { AND: clauses };\n};\n\nexport const buildViewSectionWhere = (section: ViewSectionRecord): Prisma.NoteWhereInput => {\n return buildViewNotesWhere(section);\n};\n\nconst buildViewNotesOrderBy = (\n query: Pick<ViewNotesQueryRecord, 'sortBy' | 'sortOrder'>,\n): Prisma.NoteOrderByWithRelationInput[] => {\n return [{ [query.sortBy]: query.sortOrder }, { id: 'asc' }];\n};\n\nconst buildViewSectionOrderBy = (section: ViewSectionRecord): Prisma.NoteOrderByWithRelationInput[] => {\n return buildViewNotesOrderBy(section);\n};\n\nexport const getViewSectionNotes = async (\n id: string,\n pagination: {\n limit: number;\n offset: number;\n },\n): Promise<ViewSectionNotesResult | null> => {\n const section = await models.viewSection.findUnique({\n where: { id: parseViewId(id) },\n include: orderedViewSectionTagsInclude,\n });\n\n if (!section) {\n return null;\n }\n\n const serializedSection = serializeViewSection(section);\n const where = buildViewSectionWhere(serializedSection);\n\n const [totalCount, notes] = await Promise.all([\n models.note.count({ where }),\n models.note.findMany({\n orderBy: buildViewSectionOrderBy(serializedSection),\n where,\n take: Number(pagination.limit),\n skip: Number(pagination.offset),\n }),\n ]);\n\n return {\n totalCount,\n notes,\n };\n};\n\nexport const getNotesByProperties = async (\n input: ViewNotesQueryInput,\n pagination?: {\n limit?: number;\n offset?: number;\n },\n): Promise<ViewSectionNotesResult> => {\n const normalizedQuery = normalizeViewNotesQueryInput(input);\n\n if (normalizedQuery.propertyFilters.length === 0) {\n throw new InvalidNotePropertyInputError('At least one property filter is required.');\n }\n\n const query = {\n ...normalizedQuery,\n propertyFilters: await hydratePropertyFilters(models, normalizedQuery.propertyFilters, {\n validateSelectOptions: true,\n }),\n };\n const normalizedPagination = normalizeViewNotesPagination(pagination);\n const where = buildViewNotesWhere(query);\n\n const [totalCount, notes] = await Promise.all([\n models.note.count({ where }),\n models.note.findMany({\n orderBy: buildViewNotesOrderBy(query),\n where,\n take: normalizedPagination.limit,\n skip: normalizedPagination.offset,\n }),\n ]);\n\n return {\n totalCount,\n notes,\n };\n};\n\nexport const createViewTab = async (title: string) => {\n return models.$transaction(async (tx) => {\n const workspace = await ensureViewWorkspace(tx);\n const nextTabOrder = await getNextTabOrder(tx);\n const createdTab = await tx.viewTab.create({\n data: {\n title: normalizeViewTabTitle(title),\n order: nextTabOrder,\n },\n include: orderedViewTabSectionsInclude,\n });\n\n if (workspace.activeTabId === null) {\n await tx.viewWorkspace.update({\n where: { id: VIEW_WORKSPACE_ID },\n data: { activeTabId: createdTab.id },\n });\n }\n\n return serializeViewTab(createdTab);\n });\n};\n\nexport const updateViewTab = async (id: string, title: string) => {\n const updatedTab = await models.viewTab.update({\n where: { id: parseViewId(id) },\n data: {\n title: normalizeViewTabTitle(title),\n },\n include: orderedViewTabSectionsInclude,\n });\n\n return serializeViewTab(updatedTab);\n};\n\nexport const deleteViewTab = async (id: string) => {\n const tabId = parseViewId(id);\n\n return models.$transaction(async (tx) => {\n const workspace = await ensureViewWorkspace(tx);\n const tabs = await tx.viewTab.findMany({\n orderBy: [{ order: 'asc' }, { createdAt: 'asc' }],\n select: { id: true },\n });\n\n if (!tabs.some((tab) => tab.id === tabId)) {\n return false;\n }\n\n await tx.viewTab.delete({ where: { id: tabId } });\n await resequenceViewTabs(tx);\n\n const nextActiveTabId = pickNextActiveViewTabId(\n tabs.map((tab) => tab.id),\n tabId,\n workspace.activeTabId,\n );\n\n await tx.viewWorkspace.update({\n where: { id: VIEW_WORKSPACE_ID },\n data: { activeTabId: nextActiveTabId },\n });\n\n return true;\n });\n};\n\nexport const setActiveViewTab = async (id: string) => {\n const tabId = parseViewId(id);\n\n return models.$transaction(async (tx) => {\n const workspace = await ensureViewWorkspace(tx);\n const tab = await tx.viewTab.findUnique({\n where: { id: tabId },\n select: { id: true },\n });\n\n if (!tab) {\n throw new Error('View tab not found.');\n }\n\n await tx.viewWorkspace.update({\n where: { id: workspace.id },\n data: { activeTabId: tabId },\n });\n\n return readViewWorkspace(tx);\n });\n};\n\nexport const reorderViewTabs = async (tabIds: string[]) => {\n const nextTabIds = tabIds.map(parseViewId);\n\n return models.$transaction(async (tx) => {\n const tabs = await tx.viewTab.findMany({\n orderBy: [{ order: 'asc' }, { createdAt: 'asc' }],\n select: { id: true },\n });\n const currentTabIds = tabs.map((tab) => tab.id);\n\n ensureValidReorderIds(currentTabIds, nextTabIds);\n\n await Promise.all(\n nextTabIds.map((tabId, index) =>\n tx.viewTab.update({\n where: { id: tabId },\n data: { order: index },\n }),\n ),\n );\n\n const reorderedTabs = await getOrderedViewTabs(tx);\n return reorderedTabs.map(serializeViewTab);\n });\n};\n\nexport const createViewSection = async (tabId: string, input: ViewSectionInput) => {\n const numericTabId = parseViewId(tabId);\n const nextSection = normalizeViewSectionInput(input);\n\n return models.$transaction(async (tx) => {\n const tab = await tx.viewTab.findUnique({\n where: { id: numericTabId },\n select: { id: true },\n });\n\n if (!tab) {\n throw new Error('View tab not found.');\n }\n\n const nextSectionOrder = await getNextSectionOrder(tx, numericTabId);\n const query = await buildStoredViewQuery(tx, nextSection);\n\n const createdSection = await tx.viewSection.create({\n data: {\n tabId: numericTabId,\n title: nextSection.title,\n displayType: nextSection.displayType,\n query,\n mode: nextSection.mode,\n limit: nextSection.limit,\n order: nextSectionOrder,\n tags: {\n create: nextSection.tagNames.map((tagName, index) => ({\n name: tagName,\n order: index,\n })),\n },\n },\n include: orderedViewSectionTagsInclude,\n });\n\n return serializeViewSection(createdSection);\n });\n};\n\nexport const updateViewSection = async (id: string, input: ViewSectionInput) => {\n const sectionId = parseViewId(id);\n const nextSection = normalizeViewSectionInput(input);\n\n return models.$transaction(async (tx) => {\n const query = await buildStoredViewQuery(tx, nextSection);\n\n const updatedSection = await tx.viewSection.update({\n where: { id: sectionId },\n data: {\n title: nextSection.title,\n displayType: nextSection.displayType,\n query,\n mode: nextSection.mode,\n limit: nextSection.limit,\n tags: {\n deleteMany: {},\n create: nextSection.tagNames.map((tagName, index) => ({\n name: tagName,\n order: index,\n })),\n },\n },\n include: orderedViewSectionTagsInclude,\n });\n\n return serializeViewSection(updatedSection);\n });\n};\n\nexport const deleteViewSection = async (id: string) => {\n const sectionId = parseViewId(id);\n\n return models.$transaction(async (tx) => {\n const section = await tx.viewSection.findUnique({\n where: { id: sectionId },\n select: { id: true, tabId: true },\n });\n\n if (!section) {\n return false;\n }\n\n await tx.viewSection.delete({\n where: { id: sectionId },\n });\n await resequenceViewSections(tx, section.tabId);\n\n return true;\n });\n};\n\nexport const reorderViewSections = async (tabId: string, sectionIds: string[]) => {\n const numericTabId = parseViewId(tabId);\n const nextSectionIds = sectionIds.map(parseViewId);\n\n return models.$transaction(async (tx) => {\n const sections = await tx.viewSection.findMany({\n where: { tabId: numericTabId },\n orderBy: [{ order: 'asc' }, { createdAt: 'asc' }],\n select: { id: true },\n });\n const currentSectionIds = sections.map((section) => section.id);\n\n ensureValidReorderIds(currentSectionIds, nextSectionIds);\n\n await Promise.all(\n nextSectionIds.map((sectionId, index) =>\n tx.viewSection.update({\n where: { id: sectionId },\n data: { order: index },\n }),\n ),\n );\n\n const reorderedSections = await tx.viewSection.findMany({\n where: { tabId: numericTabId },\n orderBy: [{ order: 'asc' }, { createdAt: 'asc' }],\n include: orderedViewSectionTagsInclude,\n });\n\n return reorderedSections.map(serializeViewSection);\n });\n};\n"],"mappings":"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","names":[]}
|
|
@@ -28,6 +28,21 @@ function stripUnsupportedMarkdownBlocks(blocks) {
|
|
|
28
28
|
children: block.children?.length ? stripUnsupportedMarkdownBlocks(block.children) : []
|
|
29
29
|
}));
|
|
30
30
|
}
|
|
31
|
+
function parseBlockNoteContent(contentJson) {
|
|
32
|
+
const parsed = JSON.parse(contentJson);
|
|
33
|
+
if (!Array.isArray(parsed)) {
|
|
34
|
+
throw new Error("INVALID_BLOCKNOTE_CONTENT");
|
|
35
|
+
}
|
|
36
|
+
return parsed;
|
|
37
|
+
}
|
|
38
|
+
function visitBlocks(blocks, visit) {
|
|
39
|
+
for (const block of blocks) {
|
|
40
|
+
visit(block);
|
|
41
|
+
if (block.children?.length) {
|
|
42
|
+
visitBlocks(block.children, visit);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
31
46
|
function createTagPlaceholder(index) {
|
|
32
47
|
return `${TAG_PLACEHOLDER_PREFIX}${index}${TAG_PLACEHOLDER_SUFFIX}`;
|
|
33
48
|
}
|
|
@@ -153,6 +168,255 @@ function preprocessMarkdownExplicitTags(markdown) {
|
|
|
153
168
|
placeholderToTag
|
|
154
169
|
};
|
|
155
170
|
}
|
|
171
|
+
const MARKDOWN_ANGLE_BRACKET_TOKEN_PATTERN = /<([^<>\n]+)>/g;
|
|
172
|
+
const MARKDOWN_NUMERIC_TILDE_RANGE_PATTERN = /(\d)~(?=\d)/g;
|
|
173
|
+
const MARKDOWN_FENCED_CODE_PATTERN = /^ {0,3}(`{3,}|~{3,})/;
|
|
174
|
+
const ANGLE_BRACKET_PLACEHOLDER_PREFIX = "\uE000OBANGLE";
|
|
175
|
+
const ANGLE_BRACKET_PLACEHOLDER_SUFFIX = "\uE001";
|
|
176
|
+
const NUMERIC_TILDE_RANGE_PLACEHOLDER_PREFIX = "\uE000OBTILDE";
|
|
177
|
+
const NUMERIC_TILDE_RANGE_PLACEHOLDER_SUFFIX = "\uE001";
|
|
178
|
+
function isMarkdownAutolinkAngleBracketText(innerText) {
|
|
179
|
+
if (innerText !== innerText.trim()) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
return /^[a-z][a-z0-9.+-]{1,31}:[^\s<>]*$/i.test(innerText) || /^[^\s@<>]+@[^\s@<>]+\.[^\s@<>]+$/.test(innerText);
|
|
183
|
+
}
|
|
184
|
+
function countLiteralAngleBracketTextTokens(markdown) {
|
|
185
|
+
const tokenCounts = /* @__PURE__ */ new Map();
|
|
186
|
+
for (const match of markdown.matchAll(MARKDOWN_ANGLE_BRACKET_TOKEN_PATTERN)) {
|
|
187
|
+
const token = match[0];
|
|
188
|
+
const innerText = match[1] ?? "";
|
|
189
|
+
if (!token || isMarkdownAutolinkAngleBracketText(innerText)) {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
tokenCounts.set(token, (tokenCounts.get(token) ?? 0) + 1);
|
|
193
|
+
}
|
|
194
|
+
return tokenCounts;
|
|
195
|
+
}
|
|
196
|
+
function extractLiteralAngleBracketTextTokens(markdown) {
|
|
197
|
+
return [...countLiteralAngleBracketTextTokens(markdown).keys()];
|
|
198
|
+
}
|
|
199
|
+
function hasLiteralAngleBracketTextTokenLoss(sourceMarkdown, renderedMarkdown) {
|
|
200
|
+
const sourceCounts = countLiteralAngleBracketTextTokens(sourceMarkdown);
|
|
201
|
+
if (sourceCounts.size === 0) {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
const renderedCounts = countLiteralAngleBracketTextTokens(renderedMarkdown);
|
|
205
|
+
for (const [token, sourceCount] of sourceCounts) {
|
|
206
|
+
if ((renderedCounts.get(token) ?? 0) < sourceCount) {
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
function countNumericTildeRangeMarkers(markdown) {
|
|
213
|
+
return [...markdown.matchAll(MARKDOWN_NUMERIC_TILDE_RANGE_PATTERN)].length;
|
|
214
|
+
}
|
|
215
|
+
function hasNumericTildeRangeMarkers(markdown) {
|
|
216
|
+
return countNumericTildeRangeMarkers(markdown) > 0;
|
|
217
|
+
}
|
|
218
|
+
function hasNumericTildeRangeMarkerLoss(sourceMarkdown, renderedMarkdown) {
|
|
219
|
+
const sourceCount = countNumericTildeRangeMarkers(sourceMarkdown);
|
|
220
|
+
return sourceCount > 0 && countNumericTildeRangeMarkers(renderedMarkdown) < sourceCount;
|
|
221
|
+
}
|
|
222
|
+
function protectMarkdownNumericTildeRanges(markdown) {
|
|
223
|
+
const protectedLines = [];
|
|
224
|
+
const placeholderToToken = /* @__PURE__ */ new Map();
|
|
225
|
+
let activeFence = null;
|
|
226
|
+
for (const line of markdown.split(/(?<=\n)/)) {
|
|
227
|
+
const { body: lineBody, lineEnding } = splitMarkdownLineEnding(line);
|
|
228
|
+
const fenceMatch = lineBody.match(MARKDOWN_FENCED_CODE_PATTERN);
|
|
229
|
+
if (activeFence) {
|
|
230
|
+
protectedLines.push(line);
|
|
231
|
+
if (isClosingFenceLine(lineBody, activeFence)) {
|
|
232
|
+
activeFence = null;
|
|
233
|
+
}
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
if (fenceMatch?.[1]) {
|
|
237
|
+
const marker = fenceMatch[1][0];
|
|
238
|
+
activeFence = {
|
|
239
|
+
marker,
|
|
240
|
+
length: fenceMatch[1].length
|
|
241
|
+
};
|
|
242
|
+
protectedLines.push(line);
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
if (/^(?: {4,}|\t)/.test(lineBody)) {
|
|
246
|
+
protectedLines.push(line);
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
protectedLines.push(`${protectMarkdownLineNumericTildeRanges(lineBody, placeholderToToken)}${lineEnding}`);
|
|
250
|
+
}
|
|
251
|
+
return {
|
|
252
|
+
markdown: protectedLines.join(""),
|
|
253
|
+
placeholderToToken
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
function protectMarkdownTextAngleBrackets(markdown) {
|
|
257
|
+
const protectedLines = [];
|
|
258
|
+
const placeholderToToken = /* @__PURE__ */ new Map();
|
|
259
|
+
let activeFence = null;
|
|
260
|
+
for (const line of markdown.split(/(?<=\n)/)) {
|
|
261
|
+
const { body: lineBody, lineEnding } = splitMarkdownLineEnding(line);
|
|
262
|
+
const fenceMatch = lineBody.match(MARKDOWN_FENCED_CODE_PATTERN);
|
|
263
|
+
if (activeFence) {
|
|
264
|
+
protectedLines.push(line);
|
|
265
|
+
if (isClosingFenceLine(lineBody, activeFence)) {
|
|
266
|
+
activeFence = null;
|
|
267
|
+
}
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
if (fenceMatch?.[1]) {
|
|
271
|
+
const marker = fenceMatch[1][0];
|
|
272
|
+
activeFence = {
|
|
273
|
+
marker,
|
|
274
|
+
length: fenceMatch[1].length
|
|
275
|
+
};
|
|
276
|
+
protectedLines.push(line);
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
if (/^(?: {4,}|\t)/.test(lineBody)) {
|
|
280
|
+
protectedLines.push(line);
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
protectedLines.push(`${protectMarkdownLineTextAngleBrackets(lineBody, placeholderToToken)}${lineEnding}`);
|
|
284
|
+
}
|
|
285
|
+
return {
|
|
286
|
+
markdown: protectedLines.join(""),
|
|
287
|
+
placeholderToToken
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
function splitMarkdownLineEnding(line) {
|
|
291
|
+
if (line.endsWith("\r\n")) {
|
|
292
|
+
return {
|
|
293
|
+
body: line.slice(0, -2),
|
|
294
|
+
lineEnding: "\r\n"
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
if (line.endsWith("\n")) {
|
|
298
|
+
return {
|
|
299
|
+
body: line.slice(0, -1),
|
|
300
|
+
lineEnding: "\n"
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
return {
|
|
304
|
+
body: line,
|
|
305
|
+
lineEnding: ""
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
function isClosingFenceLine(line, fence) {
|
|
309
|
+
const escapedMarker = fence.marker === "`" ? "`" : "~";
|
|
310
|
+
return new RegExp(`^ {0,3}${escapedMarker}{${fence.length},} *$`).test(line);
|
|
311
|
+
}
|
|
312
|
+
function protectMarkdownLineTextAngleBrackets(line, placeholderToToken) {
|
|
313
|
+
let result = "";
|
|
314
|
+
let cursor = 0;
|
|
315
|
+
while (cursor < line.length) {
|
|
316
|
+
const codeStart = line.indexOf("`", cursor);
|
|
317
|
+
if (codeStart === -1) {
|
|
318
|
+
result += replaceLiteralAngleBracketTextTokens(line.slice(cursor), placeholderToToken);
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
result += replaceLiteralAngleBracketTextTokens(line.slice(cursor, codeStart), placeholderToToken);
|
|
322
|
+
const delimiterLength = countRepeatedCharacter(line, codeStart, "`");
|
|
323
|
+
const codeEnd = line.indexOf("`".repeat(delimiterLength), codeStart + delimiterLength);
|
|
324
|
+
if (codeEnd === -1) {
|
|
325
|
+
result += replaceLiteralAngleBracketTextTokens(line.slice(codeStart), placeholderToToken);
|
|
326
|
+
break;
|
|
327
|
+
}
|
|
328
|
+
const codeEndExclusive = codeEnd + delimiterLength;
|
|
329
|
+
result += line.slice(codeStart, codeEndExclusive);
|
|
330
|
+
cursor = codeEndExclusive;
|
|
331
|
+
}
|
|
332
|
+
return result;
|
|
333
|
+
}
|
|
334
|
+
function protectMarkdownLineNumericTildeRanges(line, placeholderToToken) {
|
|
335
|
+
let result = "";
|
|
336
|
+
let cursor = 0;
|
|
337
|
+
while (cursor < line.length) {
|
|
338
|
+
const protectedSpan = findNextMarkdownProtectedSpan(line, cursor);
|
|
339
|
+
if (!protectedSpan) {
|
|
340
|
+
result += replaceNumericTildeRangeMarkers(line.slice(cursor), placeholderToToken);
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
343
|
+
result += replaceNumericTildeRangeMarkers(line.slice(cursor, protectedSpan.start), placeholderToToken);
|
|
344
|
+
result += line.slice(protectedSpan.start, protectedSpan.end);
|
|
345
|
+
cursor = protectedSpan.end;
|
|
346
|
+
}
|
|
347
|
+
return result;
|
|
348
|
+
}
|
|
349
|
+
function findNextMarkdownProtectedSpan(line, cursor) {
|
|
350
|
+
const codeSpan = findNextInlineCodeSpan(line, cursor);
|
|
351
|
+
const linkDestinationSpan = findNextMarkdownLinkDestinationSpan(line, cursor);
|
|
352
|
+
if (!codeSpan) {
|
|
353
|
+
return linkDestinationSpan;
|
|
354
|
+
}
|
|
355
|
+
if (!linkDestinationSpan) {
|
|
356
|
+
return codeSpan;
|
|
357
|
+
}
|
|
358
|
+
return codeSpan.start <= linkDestinationSpan.start ? codeSpan : linkDestinationSpan;
|
|
359
|
+
}
|
|
360
|
+
function findNextInlineCodeSpan(line, cursor) {
|
|
361
|
+
const codeStart = line.indexOf("`", cursor);
|
|
362
|
+
if (codeStart === -1) {
|
|
363
|
+
return null;
|
|
364
|
+
}
|
|
365
|
+
const delimiterLength = countRepeatedCharacter(line, codeStart, "`");
|
|
366
|
+
const codeEnd = line.indexOf("`".repeat(delimiterLength), codeStart + delimiterLength);
|
|
367
|
+
if (codeEnd === -1) {
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
return {
|
|
371
|
+
start: codeStart,
|
|
372
|
+
end: codeEnd + delimiterLength
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
function findNextMarkdownLinkDestinationSpan(line, cursor) {
|
|
376
|
+
const linkDestinationPrefix = line.indexOf("](", cursor);
|
|
377
|
+
if (linkDestinationPrefix === -1) {
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
const destinationStart = linkDestinationPrefix + 2;
|
|
381
|
+
const destinationEnd = line.indexOf(")", destinationStart);
|
|
382
|
+
if (destinationEnd === -1) {
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
385
|
+
return {
|
|
386
|
+
start: destinationStart,
|
|
387
|
+
end: destinationEnd
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
function replaceLiteralAngleBracketTextTokens(text, placeholderToToken) {
|
|
391
|
+
return text.replace(MARKDOWN_ANGLE_BRACKET_TOKEN_PATTERN, (match, innerText) => {
|
|
392
|
+
if (isMarkdownAutolinkAngleBracketText(innerText)) {
|
|
393
|
+
return match;
|
|
394
|
+
}
|
|
395
|
+
const placeholder = createAngleBracketPlaceholder(placeholderToToken.size);
|
|
396
|
+
placeholderToToken.set(placeholder, match);
|
|
397
|
+
return placeholder;
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
function replaceNumericTildeRangeMarkers(text, placeholderToToken) {
|
|
401
|
+
return text.replace(MARKDOWN_NUMERIC_TILDE_RANGE_PATTERN, (match, leadingDigit) => {
|
|
402
|
+
const placeholder = createNumericTildeRangePlaceholder(placeholderToToken.size);
|
|
403
|
+
placeholderToToken.set(placeholder, "~");
|
|
404
|
+
return `${leadingDigit}${placeholder}`;
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
function createAngleBracketPlaceholder(index) {
|
|
408
|
+
return `${ANGLE_BRACKET_PLACEHOLDER_PREFIX}${index}${ANGLE_BRACKET_PLACEHOLDER_SUFFIX}`;
|
|
409
|
+
}
|
|
410
|
+
function createNumericTildeRangePlaceholder(index) {
|
|
411
|
+
return `${NUMERIC_TILDE_RANGE_PLACEHOLDER_PREFIX}${index}${NUMERIC_TILDE_RANGE_PLACEHOLDER_SUFFIX}`;
|
|
412
|
+
}
|
|
413
|
+
function countRepeatedCharacter(value, start, character) {
|
|
414
|
+
let cursor = start;
|
|
415
|
+
while (value[cursor] === character) {
|
|
416
|
+
cursor += 1;
|
|
417
|
+
}
|
|
418
|
+
return cursor - start;
|
|
419
|
+
}
|
|
156
420
|
function findTagPlaceholderAtCursor(text, cursor, placeholderToTag) {
|
|
157
421
|
for (const [placeholder, tagToken] of placeholderToTag.entries()) {
|
|
158
422
|
if (text.startsWith(placeholder, cursor)) {
|
|
@@ -182,6 +446,39 @@ function restoreRemainingTagPlaceholders(blocks, placeholderToTag) {
|
|
|
182
446
|
})
|
|
183
447
|
);
|
|
184
448
|
}
|
|
449
|
+
function restoreProtectedTextPlaceholders(blocks, placeholderToToken) {
|
|
450
|
+
if (placeholderToToken.size === 0) {
|
|
451
|
+
return blocks;
|
|
452
|
+
}
|
|
453
|
+
return mapBlocks(
|
|
454
|
+
blocks,
|
|
455
|
+
(content) => mapBlockContent(
|
|
456
|
+
content,
|
|
457
|
+
(inline) => restoreProtectedTextInValue(inline, placeholderToToken)
|
|
458
|
+
)
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
function restoreProtectedTextInValue(value, placeholderToToken) {
|
|
462
|
+
if (typeof value === "string") {
|
|
463
|
+
return restoreProtectedText(value, placeholderToToken);
|
|
464
|
+
}
|
|
465
|
+
if (Array.isArray(value)) {
|
|
466
|
+
return value.map((item) => restoreProtectedTextInValue(item, placeholderToToken));
|
|
467
|
+
}
|
|
468
|
+
if (value && typeof value === "object") {
|
|
469
|
+
return Object.fromEntries(
|
|
470
|
+
Object.entries(value).map(([key, item]) => [key, restoreProtectedTextInValue(item, placeholderToToken)])
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
return value;
|
|
474
|
+
}
|
|
475
|
+
function restoreProtectedText(text, placeholderToToken) {
|
|
476
|
+
let restoredText = text;
|
|
477
|
+
for (const [placeholder, token] of placeholderToToken.entries()) {
|
|
478
|
+
restoredText = restoredText.split(placeholder).join(token);
|
|
479
|
+
}
|
|
480
|
+
return restoredText;
|
|
481
|
+
}
|
|
185
482
|
function createTextInline(text, styles = {}) {
|
|
186
483
|
return {
|
|
187
484
|
type: "text",
|
|
@@ -300,7 +597,7 @@ function getEditor() {
|
|
|
300
597
|
}
|
|
301
598
|
async function blocksToMarkdown(contentJson) {
|
|
302
599
|
try {
|
|
303
|
-
const blocks =
|
|
600
|
+
const blocks = parseBlockNoteContent(contentJson);
|
|
304
601
|
const supportedBlocks = stripUnsupportedMarkdownBlocks(blocks);
|
|
305
602
|
const placeholderToTag = /* @__PURE__ */ new Map();
|
|
306
603
|
const processed = preprocessCustomInlineContent(supportedBlocks, placeholderToTag, { value: 0 });
|
|
@@ -316,21 +613,84 @@ async function blocksToMarkdown(contentJson) {
|
|
|
316
613
|
async function markdownToBlocksJson(markdown, deps = defaultMarkdownImportDeps) {
|
|
317
614
|
const editor = getEditor();
|
|
318
615
|
const preprocessedMarkdown = preprocessMarkdownExplicitTags(markdown);
|
|
319
|
-
const
|
|
320
|
-
const
|
|
321
|
-
|
|
616
|
+
const tildeProtectedMarkdown = protectMarkdownNumericTildeRanges(preprocessedMarkdown.markdown);
|
|
617
|
+
const contentJson = await parseMarkdownToContentJson(
|
|
618
|
+
editor,
|
|
619
|
+
tildeProtectedMarkdown.markdown,
|
|
322
620
|
deps,
|
|
323
|
-
preprocessedMarkdown.placeholderToTag
|
|
621
|
+
preprocessedMarkdown.placeholderToTag,
|
|
622
|
+
tildeProtectedMarkdown.placeholderToToken
|
|
623
|
+
);
|
|
624
|
+
if (extractLiteralAngleBracketTextTokens(preprocessedMarkdown.markdown).length === 0) {
|
|
625
|
+
return contentJson;
|
|
626
|
+
}
|
|
627
|
+
if (!hasLiteralAngleBracketTextTokenLoss(preprocessedMarkdown.markdown, await blocksToMarkdown(contentJson))) {
|
|
628
|
+
return contentJson;
|
|
629
|
+
}
|
|
630
|
+
const protectedMarkdown = protectMarkdownTextAngleBrackets(tildeProtectedMarkdown.markdown);
|
|
631
|
+
const placeholderToToken = new Map([
|
|
632
|
+
...tildeProtectedMarkdown.placeholderToToken,
|
|
633
|
+
...protectedMarkdown.placeholderToToken
|
|
634
|
+
]);
|
|
635
|
+
return parseMarkdownToContentJson(
|
|
636
|
+
editor,
|
|
637
|
+
protectedMarkdown.markdown,
|
|
638
|
+
deps,
|
|
639
|
+
preprocessedMarkdown.placeholderToTag,
|
|
640
|
+
placeholderToToken
|
|
324
641
|
);
|
|
325
|
-
|
|
642
|
+
}
|
|
643
|
+
async function parseMarkdownToContentJson(editor, markdown, deps, placeholderToTag, placeholderToProtectedTextToken = /* @__PURE__ */ new Map()) {
|
|
644
|
+
const blocks = await editor.tryParseMarkdownToBlocks(markdown);
|
|
645
|
+
const restoredBlocks = await restoreCustomInlineContent(blocks, deps, placeholderToTag);
|
|
646
|
+
const restoredTagBlocks = restoreRemainingTagPlaceholders(restoredBlocks, placeholderToTag);
|
|
647
|
+
const restoredProtectedTextBlocks = restoreProtectedTextPlaceholders(
|
|
648
|
+
restoredTagBlocks,
|
|
649
|
+
placeholderToProtectedTextToken
|
|
650
|
+
);
|
|
651
|
+
return JSON.stringify(restoredProtectedTextBlocks);
|
|
326
652
|
}
|
|
327
653
|
function extractTagIdsFromContentJson(contentJson) {
|
|
328
|
-
const blocks =
|
|
654
|
+
const blocks = parseBlockNoteContent(contentJson);
|
|
329
655
|
return collectTagIds(blocks);
|
|
330
656
|
}
|
|
657
|
+
function hasUnsupportedMarkdownBlocks(contentJson) {
|
|
658
|
+
try {
|
|
659
|
+
let hasUnsupportedBlock = false;
|
|
660
|
+
visitBlocks(parseBlockNoteContent(contentJson), (block) => {
|
|
661
|
+
if (UNSUPPORTED_MARKDOWN_BLOCK_TYPES.has(block.type)) {
|
|
662
|
+
hasUnsupportedBlock = true;
|
|
663
|
+
}
|
|
664
|
+
});
|
|
665
|
+
return hasUnsupportedBlock;
|
|
666
|
+
} catch {
|
|
667
|
+
return false;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
function countReferenceInlinesFromContentJson(contentJson) {
|
|
671
|
+
try {
|
|
672
|
+
let count = 0;
|
|
673
|
+
visitBlocks(parseBlockNoteContent(contentJson), (block) => {
|
|
674
|
+
visitBlockContent(block.content, (inline) => {
|
|
675
|
+
if (inline.type === "reference") {
|
|
676
|
+
count += 1;
|
|
677
|
+
}
|
|
678
|
+
});
|
|
679
|
+
});
|
|
680
|
+
return count;
|
|
681
|
+
} catch {
|
|
682
|
+
return 0;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
331
685
|
export {
|
|
332
686
|
blocksToMarkdown,
|
|
687
|
+
countReferenceInlinesFromContentJson,
|
|
688
|
+
extractLiteralAngleBracketTextTokens,
|
|
333
689
|
extractTagIdsFromContentJson,
|
|
690
|
+
hasLiteralAngleBracketTextTokenLoss,
|
|
691
|
+
hasNumericTildeRangeMarkerLoss,
|
|
692
|
+
hasNumericTildeRangeMarkers,
|
|
693
|
+
hasUnsupportedMarkdownBlocks,
|
|
334
694
|
markdownToBlocksJson
|
|
335
695
|
};
|
|
336
696
|
//# sourceMappingURL=blocknote.js.map
|