@scalar/api-client 3.5.1 → 3.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.
Files changed (146) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/index.d.ts +1 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +0 -1
  5. package/dist/style.css +3933 -4768
  6. package/dist/styles/tailwind.config.css +20 -0
  7. package/dist/styles/utilities.css +45 -0
  8. package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.d.ts.map +1 -1
  9. package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.js +1 -1
  10. package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.js.map +1 -1
  11. package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.script.js +1 -1
  12. package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.script.js.map +1 -1
  13. package/dist/v2/blocks/request-block/RequestBlock.vue.script.js.map +1 -1
  14. package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.script.js.map +1 -1
  15. package/dist/v2/components/data-table/DataTableInput.vue.d.ts +1 -1
  16. package/dist/v2/components/data-table/DataTableInput.vue.d.ts.map +1 -1
  17. package/dist/v2/constants.js +1 -1
  18. package/dist/v2/features/app/App.vue.d.ts +15 -31
  19. package/dist/v2/features/app/App.vue.d.ts.map +1 -1
  20. package/dist/v2/features/app/App.vue.js.map +1 -1
  21. package/dist/v2/features/app/App.vue.script.js +131 -50
  22. package/dist/v2/features/app/App.vue.script.js.map +1 -1
  23. package/dist/v2/features/app/app-state.d.ts +10 -14
  24. package/dist/v2/features/app/app-state.d.ts.map +1 -1
  25. package/dist/v2/features/app/app-state.js +53 -21
  26. package/dist/v2/features/app/app-state.js.map +1 -1
  27. package/dist/v2/features/app/components/AppHeader.vue.d.ts.map +1 -1
  28. package/dist/v2/features/app/components/AppHeader.vue.js.map +1 -1
  29. package/dist/v2/features/app/components/AppHeader.vue.script.js +4 -3
  30. package/dist/v2/features/app/components/AppHeader.vue.script.js.map +1 -1
  31. package/dist/v2/features/app/components/AppHeaderActions.vue.d.ts +32 -0
  32. package/dist/v2/features/app/components/AppHeaderActions.vue.d.ts.map +1 -0
  33. package/dist/v2/features/app/components/AppHeaderActions.vue.js +7 -0
  34. package/dist/v2/features/app/components/AppHeaderActions.vue.js.map +1 -0
  35. package/dist/v2/features/app/components/AppHeaderActions.vue.script.js +172 -0
  36. package/dist/v2/features/app/components/AppHeaderActions.vue.script.js.map +1 -0
  37. package/dist/v2/features/app/components/AppSidebar.vue.d.ts +2 -5
  38. package/dist/v2/features/app/components/AppSidebar.vue.d.ts.map +1 -1
  39. package/dist/v2/features/app/components/AppSidebar.vue.js +1 -1
  40. package/dist/v2/features/app/components/AppSidebar.vue.js.map +1 -1
  41. package/dist/v2/features/app/components/AppSidebar.vue.script.js +4 -9
  42. package/dist/v2/features/app/components/AppSidebar.vue.script.js.map +1 -1
  43. package/dist/v2/features/app/components/DesktopTabs.vue.d.ts.map +1 -1
  44. package/dist/v2/features/app/components/DesktopTabs.vue.js.map +1 -1
  45. package/dist/v2/features/app/components/DesktopTabs.vue.script.js +2 -2
  46. package/dist/v2/features/app/components/DesktopTabs.vue.script.js.map +1 -1
  47. package/dist/v2/features/app/components/DocumentBreadcrumb.vue.d.ts +1 -2
  48. package/dist/v2/features/app/components/DocumentBreadcrumb.vue.d.ts.map +1 -1
  49. package/dist/v2/features/app/components/DocumentBreadcrumb.vue.js +1 -1
  50. package/dist/v2/features/app/components/DocumentBreadcrumb.vue.js.map +1 -1
  51. package/dist/v2/features/app/components/DocumentBreadcrumb.vue.script.js +4 -35
  52. package/dist/v2/features/app/components/DocumentBreadcrumb.vue.script.js.map +1 -1
  53. package/dist/v2/features/app/components/DocumentSyncIndicator.vue.d.ts +1 -1
  54. package/dist/v2/features/app/components/DocumentSyncIndicator.vue.d.ts.map +1 -1
  55. package/dist/v2/features/app/components/PublishDocumentModal.vue.d.ts +77 -0
  56. package/dist/v2/features/app/components/PublishDocumentModal.vue.d.ts.map +1 -0
  57. package/dist/v2/features/app/components/PublishDocumentModal.vue.js +7 -0
  58. package/dist/v2/features/app/components/PublishDocumentModal.vue.js.map +1 -0
  59. package/dist/v2/features/app/components/PublishDocumentModal.vue.script.js +209 -0
  60. package/dist/v2/features/app/components/PublishDocumentModal.vue.script.js.map +1 -0
  61. package/dist/v2/features/app/components/SyncConflictResolutionEditor.vue.d.ts.map +1 -0
  62. package/dist/v2/features/{collection → app}/components/SyncConflictResolutionEditor.vue.js +2 -2
  63. package/dist/v2/features/app/components/SyncConflictResolutionEditor.vue.js.map +1 -0
  64. package/dist/v2/features/{collection → app}/components/SyncConflictResolutionEditor.vue.script.js +1 -1
  65. package/dist/v2/features/{collection/components/SyncConflictResolutionEditor.vue.js.map → app/components/SyncConflictResolutionEditor.vue.script.js.map} +1 -1
  66. package/dist/v2/features/app/helpers/check-version-conflict.d.ts +8 -5
  67. package/dist/v2/features/app/helpers/check-version-conflict.d.ts.map +1 -1
  68. package/dist/v2/features/app/helpers/check-version-conflict.js +10 -7
  69. package/dist/v2/features/app/helpers/check-version-conflict.js.map +1 -1
  70. package/dist/v2/features/app/helpers/create-api-client-app.d.ts +8 -5
  71. package/dist/v2/features/app/helpers/create-api-client-app.d.ts.map +1 -1
  72. package/dist/v2/features/app/helpers/create-api-client-app.js +2 -2
  73. package/dist/v2/features/app/helpers/create-api-client-app.js.map +1 -1
  74. package/dist/v2/features/app/helpers/load-registry-document.d.ts +1 -10
  75. package/dist/v2/features/app/helpers/load-registry-document.d.ts.map +1 -1
  76. package/dist/v2/features/app/helpers/load-registry-document.js +6 -5
  77. package/dist/v2/features/app/helpers/load-registry-document.js.map +1 -1
  78. package/dist/v2/features/app/helpers/registry-error-messages.d.ts +23 -0
  79. package/dist/v2/features/app/helpers/registry-error-messages.d.ts.map +1 -0
  80. package/dist/v2/features/app/helpers/registry-error-messages.js +63 -0
  81. package/dist/v2/features/app/helpers/registry-error-messages.js.map +1 -0
  82. package/dist/v2/features/app/hooks/use-active-document-version.d.ts +2 -1
  83. package/dist/v2/features/app/hooks/use-active-document-version.d.ts.map +1 -1
  84. package/dist/v2/features/app/hooks/use-active-document-version.js.map +1 -1
  85. package/dist/v2/features/app/hooks/use-document-sync.d.ts +126 -0
  86. package/dist/v2/features/app/hooks/use-document-sync.d.ts.map +1 -0
  87. package/dist/v2/features/app/hooks/use-document-sync.js +448 -0
  88. package/dist/v2/features/app/hooks/use-document-sync.js.map +1 -0
  89. package/dist/v2/features/app/hooks/use-network-status.d.ts +29 -0
  90. package/dist/v2/features/app/hooks/use-network-status.d.ts.map +1 -0
  91. package/dist/v2/features/app/hooks/use-network-status.js +58 -0
  92. package/dist/v2/features/app/hooks/use-network-status.js.map +1 -0
  93. package/dist/v2/features/app/hooks/use-sidebar-documents.d.ts +1 -25
  94. package/dist/v2/features/app/hooks/use-sidebar-documents.d.ts.map +1 -1
  95. package/dist/v2/features/app/hooks/use-sidebar-documents.js.map +1 -1
  96. package/dist/v2/features/app/index.d.ts +1 -1
  97. package/dist/v2/features/app/index.d.ts.map +1 -1
  98. package/dist/v2/features/collection/DocumentCollection.vue.d.ts.map +1 -1
  99. package/dist/v2/features/collection/DocumentCollection.vue.js.map +1 -1
  100. package/dist/v2/features/collection/DocumentCollection.vue.script.js +43 -277
  101. package/dist/v2/features/collection/DocumentCollection.vue.script.js.map +1 -1
  102. package/dist/v2/features/command-palette/components/CommandPaletteExample.vue.d.ts.map +1 -1
  103. package/dist/v2/features/command-palette/components/CommandPaletteExample.vue.js.map +1 -1
  104. package/dist/v2/features/command-palette/components/CommandPaletteExample.vue.script.js +35 -17
  105. package/dist/v2/features/command-palette/components/CommandPaletteExample.vue.script.js.map +1 -1
  106. package/dist/v2/features/command-palette/components/CommandPaletteImport.vue.d.ts.map +1 -1
  107. package/dist/v2/features/command-palette/components/CommandPaletteImport.vue.js.map +1 -1
  108. package/dist/v2/features/command-palette/components/CommandPaletteImport.vue.script.js +15 -13
  109. package/dist/v2/features/command-palette/components/CommandPaletteImport.vue.script.js.map +1 -1
  110. package/dist/v2/features/command-palette/components/CommandPaletteImportCurl.vue.d.ts.map +1 -1
  111. package/dist/v2/features/command-palette/components/CommandPaletteImportCurl.vue.js +1 -1
  112. package/dist/v2/features/command-palette/components/CommandPaletteImportCurl.vue.js.map +1 -1
  113. package/dist/v2/features/command-palette/components/CommandPaletteImportCurl.vue.script.js +51 -39
  114. package/dist/v2/features/command-palette/components/CommandPaletteImportCurl.vue.script.js.map +1 -1
  115. package/dist/v2/features/command-palette/components/CommandPaletteOpenApiDocument.vue.d.ts.map +1 -1
  116. package/dist/v2/features/command-palette/components/CommandPaletteOpenApiDocument.vue.js.map +1 -1
  117. package/dist/v2/features/command-palette/components/CommandPaletteOpenApiDocument.vue.script.js +30 -14
  118. package/dist/v2/features/command-palette/components/CommandPaletteOpenApiDocument.vue.script.js.map +1 -1
  119. package/dist/v2/features/command-palette/components/CommandPaletteRequest.vue.d.ts.map +1 -1
  120. package/dist/v2/features/command-palette/components/CommandPaletteRequest.vue.js.map +1 -1
  121. package/dist/v2/features/command-palette/components/CommandPaletteRequest.vue.script.js +44 -42
  122. package/dist/v2/features/command-palette/components/CommandPaletteRequest.vue.script.js.map +1 -1
  123. package/dist/v2/features/command-palette/components/CommandPaletteTag.vue.d.ts.map +1 -1
  124. package/dist/v2/features/command-palette/components/CommandPaletteTag.vue.js.map +1 -1
  125. package/dist/v2/features/command-palette/components/CommandPaletteTag.vue.script.js +33 -17
  126. package/dist/v2/features/command-palette/components/CommandPaletteTag.vue.script.js.map +1 -1
  127. package/dist/v2/features/command-palette/helpers/load-document-from-source.d.ts.map +1 -1
  128. package/dist/v2/features/command-palette/helpers/load-document-from-source.js +3 -2
  129. package/dist/v2/features/command-palette/helpers/load-document-from-source.js.map +1 -1
  130. package/dist/v2/features/editor/hooks/use-three-way-merge-editor.d.ts.map +1 -1
  131. package/dist/v2/features/editor/hooks/use-three-way-merge-editor.js +5 -5
  132. package/dist/v2/features/editor/hooks/use-three-way-merge-editor.js.map +1 -1
  133. package/dist/v2/helpers/is-url.d.ts.map +1 -1
  134. package/dist/v2/helpers/is-url.js +2 -1
  135. package/dist/v2/helpers/is-url.js.map +1 -1
  136. package/dist/v2/types/configuration.d.ts +273 -7
  137. package/dist/v2/types/configuration.d.ts.map +1 -1
  138. package/dist/vue-styles.css +1389 -0
  139. package/package.json +20 -14
  140. package/dist/v2/features/app/components/DocumentSyncIndicator.vue.js +0 -7
  141. package/dist/v2/features/app/components/DocumentSyncIndicator.vue.js.map +0 -1
  142. package/dist/v2/features/app/components/DocumentSyncIndicator.vue.script.js +0 -51
  143. package/dist/v2/features/app/components/DocumentSyncIndicator.vue.script.js.map +0 -1
  144. package/dist/v2/features/collection/components/SyncConflictResolutionEditor.vue.d.ts.map +0 -1
  145. package/dist/v2/features/collection/components/SyncConflictResolutionEditor.vue.script.js.map +0 -1
  146. /package/dist/v2/features/{collection → app}/components/SyncConflictResolutionEditor.vue.d.ts +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"use-three-way-merge-editor.js","names":[],"sources":["../../../../../src/v2/features/editor/hooks/use-three-way-merge-editor.ts"],"sourcesContent":["import { apply, type merge } from '@scalar/json-magic/diff'\nimport { deepClone } from '@scalar/workspace-store/helpers/deep-clone'\nimport * as monaco from 'monaco-editor'\nimport type { ComputedRef } from 'vue'\nimport { type MaybeRefOrGetter, computed, markRaw, ref, shallowRef, toValue, watch } from 'vue'\n\nimport { rangeToWholeLine } from '@/v2/features/editor'\nimport { createJsonModel } from '@/v2/features/editor/helpers/json/create-json-model'\nimport { ensureJsonPointerLinkSupport } from '@/v2/features/editor/helpers/json/json-pointer-links'\nimport { parseJsonPointerPath } from '@/v2/features/editor/helpers/json/json-pointer-path'\nimport type { EditorModel, Path } from '@/v2/features/editor/helpers/model'\n\ntype ConflictResolutionState = 'manual' | 'local' | 'remote' | 'ignore' | 'idle'\n\ntype ConflictRange = { index: number; path: string[]; range: monaco.Range }\n\ntype UseThreeWayMergeEditorOptions = {\n /** Base document (common ancestor). */\n baseDocument: MaybeRefOrGetter<Record<string, unknown>>\n /** Document with resolved conflicts (current result). */\n resolvedDocument: MaybeRefOrGetter<Record<string, unknown>>\n /** Merge conflicts from diff. */\n conflicts: MaybeRefOrGetter<ReturnType<typeof merge>['conflicts']>\n /** Called when user applies resolved changes. */\n onApplyChanges: (resolvedDocument: Record<string, unknown>) => void\n /** Optional: called with error message for conflicts left or parse errors. */\n onError?: (message: string) => void\n}\n\ntype ThreeWayMergeEditorContainers = {\n /** Container for the local (current) diff editor. */\n local: HTMLElement\n /** Container for the remote diff editor. */\n remote: HTMLElement\n /** Container for the result (editable) diff editor. */\n result: HTMLElement\n}\n\n/**\n * Shared state and logic for a 3-way merge editor (base | local | remote → result).\n * Create editors by calling init() with the three container elements (e.g. from refs in onMounted).\n * Call dispose() in onUnmounted.\n *\n * @example\n * ```vue\n * <script setup lang=\"ts\">\n * const localRef = ref<HTMLDivElement>()\n * const remoteRef = ref<HTMLDivElement>()\n * const resultRef = ref<HTMLDivElement>()\n *\n * const mergeEditor = useThreeWayMergeEditor({\n * baseDocument,\n * resolvedDocument,\n * conflicts,\n * onApplyChanges: (doc) => emit('applyChanges', { resolvedDocument: doc }),\n * onError: (msg) => toast(msg, 'error'),\n * })\n *\n * onMounted(() => {\n * const local = localRef.value\n * const remote = remoteRef.value\n * const result = resultRef.value\n * if (local && remote && result) {\n * mergeEditor.init({ local, remote, result })\n * }\n * })\n *\n * onUnmounted(() => {\n * mergeEditor.dispose()\n * })\n * </script>\n *\n * <template>\n * <div ref=\"localRef\" />\n * <div ref=\"remoteRef\" />\n * <div ref=\"resultRef\" />\n * <button @click=\"mergeEditor.goToNextConflict\">Next conflict</button>\n * <button :disabled=\"mergeEditor.conflictsLeft > 0\" @click=\"mergeEditor.applyResolvedConflicts\">\n * Apply ({{ mergeEditor.conflictsLeft }} left)\n * </button>\n * </template>\n * ```\n */\nexport function useThreeWayMergeEditor(options: UseThreeWayMergeEditorOptions): {\n init: (containers: ThreeWayMergeEditorContainers) => void\n dispose: () => void\n conflictsLeft: ComputedRef<number>\n goToNextConflict: () => void\n applyResolvedConflicts: () => void\n} {\n const { baseDocument, resolvedDocument, conflicts, onApplyChanges, onError } = options\n\n const resolvedConflicts = ref<ConflictResolutionState[]>([])\n const conflictRangesState = shallowRef<ConflictRange[]>([])\n const localConflictRangesState = shallowRef<ConflictRange[]>([])\n const remoteConflictRangesState = shallowRef<ConflictRange[]>([])\n const lastNavigatedConflictIndex = ref<number>(-1)\n\n const localChangesEditor = shallowRef<monaco.editor.IStandaloneDiffEditor>()\n const remoteChangesEditor = shallowRef<monaco.editor.IStandaloneDiffEditor>()\n const resultEditor = shallowRef<monaco.editor.IStandaloneDiffEditor>()\n\n let resultCodeLensProviderDisposable: monaco.IDisposable | undefined\n let jsonPointerLinkSupportDispose: (() => void) | undefined\n const codeLensCommandDisposables: monaco.IDisposable[] = []\n /** Models created in init(); disposed in dispose() to avoid leaks when the sync conflict modal closes. */\n let modelsToDispose: monaco.editor.ITextModel[] = []\n\n const normalizeConflicts = computed(() => {\n const conflictList = toValue(conflicts)\n return conflictList.map((conflict) => {\n const localChanges = conflict[0]\n const remoteChanges = conflict[1]\n let smallestPath = localChanges[0]!.path\n for (const localChange of localChanges) {\n if (localChange.path.length < smallestPath.length) {\n smallestPath = localChange.path\n }\n }\n for (const remoteChange of remoteChanges) {\n if (remoteChange.path.length < smallestPath.length) {\n smallestPath = remoteChange.path\n }\n }\n return {\n local: {\n path: smallestPath,\n changes: localChanges,\n type: localChanges[0]!.type,\n },\n remote: {\n path: smallestPath,\n changes: remoteChanges,\n type: remoteChanges[0]!.type,\n },\n }\n })\n })\n\n const documentWithLocalChanges = computed(() =>\n apply(\n deepClone(toValue(resolvedDocument)),\n toValue(conflicts).flatMap((it) => it[0]),\n ),\n )\n\n const documentWithRemoteChanges = computed(() =>\n apply(\n deepClone(toValue(resolvedDocument)),\n toValue(conflicts).flatMap((it) => it[1]),\n ),\n )\n\n const conflictsLeft = computed(() => resolvedConflicts.value.filter((status) => status === 'idle').length)\n\n watch(\n normalizeConflicts,\n (nextConflicts) => {\n resolvedConflicts.value = nextConflicts.map((_, index) => resolvedConflicts.value[index] ?? 'idle')\n },\n { immediate: true },\n )\n\n const focusEditorRange = (\n diffEditor: monaco.editor.IStandaloneDiffEditor | undefined,\n range: monaco.Range | undefined,\n ): void => {\n if (!diffEditor || !range) {\n return\n }\n const modifiedEditor = diffEditor.getModifiedEditor()\n const safeRange = new monaco.Range(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn)\n modifiedEditor.setSelection(safeRange)\n modifiedEditor.revealRangeNearTop(safeRange)\n }\n\n const goToNextConflict = (): void => {\n const unresolvedConflictIndexes = normalizeConflicts.value\n .map((_, index) => index)\n .filter((index) => resolvedConflicts.value[index] === 'idle')\n if (!unresolvedConflictIndexes.length) {\n return\n }\n const nextConflictIndex =\n unresolvedConflictIndexes.find((index) => index > lastNavigatedConflictIndex.value) ??\n unresolvedConflictIndexes[0]\n if (nextConflictIndex === undefined) {\n return\n }\n const nextConflict = normalizeConflicts.value[nextConflictIndex]\n if (!nextConflict) {\n return\n }\n const localRange = localConflictRangesState.value.find((cr) => cr.index === nextConflictIndex)?.range\n const remoteRange = remoteConflictRangesState.value.find((cr) => cr.index === nextConflictIndex)?.range\n const resultRange = conflictRangesState.value.find((cr) => cr.index === nextConflictIndex)?.range\n focusEditorRange(localChangesEditor.value, localRange)\n focusEditorRange(remoteChangesEditor.value, remoteRange)\n focusEditorRange(resultEditor.value, resultRange)\n resultEditor.value?.getModifiedEditor().focus()\n lastNavigatedConflictIndex.value = nextConflictIndex\n }\n\n const applyResolvedConflicts = (): void => {\n if (conflictsLeft.value > 0) {\n onError?.('You have conflicts left')\n return\n }\n const modifiedResultModel = resultEditor.value?.getModel()?.modified\n if (!modifiedResultModel) {\n return\n }\n let nextResolvedDocument: Record<string, unknown> | null = null\n try {\n nextResolvedDocument = JSON.parse(modifiedResultModel.getValue()) as Record<string, unknown>\n } catch {\n onError?.('You have formatting errors')\n return\n }\n onApplyChanges(nextResolvedDocument)\n }\n\n const init = (containers: ThreeWayMergeEditorContainers): void => {\n const base = toValue(baseDocument)\n const resolved = toValue(resolvedDocument)\n const localDoc = documentWithLocalChanges.value\n const remoteDoc = documentWithRemoteChanges.value\n\n const originalModelLocal = monaco.editor.createModel(JSON.stringify(resolved, null, 2), 'json')\n const modifiedModelLocal = createJsonModel(JSON.stringify(localDoc, null, 2))\n\n const originalModelRemote = monaco.editor.createModel(JSON.stringify(resolved, null, 2), 'json')\n const modifiedModelRemote = createJsonModel(JSON.stringify(remoteDoc, null, 2))\n\n const originalResultModel = monaco.editor.createModel(JSON.stringify(base, null, 2), 'json')\n const modifiedResultModel = createJsonModel(JSON.stringify(resolved, null, 2))\n\n modelsToDispose = [\n originalModelLocal,\n modifiedModelLocal.model,\n originalModelRemote,\n modifiedModelRemote.model,\n originalResultModel,\n modifiedResultModel.model,\n ]\n\n const localDiffEditor = monaco.editor.createDiffEditor(containers.local, {\n originalEditable: false,\n readOnly: true,\n automaticLayout: true,\n renderSideBySide: false,\n })\n localDiffEditor.setModel({\n original: originalModelLocal,\n modified: modifiedModelLocal.model,\n })\n localChangesEditor.value = localDiffEditor\n\n const remoteDiffEditor = monaco.editor.createDiffEditor(containers.remote, {\n originalEditable: false,\n readOnly: true,\n automaticLayout: true,\n renderSideBySide: false,\n })\n remoteDiffEditor.setModel({\n original: originalModelRemote,\n modified: modifiedModelRemote.model,\n })\n remoteChangesEditor.value = remoteDiffEditor\n\n const resultDiffEditor = monaco.editor.createDiffEditor(containers.result, {\n originalEditable: false,\n readOnly: false,\n renderSideBySide: false,\n automaticLayout: true,\n })\n resultDiffEditor.setModel({\n original: originalResultModel,\n modified: modifiedResultModel.model,\n })\n const resultModifiedEditor = resultDiffEditor.getModifiedEditor()\n resultModifiedEditor.updateOptions({ codeLens: true })\n\n const focusResultPath = async (path: Path): Promise<void> => {\n const range = await modifiedResultModel.getRangeFromPath(path)\n if (!range) {\n return\n }\n const safeRange = new monaco.Range(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn)\n resultModifiedEditor.setSelection(safeRange)\n resultModifiedEditor.revealRangeNearTop(safeRange)\n }\n\n const navigateJsonPointer = async (pointer: string): Promise<void> => {\n const path = parseJsonPointerPath(pointer)\n if (!path) {\n return\n }\n await focusResultPath(path)\n }\n\n const linkSupport = ensureJsonPointerLinkSupport(navigateJsonPointer)\n jsonPointerLinkSupportDispose = linkSupport.dispose\n\n let resultHighlightDecorations: string[] = []\n let suppressedChangeEvents = 0\n\n const applyCurrentCodeLensCommandId = 'scalar.conflict.applyCurrent'\n const applyRemoteCodeLensCommandId = 'scalar.conflict.applyRemote'\n const ignoreCodeLensCommandId = 'scalar.conflict.ignore'\n const noOpCodeLensCommandId = resultModifiedEditor.addCommand(0, () => undefined) ?? 'scalar.conflict.status.noop'\n\n const getBoxDecorationsForRange = (range: monaco.Range): monaco.editor.IModelDeltaDecoration[] => {\n const startLine = range.startLineNumber\n const endLine = range.endLineNumber\n if (startLine === endLine) {\n return [\n {\n range,\n options: {\n isWholeLine: true,\n className: 'json-focus-highlight-box-single',\n },\n },\n ]\n }\n const topRange = new monaco.Range(startLine, 1, startLine, range.endColumn)\n const middleRange = new monaco.Range(startLine + 1, 1, Math.max(startLine + 1, endLine - 1), 1)\n const bottomRange = new monaco.Range(endLine, 1, endLine, range.endColumn)\n const decorations: monaco.editor.IModelDeltaDecoration[] = [\n {\n range: topRange,\n options: {\n isWholeLine: true,\n className: 'json-focus-highlight-box-top',\n },\n },\n {\n range: bottomRange,\n options: {\n isWholeLine: true,\n className: 'json-focus-highlight-box-bottom',\n },\n },\n ]\n if (endLine - startLine > 1) {\n decorations.push({\n range: middleRange,\n options: {\n isWholeLine: true,\n className: 'json-focus-highlight-box-middle',\n },\n })\n }\n return decorations\n }\n\n const refreshCodeLensProvider = (): void => {\n resultCodeLensProviderDisposable?.dispose()\n resultCodeLensProviderDisposable = monaco.languages.registerCodeLensProvider('json', {\n provideCodeLenses: (model) => {\n if (model.uri.toString() !== modifiedResultModel.model.uri.toString()) {\n return { lenses: [], dispose: () => undefined }\n }\n return {\n lenses: conflictRangesState.value.flatMap((conflictRange) => {\n const lensRange = new monaco.Range(\n conflictRange.range.startLineNumber,\n 1,\n conflictRange.range.startLineNumber,\n 1,\n )\n return [\n {\n range: lensRange,\n command: {\n id: noOpCodeLensCommandId,\n title: `Status: ${resolvedConflicts.value[conflictRange.index] ?? 'idle'}`,\n },\n },\n {\n range: lensRange,\n command: {\n id: applyCurrentCodeLensCommandId,\n title: 'Accept Current',\n arguments: [conflictRange.index],\n },\n },\n {\n range: lensRange,\n command: {\n id: applyRemoteCodeLensCommandId,\n title: 'Accept Remote',\n arguments: [conflictRange.index],\n },\n },\n {\n range: lensRange,\n command: {\n id: ignoreCodeLensCommandId,\n title: 'Ignore',\n arguments: [conflictRange.index],\n },\n },\n ]\n }),\n dispose: () => undefined,\n }\n },\n })\n }\n\n const getConflictRange = async (\n editorModel: EditorModel,\n index: number,\n path: string[],\n ): Promise<ConflictRange> => {\n const { model } = editorModel\n const fallbackRange = new monaco.Range(1, 1, 1, model.getLineMaxColumn(1))\n let range: monaco.Range | null = null\n for (let depth = path.length; depth >= 0; depth -= 1) {\n const candidatePath = path.slice(0, depth)\n const nodeRange = await editorModel.getRangeFromPath(candidatePath)\n if (!nodeRange) {\n continue\n }\n range = rangeToWholeLine(model, nodeRange)\n break\n }\n return {\n index,\n path,\n range: markRaw(range ?? fallbackRange),\n }\n }\n\n const refreshConflictRangesAndDecorations = async (): Promise<void> => {\n const [resultRanges, localRanges, remoteRanges] = await Promise.all([\n Promise.all(\n normalizeConflicts.value.map((conflict, index) =>\n getConflictRange(modifiedResultModel, index, conflict.local.path),\n ),\n ),\n Promise.all(\n normalizeConflicts.value.map((conflict, index) =>\n getConflictRange(modifiedModelLocal, index, conflict.local.path),\n ),\n ),\n Promise.all(\n normalizeConflicts.value.map((conflict, index) =>\n getConflictRange(modifiedModelRemote, index, conflict.local.path),\n ),\n ),\n ])\n conflictRangesState.value = resultRanges.filter((r): r is ConflictRange => Boolean(r))\n localConflictRangesState.value = localRanges.filter((r): r is ConflictRange => Boolean(r))\n remoteConflictRangesState.value = remoteRanges.filter((r): r is ConflictRange => Boolean(r))\n resultHighlightDecorations = resultModifiedEditor.deltaDecorations(\n resultHighlightDecorations,\n conflictRangesState.value.flatMap((cr) => getBoxDecorationsForRange(cr.range)),\n )\n refreshCodeLensProvider()\n }\n\n const setConflictResolution = (index: number, resolution: ConflictResolutionState): void => {\n resolvedConflicts.value[index] = resolution\n refreshCodeLensProvider()\n }\n\n const applyConflictChoice = async (index: number, source: 'local' | 'remote'): Promise<void> => {\n const conflict = normalizeConflicts.value[index]\n if (!conflict) {\n return\n }\n let currentDocument: Record<string, unknown> | null = null\n try {\n currentDocument = JSON.parse(modifiedResultModel.model.getValue()) as Record<string, unknown>\n } catch {\n return\n }\n const changes = source === 'local' ? conflict.local.changes : conflict.remote.changes\n const nextDocument = apply(deepClone(currentDocument), changes)\n suppressedChangeEvents += 1\n modifiedResultModel.model.setValue(JSON.stringify(nextDocument, null, 2))\n setConflictResolution(index, source)\n await refreshConflictRangesAndDecorations()\n }\n\n codeLensCommandDisposables.push(\n monaco.editor.registerCommand(applyCurrentCodeLensCommandId, (_accessor, index: number) => {\n void applyConflictChoice(index, 'local')\n }),\n )\n codeLensCommandDisposables.push(\n monaco.editor.registerCommand(applyRemoteCodeLensCommandId, (_accessor, index: number) => {\n void applyConflictChoice(index, 'remote')\n }),\n )\n codeLensCommandDisposables.push(\n monaco.editor.registerCommand(ignoreCodeLensCommandId, (_accessor, index: number) => {\n setConflictResolution(index, 'ignore')\n }),\n )\n\n void refreshConflictRangesAndDecorations()\n\n resultModifiedEditor.onDidChangeModelContent((event) => {\n if (suppressedChangeEvents > 0) {\n suppressedChangeEvents -= 1\n return\n }\n let hasStatusUpdates = false\n for (const change of event.changes) {\n const matchingConflicts = conflictRangesState.value.filter((cr) =>\n monaco.Range.areIntersectingOrTouching(change.range, cr.range),\n )\n if (!matchingConflicts.length) {\n continue\n }\n matchingConflicts.forEach((conflict) => {\n if (resolvedConflicts.value[conflict.index] !== 'manual') {\n resolvedConflicts.value[conflict.index] = 'manual'\n hasStatusUpdates = true\n }\n })\n }\n if (hasStatusUpdates) {\n refreshCodeLensProvider()\n }\n })\n\n resultEditor.value = resultDiffEditor\n }\n\n const dispose = (): void => {\n localChangesEditor.value?.dispose()\n localChangesEditor.value = undefined\n remoteChangesEditor.value?.dispose()\n remoteChangesEditor.value = undefined\n resultEditor.value?.dispose()\n resultEditor.value = undefined\n\n for (const model of modelsToDispose) {\n model.dispose()\n }\n modelsToDispose = []\n\n resultCodeLensProviderDisposable?.dispose()\n resultCodeLensProviderDisposable = undefined\n jsonPointerLinkSupportDispose?.()\n jsonPointerLinkSupportDispose = undefined\n codeLensCommandDisposables.forEach((d) => d.dispose())\n codeLensCommandDisposables.length = 0\n }\n\n return {\n init,\n dispose,\n conflictsLeft,\n goToNextConflict,\n applyResolvedConflicts,\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-three-way-merge-editor.js","names":[],"sources":["../../../../../src/v2/features/editor/hooks/use-three-way-merge-editor.ts"],"sourcesContent":["import { apply, type merge } from '@scalar/json-magic/diff'\nimport { deepClone } from '@scalar/workspace-store/helpers/deep-clone'\nimport * as monaco from 'monaco-editor'\nimport type { ComputedRef } from 'vue'\nimport { type MaybeRefOrGetter, computed, markRaw, ref, shallowRef, toValue, watch } from 'vue'\n\nimport { rangeToWholeLine } from '@/v2/features/editor'\nimport { createJsonModel } from '@/v2/features/editor/helpers/json/create-json-model'\nimport { ensureJsonPointerLinkSupport } from '@/v2/features/editor/helpers/json/json-pointer-links'\nimport { parseJsonPointerPath } from '@/v2/features/editor/helpers/json/json-pointer-path'\nimport type { EditorModel, Path } from '@/v2/features/editor/helpers/model'\n\ntype ConflictResolutionState = 'manual' | 'local' | 'remote' | 'ignore' | 'idle'\n\ntype ConflictRange = { index: number; path: string[]; range: monaco.Range }\n\ntype UseThreeWayMergeEditorOptions = {\n /** Base document (common ancestor). */\n baseDocument: MaybeRefOrGetter<Record<string, unknown>>\n /** Document with resolved conflicts (current result). */\n resolvedDocument: MaybeRefOrGetter<Record<string, unknown>>\n /** Merge conflicts from diff. */\n conflicts: MaybeRefOrGetter<ReturnType<typeof merge>['conflicts']>\n /** Called when user applies resolved changes. */\n onApplyChanges: (resolvedDocument: Record<string, unknown>) => void\n /** Optional: called with error message for conflicts left or parse errors. */\n onError?: (message: string) => void\n}\n\ntype ThreeWayMergeEditorContainers = {\n /** Container for the local (current) diff editor. */\n local: HTMLElement\n /** Container for the remote diff editor. */\n remote: HTMLElement\n /** Container for the result (editable) diff editor. */\n result: HTMLElement\n}\n\n/**\n * Shared state and logic for a 3-way merge editor (base | local | remote → result).\n * Create editors by calling init() with the three container elements (e.g. from refs in onMounted).\n * Call dispose() in onUnmounted.\n *\n * @example\n * ```vue\n * <script setup lang=\"ts\">\n * const localRef = ref<HTMLDivElement>()\n * const remoteRef = ref<HTMLDivElement>()\n * const resultRef = ref<HTMLDivElement>()\n *\n * const mergeEditor = useThreeWayMergeEditor({\n * baseDocument,\n * resolvedDocument,\n * conflicts,\n * onApplyChanges: (doc) => emit('applyChanges', { resolvedDocument: doc }),\n * onError: (msg) => toast(msg, 'error'),\n * })\n *\n * onMounted(() => {\n * const local = localRef.value\n * const remote = remoteRef.value\n * const result = resultRef.value\n * if (local && remote && result) {\n * mergeEditor.init({ local, remote, result })\n * }\n * })\n *\n * onUnmounted(() => {\n * mergeEditor.dispose()\n * })\n * </script>\n *\n * <template>\n * <div ref=\"localRef\" />\n * <div ref=\"remoteRef\" />\n * <div ref=\"resultRef\" />\n * <button @click=\"mergeEditor.goToNextConflict\">Next conflict</button>\n * <button :disabled=\"mergeEditor.conflictsLeft > 0\" @click=\"mergeEditor.applyResolvedConflicts\">\n * Apply ({{ mergeEditor.conflictsLeft }} left)\n * </button>\n * </template>\n * ```\n */\nexport function useThreeWayMergeEditor(options: UseThreeWayMergeEditorOptions): {\n init: (containers: ThreeWayMergeEditorContainers) => void\n dispose: () => void\n conflictsLeft: ComputedRef<number>\n goToNextConflict: () => void\n applyResolvedConflicts: () => void\n} {\n const { baseDocument, resolvedDocument, conflicts, onApplyChanges, onError } = options\n\n const resolvedConflicts = ref<ConflictResolutionState[]>([])\n const conflictRangesState = shallowRef<ConflictRange[]>([])\n const localConflictRangesState = shallowRef<ConflictRange[]>([])\n const remoteConflictRangesState = shallowRef<ConflictRange[]>([])\n const lastNavigatedConflictIndex = ref<number>(-1)\n\n const localChangesEditor = shallowRef<monaco.editor.IStandaloneDiffEditor>()\n const remoteChangesEditor = shallowRef<monaco.editor.IStandaloneDiffEditor>()\n const resultEditor = shallowRef<monaco.editor.IStandaloneDiffEditor>()\n\n let resultCodeLensProviderDisposable: monaco.IDisposable | undefined\n let jsonPointerLinkSupportDispose: (() => void) | undefined\n const codeLensCommandDisposables: monaco.IDisposable[] = []\n /** Models created in init(); disposed in dispose() to avoid leaks when the sync conflict modal closes. */\n let modelsToDispose: monaco.editor.ITextModel[] = []\n\n const normalizeConflicts = computed(() => {\n const conflictList = toValue(conflicts)\n return conflictList.map((conflict) => {\n // Conflict tuples follow the workspace-store convention emitted by\n // `rebaseDocument`: `[changelogIncoming, changelogLocal]` -\n // i.e. index 0 is the upstream/remote change and index 1 is the\n // local edit. Aligning here means every consumer of this hook\n // (the in-page Sync flow in `DocumentCollection.vue` and the\n // header Pull flow in `App.vue`) can pass `result.conflicts`\n // straight through without transposing.\n const remoteChanges = conflict[0]\n const localChanges = conflict[1]\n let smallestPath = localChanges[0]!.path\n for (const localChange of localChanges) {\n if (localChange.path.length < smallestPath.length) {\n smallestPath = localChange.path\n }\n }\n for (const remoteChange of remoteChanges) {\n if (remoteChange.path.length < smallestPath.length) {\n smallestPath = remoteChange.path\n }\n }\n return {\n local: {\n path: smallestPath,\n changes: localChanges,\n type: localChanges[0]!.type,\n },\n remote: {\n path: smallestPath,\n changes: remoteChanges,\n type: remoteChanges[0]!.type,\n },\n }\n })\n })\n\n // Pane previews follow the same `[remote, local]` tuple convention as\n // `normalizeConflicts` above: index 0 is the upstream change set, so\n // `documentWithRemoteChanges` reads from `it[0]` and the local /\n // \"Current\" pane reads from `it[1]`.\n const documentWithRemoteChanges = computed(() =>\n apply(\n deepClone(toValue(resolvedDocument)),\n toValue(conflicts).flatMap((it) => it[0]),\n ),\n )\n\n const documentWithLocalChanges = computed(() =>\n apply(\n deepClone(toValue(resolvedDocument)),\n toValue(conflicts).flatMap((it) => it[1]),\n ),\n )\n\n const conflictsLeft = computed(() => resolvedConflicts.value.filter((status) => status === 'idle').length)\n\n watch(\n normalizeConflicts,\n (nextConflicts) => {\n resolvedConflicts.value = nextConflicts.map((_, index) => resolvedConflicts.value[index] ?? 'idle')\n },\n { immediate: true },\n )\n\n const focusEditorRange = (\n diffEditor: monaco.editor.IStandaloneDiffEditor | undefined,\n range: monaco.Range | undefined,\n ): void => {\n if (!diffEditor || !range) {\n return\n }\n const modifiedEditor = diffEditor.getModifiedEditor()\n const safeRange = new monaco.Range(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn)\n modifiedEditor.setSelection(safeRange)\n modifiedEditor.revealRangeNearTop(safeRange)\n }\n\n const goToNextConflict = (): void => {\n const unresolvedConflictIndexes = normalizeConflicts.value\n .map((_, index) => index)\n .filter((index) => resolvedConflicts.value[index] === 'idle')\n if (!unresolvedConflictIndexes.length) {\n return\n }\n const nextConflictIndex =\n unresolvedConflictIndexes.find((index) => index > lastNavigatedConflictIndex.value) ??\n unresolvedConflictIndexes[0]\n if (nextConflictIndex === undefined) {\n return\n }\n const nextConflict = normalizeConflicts.value[nextConflictIndex]\n if (!nextConflict) {\n return\n }\n const localRange = localConflictRangesState.value.find((cr) => cr.index === nextConflictIndex)?.range\n const remoteRange = remoteConflictRangesState.value.find((cr) => cr.index === nextConflictIndex)?.range\n const resultRange = conflictRangesState.value.find((cr) => cr.index === nextConflictIndex)?.range\n focusEditorRange(localChangesEditor.value, localRange)\n focusEditorRange(remoteChangesEditor.value, remoteRange)\n focusEditorRange(resultEditor.value, resultRange)\n resultEditor.value?.getModifiedEditor().focus()\n lastNavigatedConflictIndex.value = nextConflictIndex\n }\n\n const applyResolvedConflicts = (): void => {\n if (conflictsLeft.value > 0) {\n onError?.('You have conflicts left')\n return\n }\n const modifiedResultModel = resultEditor.value?.getModel()?.modified\n if (!modifiedResultModel) {\n return\n }\n let nextResolvedDocument: Record<string, unknown> | null = null\n try {\n nextResolvedDocument = JSON.parse(modifiedResultModel.getValue()) as Record<string, unknown>\n } catch {\n onError?.('You have formatting errors')\n return\n }\n onApplyChanges(nextResolvedDocument)\n }\n\n const init = (containers: ThreeWayMergeEditorContainers): void => {\n const base = toValue(baseDocument)\n const resolved = toValue(resolvedDocument)\n const localDoc = documentWithLocalChanges.value\n const remoteDoc = documentWithRemoteChanges.value\n\n const originalModelLocal = monaco.editor.createModel(JSON.stringify(resolved, null, 2), 'json')\n const modifiedModelLocal = createJsonModel(JSON.stringify(localDoc, null, 2))\n\n const originalModelRemote = monaco.editor.createModel(JSON.stringify(resolved, null, 2), 'json')\n const modifiedModelRemote = createJsonModel(JSON.stringify(remoteDoc, null, 2))\n\n const originalResultModel = monaco.editor.createModel(JSON.stringify(base, null, 2), 'json')\n const modifiedResultModel = createJsonModel(JSON.stringify(resolved, null, 2))\n\n modelsToDispose = [\n originalModelLocal,\n modifiedModelLocal.model,\n originalModelRemote,\n modifiedModelRemote.model,\n originalResultModel,\n modifiedResultModel.model,\n ]\n\n const localDiffEditor = monaco.editor.createDiffEditor(containers.local, {\n originalEditable: false,\n readOnly: true,\n automaticLayout: true,\n renderSideBySide: false,\n })\n localDiffEditor.setModel({\n original: originalModelLocal,\n modified: modifiedModelLocal.model,\n })\n localChangesEditor.value = localDiffEditor\n\n const remoteDiffEditor = monaco.editor.createDiffEditor(containers.remote, {\n originalEditable: false,\n readOnly: true,\n automaticLayout: true,\n renderSideBySide: false,\n })\n remoteDiffEditor.setModel({\n original: originalModelRemote,\n modified: modifiedModelRemote.model,\n })\n remoteChangesEditor.value = remoteDiffEditor\n\n const resultDiffEditor = monaco.editor.createDiffEditor(containers.result, {\n originalEditable: false,\n readOnly: false,\n renderSideBySide: false,\n automaticLayout: true,\n })\n resultDiffEditor.setModel({\n original: originalResultModel,\n modified: modifiedResultModel.model,\n })\n const resultModifiedEditor = resultDiffEditor.getModifiedEditor()\n resultModifiedEditor.updateOptions({ codeLens: true })\n\n const focusResultPath = async (path: Path): Promise<void> => {\n const range = await modifiedResultModel.getRangeFromPath(path)\n if (!range) {\n return\n }\n const safeRange = new monaco.Range(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn)\n resultModifiedEditor.setSelection(safeRange)\n resultModifiedEditor.revealRangeNearTop(safeRange)\n }\n\n const navigateJsonPointer = async (pointer: string): Promise<void> => {\n const path = parseJsonPointerPath(pointer)\n if (!path) {\n return\n }\n await focusResultPath(path)\n }\n\n const linkSupport = ensureJsonPointerLinkSupport(navigateJsonPointer)\n jsonPointerLinkSupportDispose = linkSupport.dispose\n\n let resultHighlightDecorations: string[] = []\n let suppressedChangeEvents = 0\n\n const applyCurrentCodeLensCommandId = 'scalar.conflict.applyCurrent'\n const applyRemoteCodeLensCommandId = 'scalar.conflict.applyRemote'\n const ignoreCodeLensCommandId = 'scalar.conflict.ignore'\n const noOpCodeLensCommandId = resultModifiedEditor.addCommand(0, () => undefined) ?? 'scalar.conflict.status.noop'\n\n const getBoxDecorationsForRange = (range: monaco.Range): monaco.editor.IModelDeltaDecoration[] => {\n const startLine = range.startLineNumber\n const endLine = range.endLineNumber\n if (startLine === endLine) {\n return [\n {\n range,\n options: {\n isWholeLine: true,\n className: 'json-focus-highlight-box-single',\n },\n },\n ]\n }\n const topRange = new monaco.Range(startLine, 1, startLine, range.endColumn)\n const middleRange = new monaco.Range(startLine + 1, 1, Math.max(startLine + 1, endLine - 1), 1)\n const bottomRange = new monaco.Range(endLine, 1, endLine, range.endColumn)\n const decorations: monaco.editor.IModelDeltaDecoration[] = [\n {\n range: topRange,\n options: {\n isWholeLine: true,\n className: 'json-focus-highlight-box-top',\n },\n },\n {\n range: bottomRange,\n options: {\n isWholeLine: true,\n className: 'json-focus-highlight-box-bottom',\n },\n },\n ]\n if (endLine - startLine > 1) {\n decorations.push({\n range: middleRange,\n options: {\n isWholeLine: true,\n className: 'json-focus-highlight-box-middle',\n },\n })\n }\n return decorations\n }\n\n const refreshCodeLensProvider = (): void => {\n resultCodeLensProviderDisposable?.dispose()\n resultCodeLensProviderDisposable = monaco.languages.registerCodeLensProvider('json', {\n provideCodeLenses: (model) => {\n if (model.uri.toString() !== modifiedResultModel.model.uri.toString()) {\n return { lenses: [], dispose: () => undefined }\n }\n return {\n lenses: conflictRangesState.value.flatMap((conflictRange) => {\n const lensRange = new monaco.Range(\n conflictRange.range.startLineNumber,\n 1,\n conflictRange.range.startLineNumber,\n 1,\n )\n return [\n {\n range: lensRange,\n command: {\n id: noOpCodeLensCommandId,\n title: `Status: ${resolvedConflicts.value[conflictRange.index] ?? 'idle'}`,\n },\n },\n {\n range: lensRange,\n command: {\n id: applyCurrentCodeLensCommandId,\n title: 'Accept Current',\n arguments: [conflictRange.index],\n },\n },\n {\n range: lensRange,\n command: {\n id: applyRemoteCodeLensCommandId,\n title: 'Accept Remote',\n arguments: [conflictRange.index],\n },\n },\n {\n range: lensRange,\n command: {\n id: ignoreCodeLensCommandId,\n title: 'Ignore',\n arguments: [conflictRange.index],\n },\n },\n ]\n }),\n dispose: () => undefined,\n }\n },\n })\n }\n\n const getConflictRange = async (\n editorModel: EditorModel,\n index: number,\n path: string[],\n ): Promise<ConflictRange> => {\n const { model } = editorModel\n const fallbackRange = new monaco.Range(1, 1, 1, model.getLineMaxColumn(1))\n let range: monaco.Range | null = null\n for (let depth = path.length; depth >= 0; depth -= 1) {\n const candidatePath = path.slice(0, depth)\n const nodeRange = await editorModel.getRangeFromPath(candidatePath)\n if (!nodeRange) {\n continue\n }\n range = rangeToWholeLine(model, nodeRange)\n break\n }\n return {\n index,\n path,\n range: markRaw(range ?? fallbackRange),\n }\n }\n\n const refreshConflictRangesAndDecorations = async (): Promise<void> => {\n const [resultRanges, localRanges, remoteRanges] = await Promise.all([\n Promise.all(\n normalizeConflicts.value.map((conflict, index) =>\n getConflictRange(modifiedResultModel, index, conflict.local.path),\n ),\n ),\n Promise.all(\n normalizeConflicts.value.map((conflict, index) =>\n getConflictRange(modifiedModelLocal, index, conflict.local.path),\n ),\n ),\n Promise.all(\n normalizeConflicts.value.map((conflict, index) =>\n getConflictRange(modifiedModelRemote, index, conflict.local.path),\n ),\n ),\n ])\n conflictRangesState.value = resultRanges.filter((r): r is ConflictRange => Boolean(r))\n localConflictRangesState.value = localRanges.filter((r): r is ConflictRange => Boolean(r))\n remoteConflictRangesState.value = remoteRanges.filter((r): r is ConflictRange => Boolean(r))\n resultHighlightDecorations = resultModifiedEditor.deltaDecorations(\n resultHighlightDecorations,\n conflictRangesState.value.flatMap((cr) => getBoxDecorationsForRange(cr.range)),\n )\n refreshCodeLensProvider()\n }\n\n const setConflictResolution = (index: number, resolution: ConflictResolutionState): void => {\n resolvedConflicts.value[index] = resolution\n refreshCodeLensProvider()\n }\n\n const applyConflictChoice = async (index: number, source: 'local' | 'remote'): Promise<void> => {\n const conflict = normalizeConflicts.value[index]\n if (!conflict) {\n return\n }\n let currentDocument: Record<string, unknown> | null = null\n try {\n currentDocument = JSON.parse(modifiedResultModel.model.getValue()) as Record<string, unknown>\n } catch {\n return\n }\n const changes = source === 'local' ? conflict.local.changes : conflict.remote.changes\n const nextDocument = apply(deepClone(currentDocument), changes)\n suppressedChangeEvents += 1\n modifiedResultModel.model.setValue(JSON.stringify(nextDocument, null, 2))\n setConflictResolution(index, source)\n await refreshConflictRangesAndDecorations()\n }\n\n codeLensCommandDisposables.push(\n monaco.editor.registerCommand(applyCurrentCodeLensCommandId, (_accessor, index: number) => {\n void applyConflictChoice(index, 'local')\n }),\n )\n codeLensCommandDisposables.push(\n monaco.editor.registerCommand(applyRemoteCodeLensCommandId, (_accessor, index: number) => {\n void applyConflictChoice(index, 'remote')\n }),\n )\n codeLensCommandDisposables.push(\n monaco.editor.registerCommand(ignoreCodeLensCommandId, (_accessor, index: number) => {\n setConflictResolution(index, 'ignore')\n }),\n )\n\n void refreshConflictRangesAndDecorations()\n\n resultModifiedEditor.onDidChangeModelContent((event) => {\n if (suppressedChangeEvents > 0) {\n suppressedChangeEvents -= 1\n return\n }\n let hasStatusUpdates = false\n for (const change of event.changes) {\n const matchingConflicts = conflictRangesState.value.filter((cr) =>\n monaco.Range.areIntersectingOrTouching(change.range, cr.range),\n )\n if (!matchingConflicts.length) {\n continue\n }\n matchingConflicts.forEach((conflict) => {\n if (resolvedConflicts.value[conflict.index] !== 'manual') {\n resolvedConflicts.value[conflict.index] = 'manual'\n hasStatusUpdates = true\n }\n })\n }\n if (hasStatusUpdates) {\n refreshCodeLensProvider()\n }\n })\n\n resultEditor.value = resultDiffEditor\n }\n\n const dispose = (): void => {\n localChangesEditor.value?.dispose()\n localChangesEditor.value = undefined\n remoteChangesEditor.value?.dispose()\n remoteChangesEditor.value = undefined\n resultEditor.value?.dispose()\n resultEditor.value = undefined\n\n for (const model of modelsToDispose) {\n model.dispose()\n }\n modelsToDispose = []\n\n resultCodeLensProviderDisposable?.dispose()\n resultCodeLensProviderDisposable = undefined\n jsonPointerLinkSupportDispose?.()\n jsonPointerLinkSupportDispose = undefined\n codeLensCommandDisposables.forEach((d) => d.dispose())\n codeLensCommandDisposables.length = 0\n }\n\n return {\n init,\n dispose,\n conflictsLeft,\n goToNextConflict,\n applyResolvedConflicts,\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"is-url.d.ts","sourceRoot":"","sources":["../../../src/v2/helpers/is-url.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,KAAK,GAAI,OAAO,MAAM,YAElC,CAAA"}
1
+ {"version":3,"file":"is-url.d.ts","sourceRoot":"","sources":["../../../src/v2/helpers/is-url.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,KAAK,GAAI,OAAO,MAAM,YAIlC,CAAA"}
@@ -1,7 +1,8 @@
1
1
  import { isValidUrl } from "@scalar/helpers/url/is-valid-url";
2
2
  //#region src/v2/helpers/is-url.ts
3
3
  var isUrl = (input) => {
4
- return (input.startsWith("http://") || input.startsWith("https://")) && isValidUrl(input);
4
+ const trimmedInput = input.trim();
5
+ return (trimmedInput.startsWith("http://") || trimmedInput.startsWith("https://")) && isValidUrl(trimmedInput);
5
6
  };
6
7
  //#endregion
7
8
  export { isUrl };
@@ -1 +1 @@
1
- {"version":3,"file":"is-url.js","names":[],"sources":["../../../src/v2/helpers/is-url.ts"],"sourcesContent":["import { isValidUrl } from '@scalar/helpers/url/is-valid-url'\n\nexport const isUrl = (input: string) => {\n return (input.startsWith('http://') || input.startsWith('https://')) && isValidUrl(input)\n}\n"],"mappings":";;AAEA,IAAa,SAAS,UAAkB;AACtC,SAAQ,MAAM,WAAW,UAAU,IAAI,MAAM,WAAW,WAAW,KAAK,WAAW,MAAM"}
1
+ {"version":3,"file":"is-url.js","names":[],"sources":["../../../src/v2/helpers/is-url.ts"],"sourcesContent":["import { isValidUrl } from '@scalar/helpers/url/is-valid-url'\n\nexport const isUrl = (input: string) => {\n const trimmedInput = input.trim()\n\n return (trimmedInput.startsWith('http://') || trimmedInput.startsWith('https://')) && isValidUrl(trimmedInput)\n}\n"],"mappings":";;AAEA,IAAa,SAAS,UAAkB;CACtC,MAAM,eAAe,MAAM,MAAM;AAEjC,SAAQ,aAAa,WAAW,UAAU,IAAI,aAAa,WAAW,WAAW,KAAK,WAAW,aAAa"}
@@ -1,12 +1,278 @@
1
- export type ImportDocumentFromRegistry = (meta: {
1
+ import type { Result } from '@scalar/helpers/types/result';
2
+ /**
3
+ * Coordinates that uniquely identify a registry-backed document. Both the
4
+ * fetch and publish APIs operate on these so callers can compose a single
5
+ * meta object once and pass it around.
6
+ */
7
+ export type RegistryDocumentMeta = {
2
8
  namespace: string;
3
9
  slug: string;
4
10
  version?: string;
5
- }) => Promise<{
6
- ok: true;
7
- data: Record<string, unknown>;
11
+ };
12
+ /**
13
+ * Error codes surfaced by `fetchDocument`. Errors are returned as a
14
+ * discriminated union so callers can react to each failure mode without
15
+ * having to parse free-form strings:
16
+ *
17
+ * - `NOT_FOUND`: the registry has no document at the requested
18
+ * namespace / slug / version. Usually a sign that the version was
19
+ * removed upstream or the caller is asking for a draft that does not
20
+ * exist yet.
21
+ * - `FETCH_FAILED`: a network or server error prevented the fetch from
22
+ * completing. The request can usually be retried.
23
+ * - `UNAUTHORIZED`: the caller is not signed in / not allowed to read
24
+ * from this namespace. The host application is expected to surface a
25
+ * sign-in flow.
26
+ * - `UNKNOWN`: a catch-all for failure modes the adapter cannot map
27
+ * onto one of the dedicated codes above. Callers surface a generic
28
+ * error message and, when present, the human-readable `message`
29
+ * field returned alongside the code.
30
+ */
31
+ export type FetchRegistryDocumentError = 'NOT_FOUND' | 'FETCH_FAILED' | 'UNAUTHORIZED' | 'UNKNOWN';
32
+ /**
33
+ * Fetches the full document from the registry by meta. When a `registry`
34
+ * adapter is wired up, registry meta takes priority over
35
+ * `x-scalar-original-source-url` when syncing. Returns the document as a
36
+ * plain object on success, or a discriminated `FetchRegistryDocumentError`
37
+ * code (with an optional human-readable `message`) on failure.
38
+ */
39
+ export type ImportDocumentFromRegistry = (meta: RegistryDocumentMeta) => Promise<Result<{
40
+ document: Record<string, unknown>;
41
+ versionSha?: string;
42
+ }, FetchRegistryDocumentError>>;
43
+ /**
44
+ * Error codes surfaced by `publishDocument`. Errors are returned as a
45
+ * discriminated union so callers can react to each failure mode without
46
+ * having to parse free-form strings:
47
+ *
48
+ * - `CONFLICT`: the namespace/slug is already taken on the registry.
49
+ * Resolve by picking a new slug or pulling the upstream version.
50
+ * - `FETCH_FAILED`: a network or server error prevented the publish from
51
+ * completing. The request can usually be retried.
52
+ * - `UNAUTHORIZED`: the caller is not signed in / not allowed to publish
53
+ * to this namespace. The host application is expected to surface a
54
+ * sign-in flow.
55
+ * - `UNKNOWN`: a catch-all for failure modes the adapter cannot map
56
+ * onto one of the dedicated codes above. Callers surface a generic
57
+ * error message and, when present, the human-readable `message`
58
+ * field returned alongside the code.
59
+ */
60
+ export type PublishRegistryDocumentError = 'CONFLICT' | 'FETCH_FAILED' | 'UNAUTHORIZED' | 'UNKNOWN';
61
+ /**
62
+ * Discriminated outcome of a `publishDocument` call.
63
+ */
64
+ export type PublishRegistryDocumentResult = Result<RegistryDocumentMeta & {
65
+ /** Commit hash advertised by the registry for the published version. */
66
+ commitHash?: string;
67
+ }, PublishRegistryDocumentError>;
68
+ /**
69
+ * Publishes a brand-new document to the registry under the given
70
+ * namespace and slug. Used for team-workspace documents that do not yet
71
+ * have a registry entry - subsequent sync flows then go through the
72
+ * Pull / Push pair once the registry has assigned a commit hash.
73
+ *
74
+ * The caller also chooses the document's initial `version` and passes
75
+ * the full document body. The local workspace mirrors the same string
76
+ * on `info.version` after a successful publish so the document and the
77
+ * registry stay in sync without a follow-up edit.
78
+ */
79
+ export type PublishRegistryDocument = (input: {
80
+ namespace: string;
81
+ slug: string;
82
+ /** Initial version the document is published under (e.g. `1.0.0`). */
83
+ version: string;
84
+ /**
85
+ * Full OpenAPI document body to seed the registry entry with. The
86
+ * caller is expected to apply the chosen `version` to `info.version`
87
+ * before passing the document so the registry stores a consistent
88
+ * snapshot.
89
+ */
90
+ document: Record<string, unknown>;
91
+ }) => Promise<PublishRegistryDocumentResult>;
92
+ /**
93
+ * Error codes surfaced by `publishVersion`. Errors are returned as a
94
+ * discriminated union so callers can react to each failure mode without
95
+ * having to parse free-form strings:
96
+ *
97
+ * - `CONFLICT`: the registry's current commit hash for this version no
98
+ * longer matches the one the caller passed in. Somebody pushed in the
99
+ * meantime - the caller is expected to pull the upstream changes,
100
+ * resolve any merge conflicts and try again.
101
+ * - `NOT_FOUND`: the registry has no document at this namespace / slug
102
+ * to publish a new version against. Use `publishDocument` instead to
103
+ * create the document group first.
104
+ * - `FETCH_FAILED`: a network or server error prevented the publish
105
+ * from completing. The request can usually be retried.
106
+ * - `UNAUTHORIZED`: the caller is not signed in / not allowed to
107
+ * publish to this namespace. The host application is expected to
108
+ * surface a sign-in flow.
109
+ * - `UNKNOWN`: a catch-all for failure modes the adapter cannot map
110
+ * onto one of the dedicated codes above. Callers surface a generic
111
+ * error message and, when present, the human-readable `message`
112
+ * field returned alongside the code.
113
+ */
114
+ export type PublishRegistryVersionError = 'CONFLICT' | 'NOT_FOUND' | 'FETCH_FAILED' | 'UNAUTHORIZED' | 'UNKNOWN';
115
+ /**
116
+ * Discriminated outcome of a `publishVersion` call. On success the
117
+ * registry returns the new commit hash so the caller can persist it on
118
+ * `x-scalar-registry-meta` and detect upstream drift on subsequent
119
+ * refreshes.
120
+ */
121
+ export type PublishRegistryVersionResult = Result<RegistryDocumentMeta & {
122
+ /** Commit hash advertised by the registry for the published version. */
123
+ commitHash?: string;
124
+ }, PublishRegistryVersionError>;
125
+ /**
126
+ * Publishes a new version of an existing registry document. Pairs with
127
+ * `publishDocument` (which creates the document group itself) and is
128
+ * what the team-workspace "Push" flow ultimately calls once the user
129
+ * has saved local edits.
130
+ *
131
+ * The caller passes the `commitHash` it currently has locally so the
132
+ * registry can do optimistic concurrency: if the upstream hash has
133
+ * moved on, the publish is rejected with `CONFLICT` and the caller is
134
+ * expected to pull the latest version before retrying.
135
+ */
136
+ export type PublishRegistryVersion = (input: {
137
+ namespace: string;
138
+ slug: string;
139
+ /** Version identifier the caller is publishing (e.g. `1.2.0`). */
140
+ version: string;
141
+ /**
142
+ * Full OpenAPI document body that should become the new state on the
143
+ * registry for this `version`. Mirrors the input shape of
144
+ * `publishDocument` so adapters can share the same upload helper.
145
+ */
146
+ document: Record<string, unknown>;
147
+ /**
148
+ * Commit hash the caller currently believes is the latest one for
149
+ * this `version`. The registry compares this against its own current
150
+ * hash and rejects the publish with `CONFLICT` when they no longer
151
+ * match, preventing accidental overwrites of upstream changes.
152
+ */
153
+ commitHash?: string;
154
+ }) => Promise<PublishRegistryVersionResult>;
155
+ /**
156
+ * A single version that the registry advertises for a document group.
157
+ *
158
+ * Mirrors the minimum surface the sidebar needs to render a version row
159
+ * (the version label and an optional commit hash). Loaded vs unloaded
160
+ * state is derived later by matching against workspace-store documents.
161
+ */
162
+ export type RegistryDocumentVersion = {
163
+ version: string;
164
+ commitHash?: string;
165
+ };
166
+ /**
167
+ * A document group as advertised by the registry, before it is merged
168
+ * with locally loaded workspace documents. Lives at the configuration
169
+ * layer so consumers can produce these without depending on internal
170
+ * sidebar hooks.
171
+ */
172
+ export type RegistryDocument = {
173
+ namespace: string;
174
+ slug: string;
175
+ title: string;
176
+ versions: RegistryDocumentVersion[];
177
+ };
178
+ /**
179
+ * Loading-aware wrapper for the list of registry documents.
180
+ *
181
+ * The sidebar uses the `status` to decide whether to render skeleton
182
+ * placeholders while the registry is being fetched. `documents` is
183
+ * optional during loading so callers can either render nothing or stream
184
+ * in cached results while a refresh is still in flight.
185
+ */
186
+ export type RegistryDocumentsState = {
187
+ status: 'loading';
188
+ documents?: RegistryDocument[];
189
+ } | {
190
+ status: 'success';
191
+ documents: RegistryDocument[];
192
+ };
193
+ /**
194
+ * A namespace under which the user is allowed to publish documents.
195
+ *
196
+ * The publish modal renders one entry per namespace - as a static label
197
+ * when there is only one, or as a dropdown otherwise - so callers can
198
+ * surface the personal account, organisations, teams, etc. the user
199
+ * has access to.
200
+ */
201
+ export type RegistryNamespace = {
202
+ /** Stable namespace identifier passed back to publish callbacks. */
203
+ namespace: string;
204
+ /** Optional human-readable label. Falls back to `namespace` when omitted. */
205
+ title?: string;
206
+ };
207
+ /**
208
+ * Loading-aware wrapper for the list of namespaces the user can publish
209
+ * to. Mirrors {@link RegistryDocumentsState} so the publish modal can
210
+ * render a skeleton row while the host application is still resolving
211
+ * the user's memberships.
212
+ */
213
+ export type RegistryNamespacesState = {
214
+ status: 'loading';
215
+ namespaces?: RegistryNamespace[];
8
216
  } | {
9
- ok: false;
10
- error: string;
11
- }>;
217
+ status: 'success';
218
+ namespaces: RegistryNamespace[];
219
+ };
220
+ /**
221
+ * Bundles every interaction the API client needs with an external
222
+ * registry. Consumers (Scalar Cloud, custom self-hosted setups) provide
223
+ * a single adapter object instead of wiring each callback up
224
+ * individually. The adapter itself is optional at the top level of the
225
+ * client - omit it to opt out of registry features entirely - but every
226
+ * field inside the adapter is required when it is provided.
227
+ */
228
+ export type RegistryAdapter = {
229
+ /**
230
+ * Reactive list of all available registry documents with a loading
231
+ * status, used by the sidebar to render skeleton placeholders until
232
+ * the real list is ready.
233
+ */
234
+ documents: RegistryDocumentsState;
235
+ /**
236
+ * Reactive list of namespaces the user can publish into. The publish
237
+ * modal uses it to show a single-line label (one namespace) or a
238
+ * dropdown (multiple namespaces) and falls back to a skeleton while
239
+ * the listing is still loading.
240
+ */
241
+ namespaces: RegistryNamespacesState;
242
+ /**
243
+ * Fetches the full document from the registry by meta. When provided,
244
+ * registry meta takes priority over `x-scalar-original-source-url`
245
+ * when syncing.
246
+ */
247
+ fetchDocument: ImportDocumentFromRegistry;
248
+ /**
249
+ * Publishes a brand-new document to the registry under the given
250
+ * namespace and slug. Returns a discriminated `Result` so callers can
251
+ * branch on `CONFLICT` / `FETCH_FAILED` / `UNAUTHORIZED` without
252
+ * string-matching error messages.
253
+ */
254
+ publishDocument: PublishRegistryDocument;
255
+ /**
256
+ * Publishes a new version of an existing registry document. The
257
+ * caller passes the `commitHash` it currently has locally so the
258
+ * registry can do optimistic concurrency and reject the publish with
259
+ * `CONFLICT` when the upstream hash has moved on.
260
+ */
261
+ publishVersion: PublishRegistryVersion;
262
+ /**
263
+ * Forces the host application to refetch `documents` and resolves once
264
+ * the new listing is in hand.
265
+ *
266
+ * Used by the sync flow to invalidate the host's listing cache after a
267
+ * `CONFLICT` push: the rejection means the registry has a newer
268
+ * commit hash than our local listing knows about, so refreshing the
269
+ * listing lets `computeVersionStatus` notice the mismatch and flip the
270
+ * Pull button on naturally - without the hook having to track its own
271
+ * "needs pull" overlay state.
272
+ *
273
+ * Optional so existing adapters keep type-checking; the sync flow
274
+ * silently no-ops when it is missing.
275
+ */
276
+ refreshDocuments?: () => Promise<void>;
277
+ };
12
278
  //# sourceMappingURL=configuration.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"configuration.d.ts","sourceRoot":"","sources":["../../../src/v2/types/configuration.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,0BAA0B,GAAG,CAAC,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,OAAO,CAC7G;IACE,EAAE,EAAE,IAAI,CAAA;IACR,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC9B,GACD;IACE,EAAE,EAAE,KAAK,CAAA;IACT,KAAK,EAAE,MAAM,CAAA;CACd,CACJ,CAAA"}
1
+ {"version":3,"file":"configuration.d.ts","sourceRoot":"","sources":["../../../src/v2/types/configuration.ts"],"names":[],"mappings":"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"}