@knpkv/confluence-to-markdown 0.5.0 → 0.7.0
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 +61 -0
- package/README.md +58 -14
- package/dist/AdfPlaceholders.d.ts +42 -0
- package/dist/AdfPlaceholders.d.ts.map +1 -0
- package/dist/AdfPlaceholders.js +547 -0
- package/dist/AdfPlaceholders.js.map +1 -0
- package/dist/AdfSchemaValidator.d.ts +37 -0
- package/dist/AdfSchemaValidator.d.ts.map +1 -0
- package/dist/AdfSchemaValidator.js +37 -0
- package/dist/AdfSchemaValidator.js.map +1 -0
- package/dist/AdfWalker.d.ts +39 -0
- package/dist/AdfWalker.d.ts.map +1 -0
- package/dist/AdfWalker.js +527 -0
- package/dist/AdfWalker.js.map +1 -0
- package/dist/AtlaskitTransformers.d.ts +35 -0
- package/dist/AtlaskitTransformers.d.ts.map +1 -0
- package/dist/AtlaskitTransformers.js +48 -0
- package/dist/AtlaskitTransformers.js.map +1 -0
- package/dist/Brand.d.ts +6 -6
- package/dist/Brand.d.ts.map +1 -1
- package/dist/Brand.js +8 -6
- package/dist/Brand.js.map +1 -1
- package/dist/ConfluenceAuth.d.ts +4 -4
- package/dist/ConfluenceAuth.d.ts.map +1 -1
- package/dist/ConfluenceAuth.js +15 -27
- package/dist/ConfluenceAuth.js.map +1 -1
- package/dist/ConfluenceClient.d.ts +4 -4
- package/dist/ConfluenceClient.d.ts.map +1 -1
- package/dist/ConfluenceClient.js +21 -14
- package/dist/ConfluenceClient.js.map +1 -1
- package/dist/ConfluenceConfig.d.ts +3 -3
- package/dist/ConfluenceConfig.d.ts.map +1 -1
- package/dist/ConfluenceConfig.js +13 -11
- package/dist/ConfluenceConfig.js.map +1 -1
- package/dist/ConfluenceError.d.ts +56 -4
- package/dist/ConfluenceError.d.ts.map +1 -1
- package/dist/ConfluenceError.js +30 -1
- package/dist/ConfluenceError.js.map +1 -1
- package/dist/GitService.d.ts +11 -3
- package/dist/GitService.d.ts.map +1 -1
- package/dist/GitService.js +19 -27
- package/dist/GitService.js.map +1 -1
- package/dist/LocalFileSystem.d.ts +3 -3
- package/dist/LocalFileSystem.d.ts.map +1 -1
- package/dist/LocalFileSystem.js +6 -6
- package/dist/LocalFileSystem.js.map +1 -1
- package/dist/MarkdownConverter.d.ts +16 -65
- package/dist/MarkdownConverter.d.ts.map +1 -1
- package/dist/MarkdownConverter.js +64 -85
- package/dist/MarkdownConverter.js.map +1 -1
- package/dist/Schemas.d.ts +128 -141
- package/dist/Schemas.d.ts.map +1 -1
- package/dist/Schemas.js +21 -23
- package/dist/Schemas.js.map +1 -1
- package/dist/SyncEngine.d.ts +8 -5
- package/dist/SyncEngine.d.ts.map +1 -1
- package/dist/SyncEngine.js +189 -113
- package/dist/SyncEngine.js.map +1 -1
- package/dist/bin.js +23 -35
- package/dist/bin.js.map +1 -1
- package/dist/commands/auth.d.ts +2 -14
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/auth.js +11 -16
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/clone.d.ts +4 -6
- package/dist/commands/clone.d.ts.map +1 -1
- package/dist/commands/clone.js +34 -32
- package/dist/commands/clone.js.map +1 -1
- package/dist/commands/delete.d.ts +2 -10
- package/dist/commands/delete.d.ts.map +1 -1
- package/dist/commands/delete.js +5 -4
- package/dist/commands/delete.js.map +1 -1
- package/dist/commands/errorHandler.d.ts +2 -1
- package/dist/commands/errorHandler.d.ts.map +1 -1
- package/dist/commands/errorHandler.js +22 -15
- package/dist/commands/errorHandler.js.map +1 -1
- package/dist/commands/fetch.d.ts +27 -0
- package/dist/commands/fetch.d.ts.map +1 -0
- package/dist/commands/fetch.js +48 -0
- package/dist/commands/fetch.js.map +1 -0
- package/dist/commands/git.d.ts +7 -10
- package/dist/commands/git.d.ts.map +1 -1
- package/dist/commands/git.js +6 -6
- package/dist/commands/git.js.map +1 -1
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +1 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/layers.d.ts +10 -9
- package/dist/commands/layers.d.ts.map +1 -1
- package/dist/commands/layers.js +41 -30
- package/dist/commands/layers.js.map +1 -1
- package/dist/commands/new.d.ts +2 -6
- package/dist/commands/new.d.ts.map +1 -1
- package/dist/commands/new.js +5 -4
- package/dist/commands/new.js.map +1 -1
- package/dist/commands/pageInput.d.ts +19 -0
- package/dist/commands/pageInput.d.ts.map +1 -0
- package/dist/commands/pageInput.js +68 -0
- package/dist/commands/pageInput.js.map +1 -0
- package/dist/commands/root.d.ts +8 -0
- package/dist/commands/root.d.ts.map +1 -0
- package/dist/commands/root.js +29 -0
- package/dist/commands/root.js.map +1 -0
- package/dist/commands/sync.d.ts +6 -9
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +5 -6
- package/dist/commands/sync.js.map +1 -1
- package/dist/index.d.ts +3 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -13
- package/dist/index.js.map +1 -1
- package/dist/internal/NodeLayers.d.ts.map +1 -1
- package/dist/internal/NodeLayers.js +1 -2
- package/dist/internal/NodeLayers.js.map +1 -1
- package/dist/internal/adfMetadata.d.ts +30 -0
- package/dist/internal/adfMetadata.d.ts.map +1 -0
- package/dist/internal/adfMetadata.js +126 -0
- package/dist/internal/adfMetadata.js.map +1 -0
- package/dist/internal/cleanMarkdown.d.ts +5 -0
- package/dist/internal/cleanMarkdown.d.ts.map +1 -0
- package/dist/internal/cleanMarkdown.js +13 -0
- package/dist/internal/cleanMarkdown.js.map +1 -0
- package/dist/internal/frontmatter.d.ts.map +1 -1
- package/dist/internal/frontmatter.js +41 -8
- package/dist/internal/frontmatter.js.map +1 -1
- package/dist/internal/gitCommands.d.ts +9 -3
- package/dist/internal/gitCommands.d.ts.map +1 -1
- package/dist/internal/gitCommands.js +18 -9
- package/dist/internal/gitCommands.js.map +1 -1
- package/dist/internal/hashUtils.d.ts +1 -1
- package/dist/internal/hashUtils.d.ts.map +1 -1
- package/dist/internal/hashUtils.js +1 -1
- package/dist/internal/hashUtils.js.map +1 -1
- package/dist/internal/oauthServer.d.ts +10 -5
- package/dist/internal/oauthServer.d.ts.map +1 -1
- package/dist/internal/oauthServer.js +19 -40
- package/dist/internal/oauthServer.js.map +1 -1
- package/dist/internal/pathUtils.d.ts +1 -1
- package/dist/internal/pathUtils.d.ts.map +1 -1
- package/dist/internal/pathUtils.js +1 -1
- package/dist/internal/pathUtils.js.map +1 -1
- package/dist/internal/process.d.ts +15 -0
- package/dist/internal/process.d.ts.map +1 -0
- package/dist/internal/process.js +10 -0
- package/dist/internal/process.js.map +1 -0
- package/dist/internal/stdio.d.ts +6 -0
- package/dist/internal/stdio.d.ts.map +1 -0
- package/dist/internal/stdio.js +15 -0
- package/dist/internal/stdio.js.map +1 -0
- package/dist/internal/tokenStorage.d.ts +3 -13
- package/dist/internal/tokenStorage.d.ts.map +1 -1
- package/dist/internal/tokenStorage.js +26 -24
- package/dist/internal/tokenStorage.js.map +1 -1
- package/dist/internal/userCache.d.ts +1 -1
- package/dist/internal/userCache.d.ts.map +1 -1
- package/dist/internal/userCache.js +1 -1
- package/dist/internal/userCache.js.map +1 -1
- package/package.json +29 -20
- package/skills/confluence/SKILL.md +143 -0
- package/skills/confluence/agents/openai.yaml +4 -0
- package/src/AdfPlaceholders.ts +563 -0
- package/src/AdfSchemaValidator.ts +65 -0
- package/src/AdfWalker.ts +591 -0
- package/src/AtlaskitTransformers.ts +70 -0
- package/src/Brand.ts +11 -16
- package/src/ConfluenceAuth.ts +22 -30
- package/src/ConfluenceClient.ts +28 -24
- package/src/ConfluenceConfig.ts +14 -14
- package/src/ConfluenceError.ts +65 -3
- package/src/GitService.ts +39 -49
- package/src/LocalFileSystem.ts +7 -9
- package/src/MarkdownConverter.ts +108 -143
- package/src/Schemas.ts +17 -16
- package/src/SyncEngine.ts +272 -127
- package/src/atlaskit-adf-schema.d.ts +3 -0
- package/src/bin.ts +30 -56
- package/src/commands/auth.ts +21 -18
- package/src/commands/clone.ts +46 -38
- package/src/commands/delete.ts +5 -4
- package/src/commands/errorHandler.ts +25 -18
- package/src/commands/fetch.ts +90 -0
- package/src/commands/git.ts +6 -6
- package/src/commands/index.ts +1 -0
- package/src/commands/layers.ts +64 -37
- package/src/commands/new.ts +5 -4
- package/src/commands/pageInput.ts +103 -0
- package/src/commands/root.ts +59 -0
- package/src/commands/sync.ts +7 -6
- package/src/index.ts +3 -18
- package/src/internal/NodeLayers.ts +1 -2
- package/src/internal/adfMetadata.ts +145 -0
- package/src/internal/cleanMarkdown.ts +15 -0
- package/src/internal/frontmatter.ts +45 -8
- package/src/internal/gitCommands.ts +23 -17
- package/src/internal/hashUtils.ts +2 -2
- package/src/internal/oauthServer.ts +84 -105
- package/src/internal/pathUtils.ts +1 -1
- package/src/internal/process.ts +15 -0
- package/src/internal/stdio.ts +22 -0
- package/src/internal/tokenStorage.ts +39 -29
- package/src/internal/userCache.ts +2 -2
- package/test/AdfPlaceholders.test.ts +508 -0
- package/test/AdfSchemaValidator.test.ts +34 -0
- package/test/AdfWalker.test.ts +676 -0
- package/test/AtlaskitTransformers.test.ts +25 -0
- package/test/Brand.test.ts +11 -11
- package/test/GitService.test.ts +6 -2
- package/test/MarkdownConverter.test.ts +121 -105
- package/test/RoundTrip.test.ts +521 -0
- package/test/Schemas.test.ts +40 -40
- package/test/adfMetadata.test.ts +110 -0
- package/test/cleanMarkdown.test.ts +36 -0
- package/test/commandHarness.test.ts +79 -0
- package/test/commandHarness.ts +147 -0
- package/test/fetch.test.ts +61 -0
- package/test/frontmatter.test.ts +41 -0
- package/test/integration.test.ts +569 -156
- package/test/layers.test.ts +12 -0
- package/test/oauthServer.test.ts +4 -5
- package/test/pageInput.test.ts +83 -0
- package/test/tokenStorage.test.ts +17 -17
- package/dist/SchemaConverterError.d.ts +0 -108
- package/dist/SchemaConverterError.d.ts.map +0 -1
- package/dist/SchemaConverterError.js +0 -84
- package/dist/SchemaConverterError.js.map +0 -1
- package/dist/ast/BlockNode.d.ts +0 -453
- package/dist/ast/BlockNode.d.ts.map +0 -1
- package/dist/ast/BlockNode.js +0 -310
- package/dist/ast/BlockNode.js.map +0 -1
- package/dist/ast/Document.d.ts +0 -216
- package/dist/ast/Document.d.ts.map +0 -1
- package/dist/ast/Document.js +0 -69
- package/dist/ast/Document.js.map +0 -1
- package/dist/ast/InlineNode.d.ts +0 -477
- package/dist/ast/InlineNode.d.ts.map +0 -1
- package/dist/ast/InlineNode.js +0 -263
- package/dist/ast/InlineNode.js.map +0 -1
- package/dist/ast/MacroNode.d.ts +0 -267
- package/dist/ast/MacroNode.d.ts.map +0 -1
- package/dist/ast/MacroNode.js +0 -164
- package/dist/ast/MacroNode.js.map +0 -1
- package/dist/ast/index.d.ts +0 -10
- package/dist/ast/index.d.ts.map +0 -1
- package/dist/ast/index.js +0 -14
- package/dist/ast/index.js.map +0 -1
- package/dist/parsers/ConfluenceParser.d.ts +0 -26
- package/dist/parsers/ConfluenceParser.d.ts.map +0 -1
- package/dist/parsers/ConfluenceParser.js +0 -797
- package/dist/parsers/ConfluenceParser.js.map +0 -1
- package/dist/parsers/MarkdownParser.d.ts +0 -26
- package/dist/parsers/MarkdownParser.d.ts.map +0 -1
- package/dist/parsers/MarkdownParser.js +0 -982
- package/dist/parsers/MarkdownParser.js.map +0 -1
- package/dist/parsers/index.d.ts +0 -8
- package/dist/parsers/index.d.ts.map +0 -1
- package/dist/parsers/index.js +0 -8
- package/dist/parsers/index.js.map +0 -1
- package/dist/schemas/ConfluenceSchema.d.ts +0 -21
- package/dist/schemas/ConfluenceSchema.d.ts.map +0 -1
- package/dist/schemas/ConfluenceSchema.js +0 -38
- package/dist/schemas/ConfluenceSchema.js.map +0 -1
- package/dist/schemas/ConversionSchema.d.ts +0 -35
- package/dist/schemas/ConversionSchema.d.ts.map +0 -1
- package/dist/schemas/ConversionSchema.js +0 -208
- package/dist/schemas/ConversionSchema.js.map +0 -1
- package/dist/schemas/MarkdownSchema.d.ts +0 -21
- package/dist/schemas/MarkdownSchema.d.ts.map +0 -1
- package/dist/schemas/MarkdownSchema.js +0 -38
- package/dist/schemas/MarkdownSchema.js.map +0 -1
- package/dist/schemas/hast/HastFromHtml.d.ts +0 -27
- package/dist/schemas/hast/HastFromHtml.d.ts.map +0 -1
- package/dist/schemas/hast/HastFromHtml.js +0 -107
- package/dist/schemas/hast/HastFromHtml.js.map +0 -1
- package/dist/schemas/hast/HastSchema.d.ts +0 -195
- package/dist/schemas/hast/HastSchema.d.ts.map +0 -1
- package/dist/schemas/hast/HastSchema.js +0 -183
- package/dist/schemas/hast/HastSchema.js.map +0 -1
- package/dist/schemas/hast/index.d.ts +0 -9
- package/dist/schemas/hast/index.d.ts.map +0 -1
- package/dist/schemas/hast/index.js +0 -3
- package/dist/schemas/hast/index.js.map +0 -1
- package/dist/schemas/index.d.ts +0 -14
- package/dist/schemas/index.d.ts.map +0 -1
- package/dist/schemas/index.js +0 -16
- package/dist/schemas/index.js.map +0 -1
- package/dist/schemas/mdast/MdastFromMarkdown.d.ts +0 -30
- package/dist/schemas/mdast/MdastFromMarkdown.d.ts.map +0 -1
- package/dist/schemas/mdast/MdastFromMarkdown.js +0 -79
- package/dist/schemas/mdast/MdastFromMarkdown.js.map +0 -1
- package/dist/schemas/mdast/MdastSchema.d.ts +0 -385
- package/dist/schemas/mdast/MdastSchema.d.ts.map +0 -1
- package/dist/schemas/mdast/MdastSchema.js +0 -266
- package/dist/schemas/mdast/MdastSchema.js.map +0 -1
- package/dist/schemas/mdast/index.d.ts +0 -10
- package/dist/schemas/mdast/index.d.ts.map +0 -1
- package/dist/schemas/mdast/index.js +0 -4
- package/dist/schemas/mdast/index.js.map +0 -1
- package/dist/schemas/mdast/mdastToString.d.ts +0 -13
- package/dist/schemas/mdast/mdastToString.d.ts.map +0 -1
- package/dist/schemas/mdast/mdastToString.js +0 -85
- package/dist/schemas/mdast/mdastToString.js.map +0 -1
- package/dist/schemas/nodes/block/BlockSchema.d.ts +0 -43
- package/dist/schemas/nodes/block/BlockSchema.d.ts.map +0 -1
- package/dist/schemas/nodes/block/BlockSchema.js +0 -634
- package/dist/schemas/nodes/block/BlockSchema.js.map +0 -1
- package/dist/schemas/nodes/block/index.d.ts +0 -7
- package/dist/schemas/nodes/block/index.d.ts.map +0 -1
- package/dist/schemas/nodes/block/index.js +0 -7
- package/dist/schemas/nodes/block/index.js.map +0 -1
- package/dist/schemas/nodes/index.d.ts +0 -9
- package/dist/schemas/nodes/index.d.ts.map +0 -1
- package/dist/schemas/nodes/index.js +0 -12
- package/dist/schemas/nodes/index.js.map +0 -1
- package/dist/schemas/nodes/inline/InlineSchema.d.ts +0 -48
- package/dist/schemas/nodes/inline/InlineSchema.d.ts.map +0 -1
- package/dist/schemas/nodes/inline/InlineSchema.js +0 -436
- package/dist/schemas/nodes/inline/InlineSchema.js.map +0 -1
- package/dist/schemas/nodes/inline/index.d.ts +0 -7
- package/dist/schemas/nodes/inline/index.d.ts.map +0 -1
- package/dist/schemas/nodes/inline/index.js +0 -7
- package/dist/schemas/nodes/inline/index.js.map +0 -1
- package/dist/schemas/nodes/macro/MacroSchema.d.ts +0 -27
- package/dist/schemas/nodes/macro/MacroSchema.d.ts.map +0 -1
- package/dist/schemas/nodes/macro/MacroSchema.js +0 -162
- package/dist/schemas/nodes/macro/MacroSchema.js.map +0 -1
- package/dist/schemas/nodes/macro/index.d.ts +0 -7
- package/dist/schemas/nodes/macro/index.d.ts.map +0 -1
- package/dist/schemas/nodes/macro/index.js +0 -7
- package/dist/schemas/nodes/macro/index.js.map +0 -1
- package/dist/schemas/preprocessing/ConfluencePreprocessor.d.ts +0 -24
- package/dist/schemas/preprocessing/ConfluencePreprocessor.d.ts.map +0 -1
- package/dist/schemas/preprocessing/ConfluencePreprocessor.js +0 -359
- package/dist/schemas/preprocessing/ConfluencePreprocessor.js.map +0 -1
- package/dist/schemas/preprocessing/index.d.ts +0 -8
- package/dist/schemas/preprocessing/index.d.ts.map +0 -1
- package/dist/schemas/preprocessing/index.js +0 -2
- package/dist/schemas/preprocessing/index.js.map +0 -1
- package/dist/serializers/ConfluenceSerializer.d.ts +0 -30
- package/dist/serializers/ConfluenceSerializer.d.ts.map +0 -1
- package/dist/serializers/ConfluenceSerializer.js +0 -560
- package/dist/serializers/ConfluenceSerializer.js.map +0 -1
- package/dist/serializers/MarkdownSerializer.d.ts +0 -34
- package/dist/serializers/MarkdownSerializer.d.ts.map +0 -1
- package/dist/serializers/MarkdownSerializer.js +0 -395
- package/dist/serializers/MarkdownSerializer.js.map +0 -1
- package/dist/serializers/index.d.ts +0 -8
- package/dist/serializers/index.d.ts.map +0 -1
- package/dist/serializers/index.js +0 -8
- package/dist/serializers/index.js.map +0 -1
- package/src/SchemaConverterError.ts +0 -108
- package/src/ast/BlockNode.ts +0 -469
- package/src/ast/Document.ts +0 -90
- package/src/ast/InlineNode.ts +0 -323
- package/src/ast/MacroNode.ts +0 -245
- package/src/ast/index.ts +0 -83
- package/src/parsers/ConfluenceParser.ts +0 -956
- package/src/parsers/MarkdownParser.ts +0 -1338
- package/src/parsers/index.ts +0 -8
- package/src/schemas/ConfluenceSchema.ts +0 -56
- package/src/schemas/ConversionSchema.ts +0 -318
- package/src/schemas/MarkdownSchema.ts +0 -56
- package/src/schemas/hast/HastFromHtml.ts +0 -153
- package/src/schemas/hast/HastSchema.ts +0 -274
- package/src/schemas/hast/index.ts +0 -35
- package/src/schemas/index.ts +0 -20
- package/src/schemas/mdast/MdastFromMarkdown.ts +0 -118
- package/src/schemas/mdast/MdastSchema.ts +0 -566
- package/src/schemas/mdast/index.ts +0 -59
- package/src/schemas/mdast/mdastToString.ts +0 -102
- package/src/schemas/nodes/block/BlockSchema.ts +0 -773
- package/src/schemas/nodes/block/index.ts +0 -13
- package/src/schemas/nodes/index.ts +0 -20
- package/src/schemas/nodes/inline/InlineSchema.ts +0 -523
- package/src/schemas/nodes/inline/index.ts +0 -14
- package/src/schemas/nodes/macro/MacroSchema.ts +0 -226
- package/src/schemas/nodes/macro/index.ts +0 -6
- package/src/schemas/preprocessing/ConfluencePreprocessor.ts +0 -455
- package/src/schemas/preprocessing/index.ts +0 -8
- package/src/serializers/ConfluenceSerializer.ts +0 -737
- package/src/serializers/MarkdownSerializer.ts +0 -543
- package/src/serializers/index.ts +0 -8
- package/test/ast/BlockNode.test.ts +0 -265
- package/test/ast/Document.test.ts +0 -126
- package/test/ast/InlineNode.test.ts +0 -161
- package/test/fixtures/integration-test.html.fixture +0 -103
- package/test/fixtures/integration-test.md.expected +0 -257
- package/test/parsers/ConfluenceParser.test.ts +0 -452
- package/test/schemas/ConfluencePreprocessor.test.ts +0 -180
- package/test/schemas/ConversionSchema.test.ts +0 -159
- package/test/schemas/HastSchema.test.ts +0 -138
- package/test/schemas/MdastSchema.test.ts +0 -145
- package/test/schemas/nodes/block/BlockSchema.test.ts +0 -173
- package/test/schemas/nodes/inline/InlineSchema.test.ts +0 -198
- package/test/schemas/nodes/macro/MacroSchema.test.ts +0 -142
package/src/SyncEngine.ts
CHANGED
|
@@ -3,10 +3,15 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
|
-
import * as Path from "@effect/platform/Path"
|
|
7
6
|
import * as Context from "effect/Context"
|
|
8
7
|
import * as Effect from "effect/Effect"
|
|
8
|
+
import * as FileSystem from "effect/FileSystem"
|
|
9
9
|
import * as Layer from "effect/Layer"
|
|
10
|
+
import * as Path from "effect/Path"
|
|
11
|
+
import type * as PlatformError from "effect/PlatformError"
|
|
12
|
+
import * as Result from "effect/Result"
|
|
13
|
+
import * as Schema from "effect/Schema"
|
|
14
|
+
import type * as Terminal from "effect/Terminal"
|
|
10
15
|
import { PageId } from "./Brand.js"
|
|
11
16
|
import { ConfluenceClient } from "./ConfluenceClient.js"
|
|
12
17
|
import { ConfluenceConfig } from "./ConfluenceConfig.js"
|
|
@@ -14,6 +19,14 @@ import type { ApiError, ConversionError, FrontMatterError, RateLimitError } from
|
|
|
14
19
|
import { FileSystemError, StructureError } from "./ConfluenceError.js"
|
|
15
20
|
import type { GitServiceError } from "./GitService.js"
|
|
16
21
|
import { GitService } from "./GitService.js"
|
|
22
|
+
import type { AdfMetadataSidecar } from "./internal/adfMetadata.js"
|
|
23
|
+
import {
|
|
24
|
+
AdfMetadataSidecarSchema,
|
|
25
|
+
collectAdfMetadataHrefs,
|
|
26
|
+
externalizeAdfMetadata,
|
|
27
|
+
hydrateAdfMetadata
|
|
28
|
+
} from "./internal/adfMetadata.js"
|
|
29
|
+
import { parseMarkdown } from "./internal/frontmatter.js"
|
|
17
30
|
import { computeHash, HashServiceLive } from "./internal/hashUtils.js"
|
|
18
31
|
import { UserCache } from "./internal/userCache.js"
|
|
19
32
|
import { LocalFileSystem } from "./LocalFileSystem.js"
|
|
@@ -40,7 +53,11 @@ export type SyncStatus =
|
|
|
40
53
|
/**
|
|
41
54
|
* Progress callback for version replay.
|
|
42
55
|
*/
|
|
43
|
-
export type ProgressCallback = (
|
|
56
|
+
export type ProgressCallback = (
|
|
57
|
+
current: number,
|
|
58
|
+
total: number,
|
|
59
|
+
message: string
|
|
60
|
+
) => Effect.Effect<void, PlatformError.PlatformError, Terminal.Terminal>
|
|
44
61
|
|
|
45
62
|
/**
|
|
46
63
|
* Options for pull operation.
|
|
@@ -101,6 +118,26 @@ type SyncError =
|
|
|
101
118
|
| GitServiceError
|
|
102
119
|
| StructureError
|
|
103
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Pretty-print an ADF JSON wire string for the `.source.json` companion file.
|
|
123
|
+
* Falls back to the raw string if it can't be parsed as JSON.
|
|
124
|
+
*/
|
|
125
|
+
const prettyAdf = (raw: string): string => {
|
|
126
|
+
try {
|
|
127
|
+
return JSON.stringify(JSON.parse(raw), null, 2)
|
|
128
|
+
} catch {
|
|
129
|
+
return raw
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Hash a markdown body in the form `readMarkdownFile` will later return it.
|
|
135
|
+
* `parseMarkdown` trims the body when reading, so the hash we store on
|
|
136
|
+
* frontmatter must hash the trimmed body too — otherwise every subsequent
|
|
137
|
+
* read sees a "changed" file and `push` keeps pushing a no-op update.
|
|
138
|
+
*/
|
|
139
|
+
const hashBody = (markdown: string) => computeHash(markdown.trim()).pipe(Effect.provide(HashServiceLive))
|
|
140
|
+
|
|
104
141
|
/**
|
|
105
142
|
* Sync engine service for Confluence <-> Markdown operations.
|
|
106
143
|
*
|
|
@@ -118,15 +155,15 @@ type SyncError =
|
|
|
118
155
|
*
|
|
119
156
|
* @category Sync
|
|
120
157
|
*/
|
|
121
|
-
export class SyncEngine extends Context.
|
|
122
|
-
"@knpkv/confluence-to-markdown/SyncEngine"
|
|
123
|
-
)<
|
|
158
|
+
export class SyncEngine extends Context.Service<
|
|
124
159
|
SyncEngine,
|
|
125
160
|
{
|
|
126
161
|
/**
|
|
127
162
|
* Pull pages from Confluence to local markdown.
|
|
128
163
|
*/
|
|
129
|
-
readonly pull: (
|
|
164
|
+
readonly pull: (
|
|
165
|
+
options: PullOptions
|
|
166
|
+
) => Effect.Effect<PullResult, SyncError | PlatformError.PlatformError, Terminal.Terminal>
|
|
130
167
|
|
|
131
168
|
/**
|
|
132
169
|
* Push local markdown changes to Confluence.
|
|
@@ -138,7 +175,7 @@ export class SyncEngine extends Context.Tag(
|
|
|
138
175
|
*/
|
|
139
176
|
readonly status: () => Effect.Effect<StatusResult, SyncError>
|
|
140
177
|
}
|
|
141
|
-
>() {}
|
|
178
|
+
>()("@knpkv/confluence-to-markdown/SyncEngine") {}
|
|
142
179
|
|
|
143
180
|
/**
|
|
144
181
|
* Layer that provides SyncEngine.
|
|
@@ -148,7 +185,14 @@ export class SyncEngine extends Context.Tag(
|
|
|
148
185
|
export const layer: Layer.Layer<
|
|
149
186
|
SyncEngine,
|
|
150
187
|
never,
|
|
151
|
-
|
|
188
|
+
| ConfluenceClient
|
|
189
|
+
| ConfluenceConfig
|
|
190
|
+
| MarkdownConverter
|
|
191
|
+
| LocalFileSystem
|
|
192
|
+
| Path.Path
|
|
193
|
+
| GitService
|
|
194
|
+
| UserCache
|
|
195
|
+
| FileSystem.FileSystem
|
|
152
196
|
> = Layer.effect(
|
|
153
197
|
SyncEngine,
|
|
154
198
|
Effect.gen(function*() {
|
|
@@ -157,10 +201,69 @@ export const layer: Layer.Layer<
|
|
|
157
201
|
const converter = yield* MarkdownConverter
|
|
158
202
|
const localFs = yield* LocalFileSystem
|
|
159
203
|
const pathService = yield* Path.Path
|
|
204
|
+
const fs = yield* FileSystem.FileSystem
|
|
160
205
|
const git = yield* GitService
|
|
161
206
|
const userCache = yield* UserCache
|
|
162
207
|
|
|
163
|
-
const
|
|
208
|
+
const cwd = pathService.resolve(".")
|
|
209
|
+
const docsPath = pathService.join(cwd, config.docsPath)
|
|
210
|
+
|
|
211
|
+
const adfMetadataPath = (filePath: string, pageId?: string): string =>
|
|
212
|
+
pageId
|
|
213
|
+
? pathService.join(pathService.dirname(filePath), `${pageId}.adf.json`)
|
|
214
|
+
: filePath.replace(/\.md$/, ".adf.json")
|
|
215
|
+
|
|
216
|
+
const adfMetadataHref = (filePath: string, pageId?: string): string =>
|
|
217
|
+
`./${pathService.basename(adfMetadataPath(filePath, pageId))}`
|
|
218
|
+
|
|
219
|
+
const prepareMarkdownForFile = (filePath: string, markdown: string, pageId?: string) =>
|
|
220
|
+
externalizeAdfMetadata(markdown, adfMetadataHref(filePath, pageId))
|
|
221
|
+
|
|
222
|
+
const writePreparedMarkdownWithAdfMetadata = (
|
|
223
|
+
filePath: string,
|
|
224
|
+
frontMatter: PageFrontMatter,
|
|
225
|
+
prepared: ReturnType<typeof externalizeAdfMetadata>
|
|
226
|
+
): Effect.Effect<void, FileSystemError> =>
|
|
227
|
+
Effect.gen(function*() {
|
|
228
|
+
yield* localFs.writeMarkdownFile(filePath, frontMatter, prepared.markdown)
|
|
229
|
+
const sidecarPath = adfMetadataPath(filePath, frontMatter.pageId)
|
|
230
|
+
if (prepared.sidecar !== null) {
|
|
231
|
+
yield* localFs.writeFile(
|
|
232
|
+
sidecarPath,
|
|
233
|
+
JSON.stringify(prepared.sidecar, null, 2) + "\n"
|
|
234
|
+
)
|
|
235
|
+
} else if (yield* localFs.exists(sidecarPath)) {
|
|
236
|
+
yield* localFs.deleteFile(sidecarPath)
|
|
237
|
+
}
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
const readAdfMetadataSidecar = (sidecarPath: string): Effect.Effect<AdfMetadataSidecar | null, FileSystemError> =>
|
|
241
|
+
Effect.gen(function*() {
|
|
242
|
+
const exists = yield* localFs.exists(sidecarPath)
|
|
243
|
+
if (!exists) return null
|
|
244
|
+
const raw = yield* fs.readFileString(sidecarPath).pipe(
|
|
245
|
+
Effect.mapError((cause) => new FileSystemError({ operation: "read", path: sidecarPath, cause }))
|
|
246
|
+
)
|
|
247
|
+
const parsed = yield* Effect.try({
|
|
248
|
+
try: () => JSON.parse(raw) as unknown,
|
|
249
|
+
catch: (cause) => new FileSystemError({ operation: "read", path: sidecarPath, cause })
|
|
250
|
+
})
|
|
251
|
+
return yield* Schema.decodeUnknownEffect(AdfMetadataSidecarSchema)(parsed).pipe(
|
|
252
|
+
Effect.mapError((cause) => new FileSystemError({ operation: "read", path: sidecarPath, cause }))
|
|
253
|
+
)
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
const hydrateMarkdownForFile = (filePath: string, markdown: string): Effect.Effect<string, FileSystemError> =>
|
|
257
|
+
Effect.gen(function*() {
|
|
258
|
+
const sidecars = new Map<string, AdfMetadataSidecar>()
|
|
259
|
+
const dir = pathService.dirname(filePath)
|
|
260
|
+
for (const href of collectAdfMetadataHrefs(markdown)) {
|
|
261
|
+
const sidecarPath = pathService.resolve(dir, href)
|
|
262
|
+
const sidecar = yield* readAdfMetadataSidecar(sidecarPath)
|
|
263
|
+
if (sidecar !== null) sidecars.set(href, sidecar)
|
|
264
|
+
}
|
|
265
|
+
return hydrateAdfMetadata(markdown, sidecars)
|
|
266
|
+
})
|
|
164
267
|
|
|
165
268
|
/**
|
|
166
269
|
* Build a map of relative path (without .md) to pageId for resolving parents.
|
|
@@ -320,25 +423,30 @@ export const layer: Layer.Layer<
|
|
|
320
423
|
*/
|
|
321
424
|
const getUser = (accountId: string): Effect.Effect<AtlassianUser | undefined, ApiError | RateLimitError> =>
|
|
322
425
|
userCache.getOrFetch(accountId, client.getUser).pipe(
|
|
323
|
-
Effect.
|
|
426
|
+
Effect.catchCause(() => Effect.succeed(undefined))
|
|
324
427
|
)
|
|
325
428
|
|
|
326
429
|
/**
|
|
327
430
|
* Convert version content to markdown and front-matter.
|
|
328
431
|
*/
|
|
329
432
|
const versionToMarkdown = (
|
|
433
|
+
filePath: string,
|
|
330
434
|
pageId: PageId,
|
|
331
435
|
version: PageVersionContent,
|
|
332
436
|
title: string,
|
|
333
437
|
parentId?: string,
|
|
334
438
|
position?: number
|
|
335
|
-
): Effect.Effect<{
|
|
439
|
+
): Effect.Effect<{
|
|
440
|
+
markdown: string
|
|
441
|
+
frontMatter: PageFrontMatter
|
|
442
|
+
prepared: ReturnType<typeof externalizeAdfMetadata>
|
|
443
|
+
}, SyncError> =>
|
|
336
444
|
Effect.gen(function*() {
|
|
337
|
-
const
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
}
|
|
341
|
-
const contentHash = yield*
|
|
445
|
+
const adfJson = version.body?.atlas_doc_format?.value ?? ""
|
|
446
|
+
const rawMarkdown = yield* converter.adfToMarkdown(adfJson)
|
|
447
|
+
const prepared = prepareMarkdownForFile(filePath, rawMarkdown, pageId)
|
|
448
|
+
const { markdown } = prepared
|
|
449
|
+
const contentHash = yield* hashBody(markdown)
|
|
342
450
|
|
|
343
451
|
// Get author info
|
|
344
452
|
const author = version.authorId ? yield* getUser(version.authorId) : undefined
|
|
@@ -356,7 +464,7 @@ export const layer: Layer.Layer<
|
|
|
356
464
|
...(author?.email ? { authorEmail: author.email } : {})
|
|
357
465
|
}
|
|
358
466
|
|
|
359
|
-
return { markdown, frontMatter }
|
|
467
|
+
return { markdown, frontMatter, prepared }
|
|
360
468
|
})
|
|
361
469
|
|
|
362
470
|
/**
|
|
@@ -369,7 +477,11 @@ export const layer: Layer.Layer<
|
|
|
369
477
|
options: PullOptions,
|
|
370
478
|
gitInitialized: boolean,
|
|
371
479
|
knownParentId?: string
|
|
372
|
-
): Effect.Effect<
|
|
480
|
+
): Effect.Effect<
|
|
481
|
+
{ pulled: number; commits: number },
|
|
482
|
+
SyncError | PlatformError.PlatformError,
|
|
483
|
+
Terminal.Terminal
|
|
484
|
+
> =>
|
|
373
485
|
Effect.gen(function*() {
|
|
374
486
|
const pageId = page.id as PageId
|
|
375
487
|
// Get children to determine if this is a folder
|
|
@@ -430,11 +542,11 @@ export const layer: Layer.Layer<
|
|
|
430
542
|
versionIdx++
|
|
431
543
|
// Report progress
|
|
432
544
|
if (options.onProgress) {
|
|
433
|
-
options.onProgress(versionIdx, totalVersions, `${fullPage.title} v${versionInfo.number}`)
|
|
545
|
+
yield* options.onProgress(versionIdx, totalVersions, `${fullPage.title} v${versionInfo.number}`)
|
|
434
546
|
}
|
|
435
547
|
|
|
436
548
|
// Check if body content is available from the versions list
|
|
437
|
-
const bodyContent = versionInfo.page?.body?.
|
|
549
|
+
const bodyContent = versionInfo.page?.body?.atlas_doc_format?.value
|
|
438
550
|
if (!bodyContent) {
|
|
439
551
|
// No body content available - history replay not supported
|
|
440
552
|
historyReplayFailed = true
|
|
@@ -448,13 +560,14 @@ export const layer: Layer.Layer<
|
|
|
448
560
|
createdAt: versionInfo.createdAt,
|
|
449
561
|
message: versionInfo.message,
|
|
450
562
|
body: {
|
|
451
|
-
|
|
563
|
+
atlas_doc_format: {
|
|
452
564
|
value: bodyContent,
|
|
453
|
-
representation: "
|
|
565
|
+
representation: "atlas_doc_format" as const
|
|
454
566
|
}
|
|
455
567
|
}
|
|
456
568
|
}
|
|
457
|
-
const { frontMatter,
|
|
569
|
+
const { frontMatter, prepared } = yield* versionToMarkdown(
|
|
570
|
+
filePath,
|
|
458
571
|
pageId,
|
|
459
572
|
versionContent,
|
|
460
573
|
versionInfo.page?.title ?? fullPage.title,
|
|
@@ -463,12 +576,12 @@ export const layer: Layer.Layer<
|
|
|
463
576
|
)
|
|
464
577
|
|
|
465
578
|
// Write file
|
|
466
|
-
yield*
|
|
579
|
+
yield* writePreparedMarkdownWithAdfMetadata(filePath, frontMatter, prepared)
|
|
467
580
|
|
|
468
|
-
// Save source
|
|
469
|
-
if (config.saveSource && versionContent.body?.
|
|
470
|
-
const sourceFilePath = filePath.replace(/\.md$/, ".
|
|
471
|
-
yield* localFs.writeFile(sourceFilePath, versionContent.body.
|
|
581
|
+
// Save source ADF JSON if configured
|
|
582
|
+
if (config.saveSource && versionContent.body?.atlas_doc_format?.value) {
|
|
583
|
+
const sourceFilePath = filePath.replace(/\.md$/, ".source.json")
|
|
584
|
+
yield* localFs.writeFile(sourceFilePath, prettyAdf(versionContent.body.atlas_doc_format.value))
|
|
472
585
|
}
|
|
473
586
|
|
|
474
587
|
// Commit this version
|
|
@@ -501,10 +614,8 @@ export const layer: Layer.Layer<
|
|
|
501
614
|
}
|
|
502
615
|
|
|
503
616
|
// Simple pull without history replay
|
|
504
|
-
const
|
|
505
|
-
let
|
|
506
|
-
includeRawSource: config.saveSource
|
|
507
|
-
})
|
|
617
|
+
const adfJson = fullPage.body?.atlas_doc_format?.value ?? ""
|
|
618
|
+
let rawMarkdown = yield* converter.adfToMarkdown(adfJson)
|
|
508
619
|
|
|
509
620
|
// Add child page links for index pages
|
|
510
621
|
if (hasChildren && config.spaceKey) {
|
|
@@ -514,10 +625,12 @@ export const layer: Layer.Layer<
|
|
|
514
625
|
return `- [${child.title}](${pageUrl})`
|
|
515
626
|
})
|
|
516
627
|
.join("\n")
|
|
517
|
-
|
|
628
|
+
rawMarkdown = rawMarkdown.trim() + "\n\n## Child Pages\n\n" + childLinks + "\n"
|
|
518
629
|
}
|
|
519
630
|
|
|
520
|
-
const
|
|
631
|
+
const prepared = prepareMarkdownForFile(filePath, rawMarkdown, pageId)
|
|
632
|
+
const { markdown } = prepared
|
|
633
|
+
const contentHash = yield* hashBody(markdown)
|
|
521
634
|
|
|
522
635
|
// Get author info
|
|
523
636
|
const author = fullPage.version.authorId ? yield* getUser(fullPage.version.authorId) : undefined
|
|
@@ -536,12 +649,12 @@ export const layer: Layer.Layer<
|
|
|
536
649
|
...(author?.email ? { authorEmail: author.email } : {})
|
|
537
650
|
}
|
|
538
651
|
|
|
539
|
-
yield*
|
|
652
|
+
yield* writePreparedMarkdownWithAdfMetadata(filePath, frontMatter, prepared)
|
|
540
653
|
|
|
541
|
-
// Save source
|
|
542
|
-
if (config.saveSource &&
|
|
543
|
-
const sourceFilePath = filePath.replace(/\.md$/, ".
|
|
544
|
-
yield* localFs.writeFile(sourceFilePath,
|
|
654
|
+
// Save source ADF JSON if configured
|
|
655
|
+
if (config.saveSource && adfJson) {
|
|
656
|
+
const sourceFilePath = filePath.replace(/\.md$/, ".source.json")
|
|
657
|
+
yield* localFs.writeFile(sourceFilePath, prettyAdf(adfJson))
|
|
545
658
|
}
|
|
546
659
|
}
|
|
547
660
|
|
|
@@ -558,7 +671,9 @@ export const layer: Layer.Layer<
|
|
|
558
671
|
return { pulled: 1 + childPulled, commits: totalCommits + childCommits }
|
|
559
672
|
})
|
|
560
673
|
|
|
561
|
-
const pull = (
|
|
674
|
+
const pull = (
|
|
675
|
+
options: PullOptions
|
|
676
|
+
): Effect.Effect<PullResult, SyncError | PlatformError.PlatformError, Terminal.Terminal> =>
|
|
562
677
|
Effect.gen(function*() {
|
|
563
678
|
yield* localFs.ensureDir(docsPath)
|
|
564
679
|
|
|
@@ -576,31 +691,55 @@ export const layer: Layer.Layer<
|
|
|
576
691
|
yield* git.checkout("origin/confluence")
|
|
577
692
|
}
|
|
578
693
|
|
|
579
|
-
const
|
|
580
|
-
|
|
694
|
+
const pullAndMerge = Effect.gen(function*() {
|
|
695
|
+
const rootPage = yield* client.getPage(config.rootPageId)
|
|
696
|
+
const result = yield* pullPage(rootPage, docsPath, options, gitInitialized)
|
|
581
697
|
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
698
|
+
// If git is initialized and we have changes but didn't replay history, auto-commit
|
|
699
|
+
if (gitInitialized && !options.replayHistory && result.pulled > 0) {
|
|
700
|
+
yield* git.addAll()
|
|
701
|
+
yield* git.commit({
|
|
702
|
+
message: `Pull from Confluence (${result.pulled} page${result.pulled !== 1 ? "s" : ""})`
|
|
703
|
+
}).pipe(Effect.catchTag("GitNoChangesError", () => Effect.void))
|
|
704
|
+
}
|
|
589
705
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
706
|
+
// Two-branch model: merge origin/confluence into current branch
|
|
707
|
+
if (hasRemoteBranch && originalBranch && originalBranch !== "origin/confluence") {
|
|
708
|
+
yield* git.checkout(originalBranch)
|
|
709
|
+
yield* git.merge("origin/confluence", {
|
|
710
|
+
message: `Merge remote changes from Confluence`
|
|
711
|
+
}).pipe(Effect.catchIf(() => true, () => Effect.void)) // May fail if no changes
|
|
712
|
+
}
|
|
597
713
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
714
|
+
return {
|
|
715
|
+
pulled: result.pulled,
|
|
716
|
+
skipped: 0,
|
|
717
|
+
commits: result.commits,
|
|
718
|
+
errors: [] as ReadonlyArray<string>
|
|
719
|
+
}
|
|
720
|
+
})
|
|
721
|
+
|
|
722
|
+
// Any failure after the origin/confluence checkout (API, conversion,
|
|
723
|
+
// git) must not strand the repo on a detached HEAD — same protection
|
|
724
|
+
// as findUnpushedCommits. On success this re-checkout is a no-op.
|
|
725
|
+
// The restore itself can fail (a half-written pull leaves dirty files
|
|
726
|
+
// that differ between branches); that must be loud, not swallowed.
|
|
727
|
+
return yield* pullAndMerge.pipe(
|
|
728
|
+
Effect.ensuring(
|
|
729
|
+
hasRemoteBranch && originalBranch
|
|
730
|
+
? git.checkout(originalBranch).pipe(
|
|
731
|
+
Effect.catchCause((cause) =>
|
|
732
|
+
Effect.logWarning(
|
|
733
|
+
`pull: could not restore branch '${originalBranch}' — the repo may still be on origin/confluence. ` +
|
|
734
|
+
`Restore manually with \`git checkout ${originalBranch}\` (stash local changes first if needed). Cause: ${
|
|
735
|
+
String(cause)
|
|
736
|
+
}`
|
|
737
|
+
)
|
|
738
|
+
)
|
|
739
|
+
)
|
|
740
|
+
: Effect.void
|
|
741
|
+
)
|
|
742
|
+
)
|
|
604
743
|
})
|
|
605
744
|
|
|
606
745
|
/**
|
|
@@ -627,22 +766,18 @@ export const layer: Layer.Layer<
|
|
|
627
766
|
|
|
628
767
|
// For new pages, re-parse front-matter to get title
|
|
629
768
|
// The localFile only has the content (body), not the original front-matter
|
|
630
|
-
const
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
const parsed = matter.default(rawFile)
|
|
636
|
-
return (parsed.data as { title?: string }).title ?? baseName
|
|
637
|
-
},
|
|
638
|
-
catch: (cause) => new FileSystemError({ operation: "read", path: filePath, cause })
|
|
639
|
-
})
|
|
769
|
+
const rawFile = yield* fs.readFileString(filePath).pipe(
|
|
770
|
+
Effect.mapError((cause) => new FileSystemError({ operation: "read", path: filePath, cause }))
|
|
771
|
+
)
|
|
772
|
+
const parsed = yield* parseMarkdown(filePath, rawFile)
|
|
773
|
+
const title = parsed.frontMatter?.title ?? baseName
|
|
640
774
|
|
|
641
775
|
// Resolve parent from directory structure
|
|
642
776
|
const parentId = yield* resolveParent(filePath, pageIdMap)
|
|
643
777
|
|
|
644
|
-
// Convert markdown to
|
|
645
|
-
const
|
|
778
|
+
// Convert markdown to ADF
|
|
779
|
+
const hydratedContent = yield* hydrateMarkdownForFile(filePath, localFile.content)
|
|
780
|
+
const adfValue = yield* converter.markdownToAdf(hydratedContent)
|
|
646
781
|
|
|
647
782
|
// Create the page
|
|
648
783
|
const createdPage = yield* client.createPage({
|
|
@@ -650,14 +785,14 @@ export const layer: Layer.Layer<
|
|
|
650
785
|
parentId,
|
|
651
786
|
title,
|
|
652
787
|
body: {
|
|
653
|
-
representation: "
|
|
654
|
-
value:
|
|
788
|
+
representation: "atlas_doc_format",
|
|
789
|
+
value: adfValue
|
|
655
790
|
}
|
|
656
791
|
})
|
|
657
792
|
|
|
658
793
|
// Set editor version to v2 (new editor)
|
|
659
794
|
yield* client.setEditorVersion(createdPage.id as PageId, "v2").pipe(
|
|
660
|
-
Effect.
|
|
795
|
+
Effect.catchIf(() => true, (error) => {
|
|
661
796
|
// Log warning but don't fail the push
|
|
662
797
|
return Effect.logWarning(`Failed to set editor v2 for page ${createdPage.id}: ${error.message}`)
|
|
663
798
|
})
|
|
@@ -665,11 +800,11 @@ export const layer: Layer.Layer<
|
|
|
665
800
|
|
|
666
801
|
// Fetch canonical content back from Confluence
|
|
667
802
|
const canonicalPage = yield* client.getPage(createdPage.id as PageId)
|
|
668
|
-
const
|
|
669
|
-
const
|
|
670
|
-
|
|
671
|
-
}
|
|
672
|
-
const canonicalHash = yield*
|
|
803
|
+
const canonicalAdf = canonicalPage.body?.atlas_doc_format?.value ?? ""
|
|
804
|
+
const rawCanonicalMarkdown = yield* converter.adfToMarkdown(canonicalAdf)
|
|
805
|
+
const preparedCanonicalMarkdown = prepareMarkdownForFile(filePath, rawCanonicalMarkdown, createdPage.id)
|
|
806
|
+
const { markdown: canonicalMarkdown } = preparedCanonicalMarkdown
|
|
807
|
+
const canonicalHash = yield* hashBody(canonicalMarkdown)
|
|
673
808
|
|
|
674
809
|
// Write canonical content with full front-matter
|
|
675
810
|
const newFrontMatter: PageFrontMatter = {
|
|
@@ -680,7 +815,7 @@ export const layer: Layer.Layer<
|
|
|
680
815
|
parentId: parentId as PageId,
|
|
681
816
|
contentHash: canonicalHash
|
|
682
817
|
}
|
|
683
|
-
yield*
|
|
818
|
+
yield* writePreparedMarkdownWithAdfMetadata(filePath, newFrontMatter, preparedCanonicalMarkdown)
|
|
684
819
|
|
|
685
820
|
// Update pageIdMap with new page
|
|
686
821
|
const key = relativePath.replace(/\.md$/, "")
|
|
@@ -698,7 +833,8 @@ export const layer: Layer.Layer<
|
|
|
698
833
|
|
|
699
834
|
// Fetch current version to avoid conflicts
|
|
700
835
|
const remotePage = yield* client.getPage(fm.pageId)
|
|
701
|
-
const
|
|
836
|
+
const hydratedContent = yield* hydrateMarkdownForFile(filePath, localFile.content)
|
|
837
|
+
const adfValue = yield* converter.markdownToAdf(hydratedContent)
|
|
702
838
|
const updatedPage = yield* client.updatePage({
|
|
703
839
|
id: fm.pageId,
|
|
704
840
|
title: fm.title,
|
|
@@ -708,18 +844,18 @@ export const layer: Layer.Layer<
|
|
|
708
844
|
message: revisionMessage
|
|
709
845
|
},
|
|
710
846
|
body: {
|
|
711
|
-
representation: "
|
|
712
|
-
value:
|
|
847
|
+
representation: "atlas_doc_format",
|
|
848
|
+
value: adfValue
|
|
713
849
|
}
|
|
714
850
|
})
|
|
715
851
|
|
|
716
852
|
// Fetch canonical content back from Confluence
|
|
717
853
|
const canonicalPage = yield* client.getPage(fm.pageId)
|
|
718
|
-
const
|
|
719
|
-
const
|
|
720
|
-
|
|
721
|
-
}
|
|
722
|
-
const canonicalHash = yield*
|
|
854
|
+
const canonicalAdf = canonicalPage.body?.atlas_doc_format?.value ?? ""
|
|
855
|
+
const rawCanonicalMarkdown = yield* converter.adfToMarkdown(canonicalAdf)
|
|
856
|
+
const preparedCanonicalMarkdown = prepareMarkdownForFile(filePath, rawCanonicalMarkdown, fm.pageId)
|
|
857
|
+
const { markdown: canonicalMarkdown } = preparedCanonicalMarkdown
|
|
858
|
+
const canonicalHash = yield* hashBody(canonicalMarkdown)
|
|
723
859
|
|
|
724
860
|
// Write canonical content with updated front-matter
|
|
725
861
|
const newFrontMatter: PageFrontMatter = {
|
|
@@ -728,7 +864,7 @@ export const layer: Layer.Layer<
|
|
|
728
864
|
updated: new Date(canonicalPage.version.createdAt ?? new Date().toISOString()),
|
|
729
865
|
contentHash: canonicalHash
|
|
730
866
|
}
|
|
731
|
-
yield*
|
|
867
|
+
yield* writePreparedMarkdownWithAdfMetadata(filePath, newFrontMatter, preparedCanonicalMarkdown)
|
|
732
868
|
|
|
733
869
|
return { pushed: true, created: false }
|
|
734
870
|
})
|
|
@@ -759,34 +895,45 @@ export const layer: Layer.Layer<
|
|
|
759
895
|
const allCommits = yield* git.log({ n: 100 })
|
|
760
896
|
if (allCommits.length === 0) return []
|
|
761
897
|
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
898
|
+
// We checkout each commit to compare content; restore HEAD before returning
|
|
899
|
+
// so subsequent pushFile() calls see the working-tree content the user staged,
|
|
900
|
+
// not whatever commit we last inspected.
|
|
901
|
+
const originalBranch = yield* git.getCurrentBranch()
|
|
902
|
+
|
|
903
|
+
const collect = Effect.gen(function*() {
|
|
904
|
+
const unpushed: Array<{ hash: string; message: string }> = []
|
|
905
|
+
for (const commit of allCommits) {
|
|
906
|
+
yield* git.checkout(commit.hash)
|
|
907
|
+
|
|
908
|
+
let hasChanges = false
|
|
909
|
+
for (const filePath of files) {
|
|
910
|
+
const exists = yield* localFs.exists(filePath)
|
|
911
|
+
if (!exists) continue
|
|
912
|
+
|
|
913
|
+
const localFile = yield* localFs.readMarkdownFile(filePath)
|
|
914
|
+
if (!localFile.frontMatter) {
|
|
915
|
+
hasChanges = true
|
|
916
|
+
break
|
|
917
|
+
}
|
|
771
918
|
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
919
|
+
const currentHash = yield* computeHash(localFile.content).pipe(Effect.provide(HashServiceLive))
|
|
920
|
+
if (currentHash !== localFile.frontMatter.contentHash) {
|
|
921
|
+
hasChanges = true
|
|
922
|
+
break
|
|
923
|
+
}
|
|
776
924
|
}
|
|
777
925
|
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
hasChanges = true
|
|
781
|
-
break
|
|
782
|
-
}
|
|
926
|
+
if (!hasChanges) break
|
|
927
|
+
unpushed.push({ hash: commit.hash, message: commit.message })
|
|
783
928
|
}
|
|
929
|
+
return unpushed.reverse()
|
|
930
|
+
})
|
|
784
931
|
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
932
|
+
return yield* collect.pipe(
|
|
933
|
+
Effect.ensuring(
|
|
934
|
+
originalBranch ? git.checkout(originalBranch).pipe(Effect.ignore) : Effect.void
|
|
935
|
+
)
|
|
936
|
+
)
|
|
790
937
|
})
|
|
791
938
|
|
|
792
939
|
const push = (options: { dryRun: boolean; message?: string }): Effect.Effect<PushResult, SyncError> =>
|
|
@@ -827,13 +974,12 @@ export const layer: Layer.Layer<
|
|
|
827
974
|
spaceId,
|
|
828
975
|
pageIdMap
|
|
829
976
|
).pipe(
|
|
830
|
-
Effect.
|
|
977
|
+
Effect.catchIf(() => true, (error) =>
|
|
831
978
|
Effect.succeed({
|
|
832
979
|
pushed: false,
|
|
833
980
|
created: false,
|
|
834
981
|
error: `Failed: ${error._tag}`
|
|
835
|
-
})
|
|
836
|
-
)
|
|
982
|
+
}))
|
|
837
983
|
)
|
|
838
984
|
if (result.error) errors.push(result.error)
|
|
839
985
|
if (result.pushed) pushed++
|
|
@@ -890,13 +1036,13 @@ export const layer: Layer.Layer<
|
|
|
890
1036
|
const match = content.match(/pageId:\s*['"]?(\d+)['"]?/)
|
|
891
1037
|
return match ? match[1] : null
|
|
892
1038
|
}),
|
|
893
|
-
Effect.
|
|
1039
|
+
Effect.catchIf(() => true, () => Effect.succeed(null))
|
|
894
1040
|
)
|
|
895
1041
|
|
|
896
1042
|
if (pageIdFromOrigin) {
|
|
897
1043
|
yield* client.deletePage(PageId(pageIdFromOrigin)).pipe(
|
|
898
1044
|
Effect.tap(() => Effect.sync(() => deleted++)),
|
|
899
|
-
Effect.
|
|
1045
|
+
Effect.catchIf(() => true, (error) => {
|
|
900
1046
|
errors.push(`Failed to delete page ${pageIdFromOrigin}: ${error.message}`)
|
|
901
1047
|
return Effect.void
|
|
902
1048
|
})
|
|
@@ -907,13 +1053,12 @@ export const layer: Layer.Layer<
|
|
|
907
1053
|
|
|
908
1054
|
for (const filePath of sortedFiles) {
|
|
909
1055
|
const result = yield* pushFile(filePath, revisionMessage, spaceId, pageIdMap).pipe(
|
|
910
|
-
Effect.
|
|
1056
|
+
Effect.catchIf(() => true, (error) =>
|
|
911
1057
|
Effect.succeed({
|
|
912
1058
|
pushed: false,
|
|
913
1059
|
created: false,
|
|
914
1060
|
error: `Failed to push ${filePath}: ${error._tag}`
|
|
915
|
-
})
|
|
916
|
-
)
|
|
1061
|
+
}))
|
|
917
1062
|
)
|
|
918
1063
|
if (result.error) errors.push(result.error)
|
|
919
1064
|
if (result.pushed) pushed++
|
|
@@ -923,7 +1068,7 @@ export const layer: Layer.Layer<
|
|
|
923
1068
|
// Amend the last commit with canonical content
|
|
924
1069
|
yield* git.addAll()
|
|
925
1070
|
yield* git.amend({ noEdit: true }).pipe(
|
|
926
|
-
Effect.
|
|
1071
|
+
Effect.catchIf(() => true, () => Effect.void)
|
|
927
1072
|
)
|
|
928
1073
|
|
|
929
1074
|
// Two-branch model: update origin/confluence to match HEAD
|
|
@@ -959,15 +1104,15 @@ export const layer: Layer.Layer<
|
|
|
959
1104
|
const currentHash = yield* computeHash(localFile.content).pipe(Effect.provide(HashServiceLive))
|
|
960
1105
|
|
|
961
1106
|
// Fetch remote page
|
|
962
|
-
const remotePage = yield* Effect.
|
|
1107
|
+
const remotePage = yield* Effect.result(client.getPage(fm.pageId))
|
|
963
1108
|
|
|
964
|
-
if (remotePage
|
|
1109
|
+
if (Result.isFailure(remotePage)) {
|
|
965
1110
|
statuses.push({ _tag: "LocalOnly", path: filePath, title: fm.title })
|
|
966
1111
|
localOnly++
|
|
967
1112
|
continue
|
|
968
1113
|
}
|
|
969
1114
|
|
|
970
|
-
const page = remotePage.
|
|
1115
|
+
const page = remotePage.success
|
|
971
1116
|
const localChanged = currentHash !== fm.contentHash
|
|
972
1117
|
const remoteChanged = page.version.number > fm.version
|
|
973
1118
|
|