@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.
- package/CHANGELOG.md +24 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/style.css +3933 -4768
- package/dist/styles/tailwind.config.css +20 -0
- package/dist/styles/utilities.css +45 -0
- package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.d.ts.map +1 -1
- package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.js +1 -1
- package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.js.map +1 -1
- package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.script.js +1 -1
- package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.script.js.map +1 -1
- package/dist/v2/blocks/request-block/RequestBlock.vue.script.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.script.js.map +1 -1
- package/dist/v2/components/data-table/DataTableInput.vue.d.ts +1 -1
- package/dist/v2/components/data-table/DataTableInput.vue.d.ts.map +1 -1
- package/dist/v2/constants.js +1 -1
- package/dist/v2/features/app/App.vue.d.ts +15 -31
- package/dist/v2/features/app/App.vue.d.ts.map +1 -1
- package/dist/v2/features/app/App.vue.js.map +1 -1
- package/dist/v2/features/app/App.vue.script.js +131 -50
- package/dist/v2/features/app/App.vue.script.js.map +1 -1
- package/dist/v2/features/app/app-state.d.ts +10 -14
- package/dist/v2/features/app/app-state.d.ts.map +1 -1
- package/dist/v2/features/app/app-state.js +53 -21
- package/dist/v2/features/app/app-state.js.map +1 -1
- package/dist/v2/features/app/components/AppHeader.vue.d.ts.map +1 -1
- package/dist/v2/features/app/components/AppHeader.vue.js.map +1 -1
- package/dist/v2/features/app/components/AppHeader.vue.script.js +4 -3
- package/dist/v2/features/app/components/AppHeader.vue.script.js.map +1 -1
- package/dist/v2/features/app/components/AppHeaderActions.vue.d.ts +32 -0
- package/dist/v2/features/app/components/AppHeaderActions.vue.d.ts.map +1 -0
- package/dist/v2/features/app/components/AppHeaderActions.vue.js +7 -0
- package/dist/v2/features/app/components/AppHeaderActions.vue.js.map +1 -0
- package/dist/v2/features/app/components/AppHeaderActions.vue.script.js +172 -0
- package/dist/v2/features/app/components/AppHeaderActions.vue.script.js.map +1 -0
- package/dist/v2/features/app/components/AppSidebar.vue.d.ts +2 -5
- package/dist/v2/features/app/components/AppSidebar.vue.d.ts.map +1 -1
- package/dist/v2/features/app/components/AppSidebar.vue.js +1 -1
- package/dist/v2/features/app/components/AppSidebar.vue.js.map +1 -1
- package/dist/v2/features/app/components/AppSidebar.vue.script.js +4 -9
- package/dist/v2/features/app/components/AppSidebar.vue.script.js.map +1 -1
- package/dist/v2/features/app/components/DesktopTabs.vue.d.ts.map +1 -1
- package/dist/v2/features/app/components/DesktopTabs.vue.js.map +1 -1
- package/dist/v2/features/app/components/DesktopTabs.vue.script.js +2 -2
- package/dist/v2/features/app/components/DesktopTabs.vue.script.js.map +1 -1
- package/dist/v2/features/app/components/DocumentBreadcrumb.vue.d.ts +1 -2
- package/dist/v2/features/app/components/DocumentBreadcrumb.vue.d.ts.map +1 -1
- package/dist/v2/features/app/components/DocumentBreadcrumb.vue.js +1 -1
- package/dist/v2/features/app/components/DocumentBreadcrumb.vue.js.map +1 -1
- package/dist/v2/features/app/components/DocumentBreadcrumb.vue.script.js +4 -35
- package/dist/v2/features/app/components/DocumentBreadcrumb.vue.script.js.map +1 -1
- package/dist/v2/features/app/components/DocumentSyncIndicator.vue.d.ts +1 -1
- package/dist/v2/features/app/components/DocumentSyncIndicator.vue.d.ts.map +1 -1
- package/dist/v2/features/app/components/PublishDocumentModal.vue.d.ts +77 -0
- package/dist/v2/features/app/components/PublishDocumentModal.vue.d.ts.map +1 -0
- package/dist/v2/features/app/components/PublishDocumentModal.vue.js +7 -0
- package/dist/v2/features/app/components/PublishDocumentModal.vue.js.map +1 -0
- package/dist/v2/features/app/components/PublishDocumentModal.vue.script.js +209 -0
- package/dist/v2/features/app/components/PublishDocumentModal.vue.script.js.map +1 -0
- package/dist/v2/features/app/components/SyncConflictResolutionEditor.vue.d.ts.map +1 -0
- package/dist/v2/features/{collection → app}/components/SyncConflictResolutionEditor.vue.js +2 -2
- package/dist/v2/features/app/components/SyncConflictResolutionEditor.vue.js.map +1 -0
- package/dist/v2/features/{collection → app}/components/SyncConflictResolutionEditor.vue.script.js +1 -1
- package/dist/v2/features/{collection/components/SyncConflictResolutionEditor.vue.js.map → app/components/SyncConflictResolutionEditor.vue.script.js.map} +1 -1
- package/dist/v2/features/app/helpers/check-version-conflict.d.ts +8 -5
- package/dist/v2/features/app/helpers/check-version-conflict.d.ts.map +1 -1
- package/dist/v2/features/app/helpers/check-version-conflict.js +10 -7
- package/dist/v2/features/app/helpers/check-version-conflict.js.map +1 -1
- package/dist/v2/features/app/helpers/create-api-client-app.d.ts +8 -5
- package/dist/v2/features/app/helpers/create-api-client-app.d.ts.map +1 -1
- package/dist/v2/features/app/helpers/create-api-client-app.js +2 -2
- package/dist/v2/features/app/helpers/create-api-client-app.js.map +1 -1
- package/dist/v2/features/app/helpers/load-registry-document.d.ts +1 -10
- package/dist/v2/features/app/helpers/load-registry-document.d.ts.map +1 -1
- package/dist/v2/features/app/helpers/load-registry-document.js +6 -5
- package/dist/v2/features/app/helpers/load-registry-document.js.map +1 -1
- package/dist/v2/features/app/helpers/registry-error-messages.d.ts +23 -0
- package/dist/v2/features/app/helpers/registry-error-messages.d.ts.map +1 -0
- package/dist/v2/features/app/helpers/registry-error-messages.js +63 -0
- package/dist/v2/features/app/helpers/registry-error-messages.js.map +1 -0
- package/dist/v2/features/app/hooks/use-active-document-version.d.ts +2 -1
- package/dist/v2/features/app/hooks/use-active-document-version.d.ts.map +1 -1
- package/dist/v2/features/app/hooks/use-active-document-version.js.map +1 -1
- package/dist/v2/features/app/hooks/use-document-sync.d.ts +126 -0
- package/dist/v2/features/app/hooks/use-document-sync.d.ts.map +1 -0
- package/dist/v2/features/app/hooks/use-document-sync.js +448 -0
- package/dist/v2/features/app/hooks/use-document-sync.js.map +1 -0
- package/dist/v2/features/app/hooks/use-network-status.d.ts +29 -0
- package/dist/v2/features/app/hooks/use-network-status.d.ts.map +1 -0
- package/dist/v2/features/app/hooks/use-network-status.js +58 -0
- package/dist/v2/features/app/hooks/use-network-status.js.map +1 -0
- package/dist/v2/features/app/hooks/use-sidebar-documents.d.ts +1 -25
- package/dist/v2/features/app/hooks/use-sidebar-documents.d.ts.map +1 -1
- package/dist/v2/features/app/hooks/use-sidebar-documents.js.map +1 -1
- package/dist/v2/features/app/index.d.ts +1 -1
- package/dist/v2/features/app/index.d.ts.map +1 -1
- package/dist/v2/features/collection/DocumentCollection.vue.d.ts.map +1 -1
- package/dist/v2/features/collection/DocumentCollection.vue.js.map +1 -1
- package/dist/v2/features/collection/DocumentCollection.vue.script.js +43 -277
- package/dist/v2/features/collection/DocumentCollection.vue.script.js.map +1 -1
- package/dist/v2/features/command-palette/components/CommandPaletteExample.vue.d.ts.map +1 -1
- package/dist/v2/features/command-palette/components/CommandPaletteExample.vue.js.map +1 -1
- package/dist/v2/features/command-palette/components/CommandPaletteExample.vue.script.js +35 -17
- package/dist/v2/features/command-palette/components/CommandPaletteExample.vue.script.js.map +1 -1
- package/dist/v2/features/command-palette/components/CommandPaletteImport.vue.d.ts.map +1 -1
- package/dist/v2/features/command-palette/components/CommandPaletteImport.vue.js.map +1 -1
- package/dist/v2/features/command-palette/components/CommandPaletteImport.vue.script.js +15 -13
- package/dist/v2/features/command-palette/components/CommandPaletteImport.vue.script.js.map +1 -1
- package/dist/v2/features/command-palette/components/CommandPaletteImportCurl.vue.d.ts.map +1 -1
- package/dist/v2/features/command-palette/components/CommandPaletteImportCurl.vue.js +1 -1
- package/dist/v2/features/command-palette/components/CommandPaletteImportCurl.vue.js.map +1 -1
- package/dist/v2/features/command-palette/components/CommandPaletteImportCurl.vue.script.js +51 -39
- package/dist/v2/features/command-palette/components/CommandPaletteImportCurl.vue.script.js.map +1 -1
- package/dist/v2/features/command-palette/components/CommandPaletteOpenApiDocument.vue.d.ts.map +1 -1
- package/dist/v2/features/command-palette/components/CommandPaletteOpenApiDocument.vue.js.map +1 -1
- package/dist/v2/features/command-palette/components/CommandPaletteOpenApiDocument.vue.script.js +30 -14
- package/dist/v2/features/command-palette/components/CommandPaletteOpenApiDocument.vue.script.js.map +1 -1
- package/dist/v2/features/command-palette/components/CommandPaletteRequest.vue.d.ts.map +1 -1
- package/dist/v2/features/command-palette/components/CommandPaletteRequest.vue.js.map +1 -1
- package/dist/v2/features/command-palette/components/CommandPaletteRequest.vue.script.js +44 -42
- package/dist/v2/features/command-palette/components/CommandPaletteRequest.vue.script.js.map +1 -1
- package/dist/v2/features/command-palette/components/CommandPaletteTag.vue.d.ts.map +1 -1
- package/dist/v2/features/command-palette/components/CommandPaletteTag.vue.js.map +1 -1
- package/dist/v2/features/command-palette/components/CommandPaletteTag.vue.script.js +33 -17
- package/dist/v2/features/command-palette/components/CommandPaletteTag.vue.script.js.map +1 -1
- package/dist/v2/features/command-palette/helpers/load-document-from-source.d.ts.map +1 -1
- package/dist/v2/features/command-palette/helpers/load-document-from-source.js +3 -2
- package/dist/v2/features/command-palette/helpers/load-document-from-source.js.map +1 -1
- package/dist/v2/features/editor/hooks/use-three-way-merge-editor.d.ts.map +1 -1
- package/dist/v2/features/editor/hooks/use-three-way-merge-editor.js +5 -5
- package/dist/v2/features/editor/hooks/use-three-way-merge-editor.js.map +1 -1
- package/dist/v2/helpers/is-url.d.ts.map +1 -1
- package/dist/v2/helpers/is-url.js +2 -1
- package/dist/v2/helpers/is-url.js.map +1 -1
- package/dist/v2/types/configuration.d.ts +273 -7
- package/dist/v2/types/configuration.d.ts.map +1 -1
- package/dist/vue-styles.css +1389 -0
- package/package.json +20 -14
- package/dist/v2/features/app/components/DocumentSyncIndicator.vue.js +0 -7
- package/dist/v2/features/app/components/DocumentSyncIndicator.vue.js.map +0 -1
- package/dist/v2/features/app/components/DocumentSyncIndicator.vue.script.js +0 -51
- package/dist/v2/features/app/components/DocumentSyncIndicator.vue.script.js.map +0 -1
- package/dist/v2/features/collection/components/SyncConflictResolutionEditor.vue.d.ts.map +0 -1
- package/dist/v2/features/collection/components/SyncConflictResolutionEditor.vue.script.js.map +0 -1
- /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,
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
-
}
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
10
|
-
|
|
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;
|
|
1
|
+
{"version":3,"file":"configuration.d.ts","sourceRoot":"","sources":["../../../src/v2/types/configuration.ts"],"names":[],"mappings":"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"}
|