@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/GitService.ts
CHANGED
|
@@ -3,17 +3,13 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
|
-
import * as NodeCommandExecutor from "@effect/platform-node/NodeCommandExecutor"
|
|
7
|
-
import * as NodeContext from "@effect/platform-node/NodeContext"
|
|
8
|
-
import * as NodeFileSystem from "@effect/platform-node/NodeFileSystem"
|
|
9
|
-
import * as NodePath from "@effect/platform-node/NodePath"
|
|
10
|
-
import * as CommandExecutor from "@effect/platform/CommandExecutor"
|
|
11
|
-
import type * as PlatformError from "@effect/platform/Error"
|
|
12
|
-
import * as FileSystem from "@effect/platform/FileSystem"
|
|
13
|
-
import * as Path from "@effect/platform/Path"
|
|
14
6
|
import * as Context from "effect/Context"
|
|
15
7
|
import * as Effect from "effect/Effect"
|
|
8
|
+
import * as FileSystem from "effect/FileSystem"
|
|
16
9
|
import * as Layer from "effect/Layer"
|
|
10
|
+
import * as Path from "effect/Path"
|
|
11
|
+
import type * as PlatformError from "effect/PlatformError"
|
|
12
|
+
import { ChildProcessSpawner } from "effect/unstable/process"
|
|
17
13
|
import {
|
|
18
14
|
GitError,
|
|
19
15
|
GitMergeConflictError,
|
|
@@ -249,10 +245,10 @@ export interface GitServiceShape {
|
|
|
249
245
|
*
|
|
250
246
|
* @category Service
|
|
251
247
|
*/
|
|
252
|
-
export class GitService extends Context.
|
|
248
|
+
export class GitService extends Context.Service<
|
|
253
249
|
GitService,
|
|
254
250
|
GitServiceShape
|
|
255
|
-
>() {}
|
|
251
|
+
>()("@knpkv/confluence-to-markdown/GitService") {}
|
|
256
252
|
|
|
257
253
|
/**
|
|
258
254
|
* Map PlatformError to GitError.
|
|
@@ -260,13 +256,15 @@ export class GitService extends Context.Tag("@knpkv/confluence-to-markdown/GitSe
|
|
|
260
256
|
const mapFsError = (error: PlatformError.PlatformError): GitError =>
|
|
261
257
|
new GitError({ command: "filesystem", message: error.message })
|
|
262
258
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
)
|
|
259
|
+
const existsOrFalse = (
|
|
260
|
+
effect: Effect.Effect<boolean, PlatformError.PlatformError>
|
|
261
|
+
): Effect.Effect<boolean> =>
|
|
262
|
+
effect.pipe(
|
|
263
|
+
Effect.catchIf(
|
|
264
|
+
(error): error is PlatformError.PlatformError => error._tag === "PlatformError",
|
|
265
|
+
() => Effect.succeed(false)
|
|
266
|
+
)
|
|
267
|
+
)
|
|
270
268
|
|
|
271
269
|
/**
|
|
272
270
|
* Copy a single file, creating parent directories as needed.
|
|
@@ -279,7 +277,7 @@ const copyFileFn = (
|
|
|
279
277
|
): Effect.Effect<void, GitError> =>
|
|
280
278
|
Effect.gen(function*() {
|
|
281
279
|
const destDir = pathService.dirname(dest)
|
|
282
|
-
yield* fs.makeDirectory(destDir, { recursive: true }).pipe(Effect.
|
|
280
|
+
yield* fs.makeDirectory(destDir, { recursive: true }).pipe(Effect.mapError(mapFsError))
|
|
283
281
|
yield* fs.copyFile(source, dest).pipe(Effect.mapError(mapFsError))
|
|
284
282
|
})
|
|
285
283
|
|
|
@@ -293,7 +291,7 @@ const copyDirectoryFn = (
|
|
|
293
291
|
dest: string
|
|
294
292
|
): Effect.Effect<void, GitError> =>
|
|
295
293
|
Effect.gen(function*() {
|
|
296
|
-
yield* fs.makeDirectory(dest, { recursive: true }).pipe(Effect.
|
|
294
|
+
yield* fs.makeDirectory(dest, { recursive: true }).pipe(Effect.mapError(mapFsError))
|
|
297
295
|
|
|
298
296
|
const entries = yield* fs.readDirectory(source).pipe(Effect.mapError(mapFsError))
|
|
299
297
|
|
|
@@ -321,7 +319,7 @@ const copyMarkdownFilesFn = (
|
|
|
321
319
|
dest: string
|
|
322
320
|
): Effect.Effect<void, GitError> =>
|
|
323
321
|
Effect.gen(function*() {
|
|
324
|
-
const exists = yield* fs.exists(source)
|
|
322
|
+
const exists = yield* existsOrFalse(fs.exists(source))
|
|
325
323
|
if (!exists) {
|
|
326
324
|
return
|
|
327
325
|
}
|
|
@@ -349,7 +347,7 @@ const copyMarkdownFilesFn = (
|
|
|
349
347
|
|
|
350
348
|
// Get paths helper - takes pathService as param
|
|
351
349
|
const getPaths = (pathService: Path.Path) => {
|
|
352
|
-
const cwd =
|
|
350
|
+
const cwd = pathService.resolve(".")
|
|
353
351
|
const confluenceDir = pathService.join(cwd, ".confluence")
|
|
354
352
|
const gitDir = pathService.join(confluenceDir, ".git")
|
|
355
353
|
return { cwd, confluenceDir, gitDir, pathService }
|
|
@@ -358,7 +356,7 @@ const getPaths = (pathService: Path.Path) => {
|
|
|
358
356
|
// Ensure initialized helper - takes fs and gitDir
|
|
359
357
|
const ensureInitializedFn = (fs: FileSystem.FileSystem, gitDir: string) =>
|
|
360
358
|
Effect.gen(function*() {
|
|
361
|
-
const initialized = yield* fs.exists(gitDir)
|
|
359
|
+
const initialized = yield* existsOrFalse(fs.exists(gitDir))
|
|
362
360
|
if (!initialized) {
|
|
363
361
|
return yield* Effect.fail(new GitNotInitializedError())
|
|
364
362
|
}
|
|
@@ -368,17 +366,18 @@ const ensureInitializedFn = (fs: FileSystem.FileSystem, gitDir: string) =>
|
|
|
368
366
|
const make = Effect.gen(function*() {
|
|
369
367
|
const fs = yield* FileSystem.FileSystem
|
|
370
368
|
const pathService = yield* Path.Path
|
|
371
|
-
const
|
|
369
|
+
const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner
|
|
372
370
|
const paths = getPaths(pathService)
|
|
373
371
|
const { confluenceDir, cwd, gitDir } = paths
|
|
374
372
|
|
|
375
373
|
// Create context with captured services for providing to returned Effects
|
|
376
|
-
const depsContext: Context.Context<FileSystem.FileSystem | Path.Path |
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
374
|
+
const depsContext: Context.Context<FileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner> =
|
|
375
|
+
Context
|
|
376
|
+
.empty().pipe(
|
|
377
|
+
Context.add(FileSystem.FileSystem, fs),
|
|
378
|
+
Context.add(Path.Path, pathService),
|
|
379
|
+
Context.add(ChildProcessSpawner.ChildProcessSpawner, childProcessSpawner)
|
|
380
|
+
)
|
|
382
381
|
|
|
383
382
|
// Helper to provide deps to an effect - uses any for R since we know depsContext covers all needs
|
|
384
383
|
const provideDeps = <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E> =>
|
|
@@ -396,11 +395,7 @@ const make = Effect.gen(function*() {
|
|
|
396
395
|
)
|
|
397
396
|
)
|
|
398
397
|
|
|
399
|
-
const isInitialized = () =>
|
|
400
|
-
Effect.succeed(fs).pipe(
|
|
401
|
-
Effect.flatMap((f) => f.exists(gitDir)),
|
|
402
|
-
Effect.catchAll(() => Effect.succeed(false))
|
|
403
|
-
)
|
|
398
|
+
const isInitialized = () => existsOrFalse(fs.exists(gitDir))
|
|
404
399
|
|
|
405
400
|
const init = () =>
|
|
406
401
|
provideDeps(
|
|
@@ -410,12 +405,12 @@ const make = Effect.gen(function*() {
|
|
|
410
405
|
Effect.catchTag("GitError", () => Effect.fail(new GitNotInstalledError({ message: "Git not found" })))
|
|
411
406
|
)
|
|
412
407
|
|
|
413
|
-
const exists = yield* fs.exists(confluenceDir)
|
|
408
|
+
const exists = yield* existsOrFalse(fs.exists(confluenceDir))
|
|
414
409
|
if (!exists) {
|
|
415
410
|
yield* fs.makeDirectory(confluenceDir, { recursive: true }).pipe(Effect.mapError(mapFsError))
|
|
416
411
|
}
|
|
417
412
|
|
|
418
|
-
const gitExists = yield* fs.exists(gitDir)
|
|
413
|
+
const gitExists = yield* existsOrFalse(fs.exists(gitDir))
|
|
419
414
|
if (!gitExists) {
|
|
420
415
|
yield* runGit(["init"], confluenceDir)
|
|
421
416
|
// Configure local git user for commits (needed in CI environments)
|
|
@@ -583,7 +578,7 @@ const make = Effect.gen(function*() {
|
|
|
583
578
|
const sourcePath = pathService.join(absoluteDocsPath, pattern)
|
|
584
579
|
const destPath = pathService.join(confluenceDir, pattern)
|
|
585
580
|
|
|
586
|
-
const exists = yield* fs.exists(sourcePath)
|
|
581
|
+
const exists = yield* existsOrFalse(fs.exists(sourcePath))
|
|
587
582
|
if (exists) {
|
|
588
583
|
const stat = yield* fs.stat(sourcePath).pipe(Effect.mapError(mapFsError))
|
|
589
584
|
if (stat.type === "Directory") {
|
|
@@ -614,7 +609,7 @@ const make = Effect.gen(function*() {
|
|
|
614
609
|
const sourcePath = pathService.join(confluenceDir, pattern)
|
|
615
610
|
const destPath = pathService.join(absoluteDocsPath, pattern)
|
|
616
611
|
|
|
617
|
-
const exists = yield* fs.exists(sourcePath)
|
|
612
|
+
const exists = yield* existsOrFalse(fs.exists(sourcePath))
|
|
618
613
|
if (exists) {
|
|
619
614
|
const stat = yield* fs.stat(sourcePath).pipe(Effect.mapError(mapFsError))
|
|
620
615
|
if (stat.type === "Directory") {
|
|
@@ -842,18 +837,13 @@ const make = Effect.gen(function*() {
|
|
|
842
837
|
})
|
|
843
838
|
})
|
|
844
839
|
|
|
845
|
-
// Layer with deps - requires FileSystem, Path, CommandExecutor
|
|
846
|
-
const layerWithDeps: Layer.Layer<
|
|
847
|
-
GitService,
|
|
848
|
-
never,
|
|
849
|
-
FileSystem.FileSystem | Path.Path | CommandExecutor.CommandExecutor
|
|
850
|
-
> = Layer.effect(GitService, make)
|
|
851
|
-
|
|
852
840
|
/**
|
|
853
|
-
* Create GitService layer
|
|
841
|
+
* Create GitService layer.
|
|
854
842
|
*
|
|
855
843
|
* @category Layers
|
|
856
844
|
*/
|
|
857
|
-
export const layer
|
|
858
|
-
|
|
859
|
-
|
|
845
|
+
export const layer: Layer.Layer<
|
|
846
|
+
GitService,
|
|
847
|
+
never,
|
|
848
|
+
FileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner
|
|
849
|
+
> = Layer.effect(GitService, make)
|
package/src/LocalFileSystem.ts
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
|
-
import * as FileSystem from "@effect/platform/FileSystem"
|
|
7
|
-
import * as Path from "@effect/platform/Path"
|
|
8
6
|
import * as Context from "effect/Context"
|
|
9
7
|
import * as Effect from "effect/Effect"
|
|
8
|
+
import * as FileSystem from "effect/FileSystem"
|
|
10
9
|
import * as Layer from "effect/Layer"
|
|
10
|
+
import * as Path from "effect/Path"
|
|
11
11
|
import type { ContentHash } from "./Brand.js"
|
|
12
12
|
import type { FrontMatterError } from "./ConfluenceError.js"
|
|
13
13
|
import { FileSystemError } from "./ConfluenceError.js"
|
|
@@ -59,9 +59,7 @@ export interface PageTreeNode {
|
|
|
59
59
|
*
|
|
60
60
|
* @category FileSystem
|
|
61
61
|
*/
|
|
62
|
-
export class LocalFileSystem extends Context.
|
|
63
|
-
"@knpkv/confluence-to-markdown/LocalFileSystem"
|
|
64
|
-
)<
|
|
62
|
+
export class LocalFileSystem extends Context.Service<
|
|
65
63
|
LocalFileSystem,
|
|
66
64
|
{
|
|
67
65
|
/**
|
|
@@ -135,7 +133,7 @@ export class LocalFileSystem extends Context.Tag(
|
|
|
135
133
|
content: string
|
|
136
134
|
) => Effect.Effect<void, FileSystemError>
|
|
137
135
|
}
|
|
138
|
-
>() {}
|
|
136
|
+
>()("@knpkv/confluence-to-markdown/LocalFileSystem") {}
|
|
139
137
|
|
|
140
138
|
/**
|
|
141
139
|
* Layer that provides LocalFileSystem.
|
|
@@ -180,7 +178,7 @@ export const layer: Layer.Layer<LocalFileSystem, never, FileSystem.FileSystem |
|
|
|
180
178
|
Effect.gen(function*() {
|
|
181
179
|
const dir = pathService.dirname(filePath)
|
|
182
180
|
yield* fs.makeDirectory(dir, { recursive: true }).pipe(
|
|
183
|
-
Effect.
|
|
181
|
+
Effect.mapError((cause) => new FileSystemError({ operation: "mkdir", path: dir, cause }))
|
|
184
182
|
)
|
|
185
183
|
|
|
186
184
|
const serialized = serializeMarkdown(frontMatter, content)
|
|
@@ -257,7 +255,7 @@ export const layer: Layer.Layer<LocalFileSystem, never, FileSystem.FileSystem |
|
|
|
257
255
|
Effect.gen(function*() {
|
|
258
256
|
const dir = pathService.dirname(filePath)
|
|
259
257
|
yield* fs.makeDirectory(dir, { recursive: true }).pipe(
|
|
260
|
-
Effect.
|
|
258
|
+
Effect.mapError((cause) => new FileSystemError({ operation: "mkdir", path: dir, cause }))
|
|
261
259
|
)
|
|
262
260
|
|
|
263
261
|
// Atomic write: write to temp file, then rename
|
|
@@ -289,7 +287,7 @@ export const layer: Layer.Layer<LocalFileSystem, never, FileSystem.FileSystem |
|
|
|
289
287
|
Effect.gen(function*() {
|
|
290
288
|
const dir = pathService.dirname(filePath)
|
|
291
289
|
yield* fs.makeDirectory(dir, { recursive: true }).pipe(
|
|
292
|
-
Effect.
|
|
290
|
+
Effect.mapError((cause) => new FileSystemError({ operation: "mkdir", path: dir, cause }))
|
|
293
291
|
)
|
|
294
292
|
|
|
295
293
|
const serialized = serializeNewPageMarkdown(frontMatter, content)
|
package/src/MarkdownConverter.ts
CHANGED
|
@@ -1,26 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* ADF ↔ Markdown conversion facade.
|
|
3
|
+
*
|
|
4
|
+
* Push (markdown → ADF) routes through the official `@atlaskit` markdown
|
|
5
|
+
* + JSON transformers and is strictly validated by `AdfSchemaValidator` —
|
|
6
|
+
* we author that side, so schema failures are bugs. Pull (ADF → markdown)
|
|
7
|
+
* routes through the in-package `AdfWalker`; incoming validation is advisory
|
|
8
|
+
* (logged, not thrown) because Confluence Cloud routinely emits documents the
|
|
9
|
+
* canonical schema lags behind.
|
|
3
10
|
*
|
|
4
11
|
* @module
|
|
5
12
|
*/
|
|
13
|
+
import type { DocNode } from "@atlaskit/adf-schema"
|
|
6
14
|
import * as Context from "effect/Context"
|
|
7
15
|
import * as Effect from "effect/Effect"
|
|
8
16
|
import * as Layer from "effect/Layer"
|
|
9
17
|
import * as Schema from "effect/Schema"
|
|
10
|
-
import
|
|
18
|
+
import { revertPlaceholders } from "./AdfPlaceholders.js"
|
|
19
|
+
import { AdfSchemaValidator } from "./AdfSchemaValidator.js"
|
|
20
|
+
import { walk, type WalkerWarning } from "./AdfWalker.js"
|
|
21
|
+
import { AtlaskitTransformers } from "./AtlaskitTransformers.js"
|
|
22
|
+
import type { AdfSchemaError, AtlaskitTransformersError } from "./ConfluenceError.js"
|
|
11
23
|
import { ConversionError } from "./ConfluenceError.js"
|
|
12
|
-
import { parseConfluenceHtml } from "./parsers/ConfluenceParser.js"
|
|
13
|
-
import { parseMarkdown } from "./parsers/MarkdownParser.js"
|
|
14
|
-
import { ParseError, type SerializeError } from "./SchemaConverterError.js"
|
|
15
|
-
import { ConfluenceToMarkdown, DocumentFromHast, DocumentFromMdast } from "./schemas/ConversionSchema.js"
|
|
16
|
-
import { HastFromHtml } from "./schemas/hast/index.js"
|
|
17
|
-
import { MdastFromMarkdown } from "./schemas/mdast/index.js"
|
|
18
|
-
import { PreprocessedHtmlFromConfluence } from "./schemas/preprocessing/index.js"
|
|
19
|
-
import { serializeToConfluence } from "./serializers/ConfluenceSerializer.js"
|
|
20
|
-
import { type SerializeOptions, serializeToMarkdown } from "./serializers/MarkdownSerializer.js"
|
|
21
24
|
|
|
22
25
|
/**
|
|
23
|
-
* Markdown conversion service
|
|
26
|
+
* Markdown conversion service. Public surface is two delegating methods —
|
|
27
|
+
* `adfToMarkdown` (pull) and `markdownToAdf` (push).
|
|
24
28
|
*
|
|
25
29
|
* @example
|
|
26
30
|
* ```typescript
|
|
@@ -29,163 +33,124 @@ import { type SerializeOptions, serializeToMarkdown } from "./serializers/Markdo
|
|
|
29
33
|
*
|
|
30
34
|
* const program = Effect.gen(function* () {
|
|
31
35
|
* const converter = yield* MarkdownConverter
|
|
32
|
-
* const md = yield* converter.
|
|
33
|
-
* console.log(md) // # Hello\n\nWorld
|
|
36
|
+
* const md = yield* converter.adfToMarkdown(adfJson)
|
|
34
37
|
* })
|
|
35
|
-
*
|
|
36
|
-
* Effect.runPromise(
|
|
37
|
-
* program.pipe(Effect.provide(MarkdownConverter.layer))
|
|
38
|
-
* )
|
|
39
38
|
* ```
|
|
40
39
|
*
|
|
41
40
|
* @category Conversion
|
|
42
41
|
*/
|
|
43
|
-
export class MarkdownConverter extends Context.
|
|
44
|
-
"@knpkv/confluence-to-markdown/MarkdownConverter"
|
|
45
|
-
)<
|
|
42
|
+
export class MarkdownConverter extends Context.Service<
|
|
46
43
|
MarkdownConverter,
|
|
47
44
|
{
|
|
48
45
|
/**
|
|
49
|
-
* Convert
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
options?: SerializeOptions
|
|
54
|
-
) => Effect.Effect<string, ConversionError>
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Convert GitHub Flavored Markdown to HTML (Confluence storage format).
|
|
58
|
-
*/
|
|
59
|
-
readonly markdownToHtml: (markdown: string) => Effect.Effect<string, ConversionError>
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Parse Confluence HTML to Document AST.
|
|
63
|
-
*/
|
|
64
|
-
readonly htmlToAst: (html: string) => Effect.Effect<Document, ParseError>
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Parse Markdown to Document AST.
|
|
68
|
-
*/
|
|
69
|
-
readonly markdownToAst: (markdown: string) => Effect.Effect<Document, ParseError>
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Serialize Document AST to Confluence HTML.
|
|
46
|
+
* Convert an ADF JSON document (as wire-format string) to GitHub Flavored
|
|
47
|
+
* Markdown. Checks against the canonical @atlaskit/adf-schema before
|
|
48
|
+
* walking; violations are logged as warnings (remote drift), and only a
|
|
49
|
+
* document too malformed to walk at all fails with ConversionError.
|
|
73
50
|
*/
|
|
74
|
-
readonly
|
|
51
|
+
readonly adfToMarkdown: (adfJson: string) => Effect.Effect<string, ConversionError>
|
|
75
52
|
|
|
76
53
|
/**
|
|
77
|
-
*
|
|
54
|
+
* Convert GitHub Flavored Markdown to a JSON-stringified ADF document.
|
|
55
|
+
* Routes through the official @atlaskit transformers; validates the
|
|
56
|
+
* produced ADF against the canonical schema before stringification.
|
|
78
57
|
*/
|
|
79
|
-
readonly
|
|
58
|
+
readonly markdownToAdf: (markdown: string) => Effect.Effect<string, ConversionError>
|
|
59
|
+
}
|
|
60
|
+
>()("@knpkv/confluence-to-markdown/MarkdownConverter") {}
|
|
61
|
+
|
|
62
|
+
const warningSummary = (w: WalkerWarning): string => {
|
|
63
|
+
switch (w._tag) {
|
|
64
|
+
case "UnsupportedNode":
|
|
65
|
+
return `${w._tag} ${w.nodeType}`
|
|
66
|
+
case "LossyMark":
|
|
67
|
+
return `${w._tag} ${w.mark}`
|
|
68
|
+
case "MediaWithoutUrl":
|
|
69
|
+
return `${w._tag} ${w.mediaId}`
|
|
70
|
+
case "UnsupportedExtension":
|
|
71
|
+
return `${w._tag} ${w.nodeType} ${w.extensionKey || "?"}`
|
|
80
72
|
}
|
|
81
|
-
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const toConversionError = (
|
|
76
|
+
direction: "adfToMarkdown" | "markdownToAdf"
|
|
77
|
+
) =>
|
|
78
|
+
(cause: AdfSchemaError | AtlaskitTransformersError | { readonly cause: unknown }): ConversionError =>
|
|
79
|
+
new ConversionError({ direction, cause })
|
|
80
|
+
|
|
81
|
+
// The least structure the walker needs: a doc node with a content array.
|
|
82
|
+
// Anything failing this isn't "schema drift", it's not an ADF document —
|
|
83
|
+
// advisory validation must not let it through (walking `null` is a defect;
|
|
84
|
+
// walking `{}` silently produces an empty page).
|
|
85
|
+
const isWalkableDoc = Schema.is(Schema.Struct({
|
|
86
|
+
type: Schema.Literal("doc"),
|
|
87
|
+
content: Schema.Array(Schema.Unknown)
|
|
88
|
+
}))
|
|
82
89
|
|
|
83
90
|
/**
|
|
84
91
|
* Layer that provides the MarkdownConverter service.
|
|
85
92
|
*
|
|
86
93
|
* @category Layers
|
|
87
94
|
*/
|
|
88
|
-
export const layer: Layer.Layer<
|
|
95
|
+
export const layer: Layer.Layer<
|
|
89
96
|
MarkdownConverter,
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
return yield* serializeToMarkdown(doc, options).pipe(
|
|
98
|
-
Effect.mapError((e) => new ConversionError({ direction: "htmlToMarkdown", cause: e.message }))
|
|
99
|
-
)
|
|
100
|
-
}),
|
|
97
|
+
never,
|
|
98
|
+
AtlaskitTransformers | AdfSchemaValidator
|
|
99
|
+
> = Layer.effect(
|
|
100
|
+
MarkdownConverter,
|
|
101
|
+
Effect.gen(function*() {
|
|
102
|
+
const transformers = yield* AtlaskitTransformers
|
|
103
|
+
const validator = yield* AdfSchemaValidator
|
|
101
104
|
|
|
102
|
-
|
|
105
|
+
const adfToMarkdown = (adfJson: string): Effect.Effect<string, ConversionError> =>
|
|
103
106
|
Effect.gen(function*() {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
const raw = yield* Effect.try({
|
|
108
|
+
try: () => JSON.parse(adfJson),
|
|
109
|
+
catch: (cause) => new ConversionError({ direction: "adfToMarkdown", cause })
|
|
110
|
+
})
|
|
111
|
+
// Incoming validation is advisory: the canonical @atlaskit schema is
|
|
112
|
+
// routinely stricter than what Confluence Cloud actually emits (old
|
|
113
|
+
// revisions, experimental nodes), so a failure here usually means
|
|
114
|
+
// "schema drift", not "broken document". Log + continue. Outgoing
|
|
115
|
+
// validation stays strict because we control that side.
|
|
116
|
+
const doc = yield* validator.check(raw, "incoming").pipe(
|
|
117
|
+
Effect.catchTag("AdfSchemaError", (err) =>
|
|
118
|
+
isWalkableDoc(raw)
|
|
119
|
+
? Effect.gen(function*() {
|
|
120
|
+
yield* Effect.logWarning(
|
|
121
|
+
`adf schema (incoming): ${err.issues.length} issue(s); first: ${
|
|
122
|
+
err.issues.slice(0, 3).map((i) =>
|
|
123
|
+
`${i.instancePath ?? "?"} ${i.keyword ?? "?"} ${i.message ?? ""}`.trim()
|
|
124
|
+
).join(" | ")
|
|
125
|
+
}`
|
|
126
|
+
)
|
|
127
|
+
return raw as DocNode
|
|
128
|
+
})
|
|
129
|
+
: Effect.fail(toConversionError("adfToMarkdown")(err)))
|
|
110
130
|
)
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
markdownToAst: (markdown) => parseMarkdown(markdown),
|
|
116
|
-
|
|
117
|
-
astToHtml: (doc) => serializeToConfluence(doc),
|
|
118
|
-
|
|
119
|
-
astToMarkdown: (doc) => serializeToMarkdown(doc)
|
|
120
|
-
})
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Schema-based layer for MarkdownConverter using Effect Schema transforms.
|
|
125
|
-
*
|
|
126
|
-
* This is an alternative implementation that uses the new Schema-based
|
|
127
|
-
* conversion pipeline. It provides the same API as the default layer.
|
|
128
|
-
*
|
|
129
|
-
* Note: For full fidelity, continue to use the default layer. This schema-based
|
|
130
|
-
* layer is useful for simpler use cases or when you want to leverage Schema
|
|
131
|
-
* composition.
|
|
132
|
-
*
|
|
133
|
-
* @example
|
|
134
|
-
* ```typescript
|
|
135
|
-
* import { MarkdownConverter, schemaBasedLayer } from "@knpkv/confluence-to-markdown/MarkdownConverter"
|
|
136
|
-
* import { Effect } from "effect"
|
|
137
|
-
*
|
|
138
|
-
* const program = Effect.gen(function* () {
|
|
139
|
-
* const converter = yield* MarkdownConverter
|
|
140
|
-
* const md = yield* converter.htmlToMarkdown("<h1>Hello</h1>")
|
|
141
|
-
* })
|
|
142
|
-
*
|
|
143
|
-
* Effect.runPromise(
|
|
144
|
-
* program.pipe(Effect.provide(schemaBasedLayer))
|
|
145
|
-
* )
|
|
146
|
-
* ```
|
|
147
|
-
*
|
|
148
|
-
* @category Layers
|
|
149
|
-
*/
|
|
150
|
-
export const schemaBasedLayer: Layer.Layer<MarkdownConverter> = Layer.succeed(
|
|
151
|
-
MarkdownConverter,
|
|
152
|
-
MarkdownConverter.of({
|
|
153
|
-
// Note: Schema-based layer doesn't support includeRawSource option yet
|
|
154
|
-
htmlToMarkdown: (html, options) =>
|
|
155
|
-
Effect.gen(function*() {
|
|
156
|
-
if (options?.includeRawSource !== undefined) {
|
|
157
|
-
yield* Effect.logWarning("schemaBasedLayer: includeRawSource option is not supported, use default layer")
|
|
131
|
+
const { markdown, warnings } = walk(doc)
|
|
132
|
+
for (const w of warnings) {
|
|
133
|
+
yield* Effect.logWarning(`adf walker: ${warningSummary(w)}`, w)
|
|
158
134
|
}
|
|
159
|
-
return
|
|
160
|
-
})
|
|
161
|
-
Effect.mapError((e) => new ConversionError({ direction: "htmlToMarkdown", cause: e.message }))
|
|
162
|
-
),
|
|
135
|
+
return markdown
|
|
136
|
+
})
|
|
163
137
|
|
|
164
|
-
|
|
165
|
-
Schema.encode(ConfluenceToMarkdown)(markdown).pipe(
|
|
166
|
-
Effect.mapError((e) => new ConversionError({ direction: "markdownToHtml", cause: e.message }))
|
|
167
|
-
),
|
|
168
|
-
|
|
169
|
-
htmlToAst: (html) =>
|
|
170
|
-
Effect.gen(function*() {
|
|
171
|
-
const preprocessed = yield* Schema.decode(PreprocessedHtmlFromConfluence)(html)
|
|
172
|
-
const hast = yield* Schema.decode(HastFromHtml)(preprocessed)
|
|
173
|
-
return yield* Schema.decode(DocumentFromHast)(hast)
|
|
174
|
-
}).pipe(
|
|
175
|
-
Effect.mapError((e) => new ParseError({ source: "confluence", message: e.message }))
|
|
176
|
-
),
|
|
177
|
-
|
|
178
|
-
markdownToAst: (markdown) =>
|
|
138
|
+
const markdownToAdf = (markdown: string): Effect.Effect<string, ConversionError> =>
|
|
179
139
|
Effect.gen(function*() {
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
140
|
+
const adf = yield* transformers.use(({ json, md }) => json.encode(md.parse(markdown))).pipe(
|
|
141
|
+
Effect.mapError(toConversionError("markdownToAdf"))
|
|
142
|
+
)
|
|
143
|
+
// The walker emits HTML/comment placeholders for Confluence-only nodes
|
|
144
|
+
// (status, extension). @atlaskit's markdown transformer doesn't know
|
|
145
|
+
// these, so they come through as plain text. Rewrite them back into
|
|
146
|
+
// the structured nodes Confluence expects before validation.
|
|
147
|
+
const reverted = revertPlaceholders(adf)
|
|
148
|
+
const validated = yield* validator.check(reverted, "outgoing").pipe(
|
|
149
|
+
Effect.mapError(toConversionError("markdownToAdf"))
|
|
150
|
+
)
|
|
151
|
+
return JSON.stringify(validated)
|
|
152
|
+
})
|
|
188
153
|
|
|
189
|
-
|
|
154
|
+
return MarkdownConverter.of({ adfToMarkdown, markdownToAdf })
|
|
190
155
|
})
|
|
191
156
|
)
|
package/src/Schemas.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
|
+
import * as Effect from "effect/Effect"
|
|
6
7
|
import * as Schema from "effect/Schema"
|
|
7
8
|
import { ContentHashSchema, PageIdSchema, SpaceKeySchema } from "./Brand.js"
|
|
8
9
|
|
|
@@ -27,18 +28,18 @@ export const ConfluenceConfigFileSchema = Schema.Struct({
|
|
|
27
28
|
rootPageId: PageIdSchema,
|
|
28
29
|
/** Confluence Cloud base URL */
|
|
29
30
|
baseUrl: Schema.String.pipe(
|
|
30
|
-
Schema.
|
|
31
|
+
Schema.check(Schema.isPattern(/^https:\/\/[a-z0-9-]+\.atlassian\.net$/))
|
|
31
32
|
),
|
|
32
33
|
/** Optional space key */
|
|
33
34
|
spaceKey: Schema.optional(SpaceKeySchema),
|
|
34
35
|
/** Local docs path (default: .confluence/docs) */
|
|
35
|
-
docsPath: Schema.
|
|
36
|
+
docsPath: Schema.String.pipe(Schema.withDecodingDefaultTypeKey(Effect.succeed(".confluence/docs"))),
|
|
36
37
|
/** Glob patterns to exclude from sync */
|
|
37
|
-
excludePatterns: Schema.
|
|
38
|
+
excludePatterns: Schema.Array(Schema.String).pipe(Schema.withDecodingDefaultTypeKey(Effect.succeed([]))),
|
|
38
39
|
/** Save original Confluence HTML alongside markdown (default: false) */
|
|
39
|
-
saveSource: Schema.
|
|
40
|
+
saveSource: Schema.Boolean.pipe(Schema.withDecodingDefaultTypeKey(Effect.succeed(false))),
|
|
40
41
|
/** Glob patterns for files to track in git */
|
|
41
|
-
trackedPaths: Schema.
|
|
42
|
+
trackedPaths: Schema.Array(Schema.String).pipe(Schema.withDecodingDefaultTypeKey(Effect.succeed(["**/*.md"])))
|
|
42
43
|
})
|
|
43
44
|
|
|
44
45
|
/**
|
|
@@ -71,9 +72,9 @@ export const PageFrontMatterSchema = Schema.Struct({
|
|
|
71
72
|
/** Confluence page ID */
|
|
72
73
|
pageId: PageIdSchema,
|
|
73
74
|
/** Page version number */
|
|
74
|
-
version: Schema.
|
|
75
|
+
version: Schema.Int.pipe(Schema.check(Schema.isGreaterThan(0))),
|
|
75
76
|
/** Page title */
|
|
76
|
-
title: Schema.
|
|
77
|
+
title: Schema.NonEmptyString,
|
|
77
78
|
/** Last updated timestamp (ISO8601) */
|
|
78
79
|
updated: Schema.DateFromString,
|
|
79
80
|
/** Parent page ID (optional) */
|
|
@@ -104,7 +105,7 @@ export type PageFrontMatter = Schema.Schema.Type<typeof PageFrontMatterSchema>
|
|
|
104
105
|
*/
|
|
105
106
|
export const NewPageFrontMatterSchema = Schema.Struct({
|
|
106
107
|
/** Page title */
|
|
107
|
-
title: Schema.
|
|
108
|
+
title: Schema.NonEmptyString,
|
|
108
109
|
/** Parent page ID (optional, determined by directory structure) */
|
|
109
110
|
parentId: Schema.optional(PageIdSchema)
|
|
110
111
|
})
|
|
@@ -125,9 +126,9 @@ export const SyncStateSchema = Schema.Struct({
|
|
|
125
126
|
/** Last sync timestamp */
|
|
126
127
|
lastSync: Schema.DateFromString,
|
|
127
128
|
/** Map of page ID to sync info */
|
|
128
|
-
pages: Schema.Record(
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
pages: Schema.Record(
|
|
130
|
+
Schema.String,
|
|
131
|
+
Schema.Struct({
|
|
131
132
|
/** Local file path */
|
|
132
133
|
localPath: Schema.String,
|
|
133
134
|
/** Last synced version */
|
|
@@ -135,7 +136,7 @@ export const SyncStateSchema = Schema.Struct({
|
|
|
135
136
|
/** Content hash at last sync */
|
|
136
137
|
contentHash: ContentHashSchema
|
|
137
138
|
})
|
|
138
|
-
|
|
139
|
+
)
|
|
139
140
|
})
|
|
140
141
|
|
|
141
142
|
/**
|
|
@@ -163,7 +164,7 @@ export const PageResponseSchema = Schema.Struct({
|
|
|
163
164
|
}),
|
|
164
165
|
body: Schema.optional(
|
|
165
166
|
Schema.Struct({
|
|
166
|
-
|
|
167
|
+
atlas_doc_format: Schema.optional(
|
|
167
168
|
Schema.Struct({
|
|
168
169
|
value: Schema.String,
|
|
169
170
|
representation: Schema.optional(Schema.String)
|
|
@@ -204,7 +205,7 @@ export const PageListItemSchema = Schema.Struct({
|
|
|
204
205
|
})),
|
|
205
206
|
body: Schema.optional(
|
|
206
207
|
Schema.Struct({
|
|
207
|
-
|
|
208
|
+
atlas_doc_format: Schema.optional(
|
|
208
209
|
Schema.Struct({
|
|
209
210
|
value: Schema.String,
|
|
210
211
|
representation: Schema.optional(Schema.String)
|
|
@@ -377,7 +378,7 @@ export const PageVersionSchema = Schema.Struct({
|
|
|
377
378
|
title: Schema.optional(Schema.String),
|
|
378
379
|
body: Schema.optional(
|
|
379
380
|
Schema.Struct({
|
|
380
|
-
|
|
381
|
+
atlas_doc_format: Schema.optional(
|
|
381
382
|
Schema.Struct({
|
|
382
383
|
value: Schema.String,
|
|
383
384
|
representation: Schema.optional(Schema.String)
|
|
@@ -413,7 +414,7 @@ export const PageVersionContentSchema = Schema.Struct({
|
|
|
413
414
|
/** Page content */
|
|
414
415
|
body: Schema.optional(
|
|
415
416
|
Schema.Struct({
|
|
416
|
-
|
|
417
|
+
atlas_doc_format: Schema.optional(
|
|
417
418
|
Schema.Struct({
|
|
418
419
|
value: Schema.String,
|
|
419
420
|
representation: Schema.optional(Schema.String)
|