@knpkv/confluence-to-markdown 0.6.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 +39 -0
- package/LICENSE +21 -0
- package/README.md +22 -13
- 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 +37 -39
- package/dist/ConfluenceAuth.js.map +1 -1
- package/dist/ConfluenceClient.d.ts +7 -17
- package/dist/ConfluenceClient.d.ts.map +1 -1
- package/dist/ConfluenceClient.js +81 -38
- 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 +68 -16
- package/dist/ConfluenceError.d.ts.map +1 -1
- package/dist/ConfluenceError.js +30 -1
- package/dist/ConfluenceError.js.map +1 -1
- package/dist/GitError.d.ts +5 -5
- package/dist/GitService.d.ts +11 -3
- package/dist/GitService.d.ts.map +1 -1
- package/dist/GitService.js +22 -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 +30 -30
- package/skills/confluence/SKILL.md +143 -0
- package/skills/confluence/agents/openai.yaml +4 -0
- package/src/AdfPlaceholders.ts +310 -13
- package/src/AdfSchemaValidator.ts +2 -4
- package/src/AdfWalker.ts +122 -42
- package/src/AtlaskitTransformers.ts +2 -4
- package/src/Brand.ts +11 -16
- package/src/ConfluenceAuth.ts +22 -30
- package/src/ConfluenceClient.ts +24 -20
- package/src/ConfluenceConfig.ts +14 -14
- package/src/GitService.ts +39 -49
- package/src/LocalFileSystem.ts +7 -9
- package/src/MarkdownConverter.ts +2 -4
- package/src/Schemas.ts +13 -12
- package/src/SyncEngine.ts +151 -53
- package/src/bin.ts +30 -56
- package/src/commands/auth.ts +21 -18
- package/src/commands/clone.ts +38 -37
- 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 +53 -33
- 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/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 +213 -0
- package/test/AdfSchemaValidator.test.ts +6 -6
- package/test/AdfWalker.test.ts +167 -21
- package/test/AtlaskitTransformers.test.ts +4 -4
- package/test/Brand.test.ts +11 -11
- package/test/GitService.test.ts +6 -2
- package/test/MarkdownConverter.test.ts +12 -11
- package/test/RoundTrip.test.ts +258 -3
- 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 -468
- package/dist/ast/BlockNode.d.ts.map +0 -1
- package/dist/ast/BlockNode.js +0 -319
- package/dist/ast/BlockNode.js.map +0 -1
- package/dist/ast/Document.d.ts +0 -244
- 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 -792
- 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 -873
- 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/parsers/preprocessing/ConfluencePreprocessing.d.ts +0 -23
- package/dist/parsers/preprocessing/ConfluencePreprocessing.d.ts.map +0 -1
- package/dist/parsers/preprocessing/ConfluencePreprocessing.js +0 -323
- package/dist/parsers/preprocessing/ConfluencePreprocessing.js.map +0 -1
- package/dist/parsers/preprocessing/index.d.ts +0 -7
- package/dist/parsers/preprocessing/index.d.ts.map +0 -1
- package/dist/parsers/preprocessing/index.js +0 -7
- package/dist/parsers/preprocessing/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 -53
- package/dist/schemas/preprocessing/ConfluencePreprocessor.d.ts.map +0 -1
- package/dist/schemas/preprocessing/ConfluencePreprocessor.js +0 -349
- 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 -551
- 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 -355
- 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/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
|
@@ -39,9 +39,7 @@ import { ConversionError } from "./ConfluenceError.js"
|
|
|
39
39
|
*
|
|
40
40
|
* @category Conversion
|
|
41
41
|
*/
|
|
42
|
-
export class MarkdownConverter extends Context.
|
|
43
|
-
"@knpkv/confluence-to-markdown/MarkdownConverter"
|
|
44
|
-
)<
|
|
42
|
+
export class MarkdownConverter extends Context.Service<
|
|
45
43
|
MarkdownConverter,
|
|
46
44
|
{
|
|
47
45
|
/**
|
|
@@ -59,7 +57,7 @@ export class MarkdownConverter extends Context.Tag(
|
|
|
59
57
|
*/
|
|
60
58
|
readonly markdownToAdf: (markdown: string) => Effect.Effect<string, ConversionError>
|
|
61
59
|
}
|
|
62
|
-
>() {}
|
|
60
|
+
>()("@knpkv/confluence-to-markdown/MarkdownConverter") {}
|
|
63
61
|
|
|
64
62
|
const warningSummary = (w: WalkerWarning): string => {
|
|
65
63
|
switch (w._tag) {
|
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
|
/**
|
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.
|
|
@@ -138,15 +155,15 @@ const hashBody = (markdown: string) => computeHash(markdown.trim()).pipe(Effect.
|
|
|
138
155
|
*
|
|
139
156
|
* @category Sync
|
|
140
157
|
*/
|
|
141
|
-
export class SyncEngine extends Context.
|
|
142
|
-
"@knpkv/confluence-to-markdown/SyncEngine"
|
|
143
|
-
)<
|
|
158
|
+
export class SyncEngine extends Context.Service<
|
|
144
159
|
SyncEngine,
|
|
145
160
|
{
|
|
146
161
|
/**
|
|
147
162
|
* Pull pages from Confluence to local markdown.
|
|
148
163
|
*/
|
|
149
|
-
readonly pull: (
|
|
164
|
+
readonly pull: (
|
|
165
|
+
options: PullOptions
|
|
166
|
+
) => Effect.Effect<PullResult, SyncError | PlatformError.PlatformError, Terminal.Terminal>
|
|
150
167
|
|
|
151
168
|
/**
|
|
152
169
|
* Push local markdown changes to Confluence.
|
|
@@ -158,7 +175,7 @@ export class SyncEngine extends Context.Tag(
|
|
|
158
175
|
*/
|
|
159
176
|
readonly status: () => Effect.Effect<StatusResult, SyncError>
|
|
160
177
|
}
|
|
161
|
-
>() {}
|
|
178
|
+
>()("@knpkv/confluence-to-markdown/SyncEngine") {}
|
|
162
179
|
|
|
163
180
|
/**
|
|
164
181
|
* Layer that provides SyncEngine.
|
|
@@ -168,7 +185,14 @@ export class SyncEngine extends Context.Tag(
|
|
|
168
185
|
export const layer: Layer.Layer<
|
|
169
186
|
SyncEngine,
|
|
170
187
|
never,
|
|
171
|
-
|
|
188
|
+
| ConfluenceClient
|
|
189
|
+
| ConfluenceConfig
|
|
190
|
+
| MarkdownConverter
|
|
191
|
+
| LocalFileSystem
|
|
192
|
+
| Path.Path
|
|
193
|
+
| GitService
|
|
194
|
+
| UserCache
|
|
195
|
+
| FileSystem.FileSystem
|
|
172
196
|
> = Layer.effect(
|
|
173
197
|
SyncEngine,
|
|
174
198
|
Effect.gen(function*() {
|
|
@@ -177,10 +201,69 @@ export const layer: Layer.Layer<
|
|
|
177
201
|
const converter = yield* MarkdownConverter
|
|
178
202
|
const localFs = yield* LocalFileSystem
|
|
179
203
|
const pathService = yield* Path.Path
|
|
204
|
+
const fs = yield* FileSystem.FileSystem
|
|
180
205
|
const git = yield* GitService
|
|
181
206
|
const userCache = yield* UserCache
|
|
182
207
|
|
|
183
|
-
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
|
+
})
|
|
184
267
|
|
|
185
268
|
/**
|
|
186
269
|
* Build a map of relative path (without .md) to pageId for resolving parents.
|
|
@@ -340,22 +423,29 @@ export const layer: Layer.Layer<
|
|
|
340
423
|
*/
|
|
341
424
|
const getUser = (accountId: string): Effect.Effect<AtlassianUser | undefined, ApiError | RateLimitError> =>
|
|
342
425
|
userCache.getOrFetch(accountId, client.getUser).pipe(
|
|
343
|
-
Effect.
|
|
426
|
+
Effect.catchCause(() => Effect.succeed(undefined))
|
|
344
427
|
)
|
|
345
428
|
|
|
346
429
|
/**
|
|
347
430
|
* Convert version content to markdown and front-matter.
|
|
348
431
|
*/
|
|
349
432
|
const versionToMarkdown = (
|
|
433
|
+
filePath: string,
|
|
350
434
|
pageId: PageId,
|
|
351
435
|
version: PageVersionContent,
|
|
352
436
|
title: string,
|
|
353
437
|
parentId?: string,
|
|
354
438
|
position?: number
|
|
355
|
-
): Effect.Effect<{
|
|
439
|
+
): Effect.Effect<{
|
|
440
|
+
markdown: string
|
|
441
|
+
frontMatter: PageFrontMatter
|
|
442
|
+
prepared: ReturnType<typeof externalizeAdfMetadata>
|
|
443
|
+
}, SyncError> =>
|
|
356
444
|
Effect.gen(function*() {
|
|
357
445
|
const adfJson = version.body?.atlas_doc_format?.value ?? ""
|
|
358
|
-
const
|
|
446
|
+
const rawMarkdown = yield* converter.adfToMarkdown(adfJson)
|
|
447
|
+
const prepared = prepareMarkdownForFile(filePath, rawMarkdown, pageId)
|
|
448
|
+
const { markdown } = prepared
|
|
359
449
|
const contentHash = yield* hashBody(markdown)
|
|
360
450
|
|
|
361
451
|
// Get author info
|
|
@@ -374,7 +464,7 @@ export const layer: Layer.Layer<
|
|
|
374
464
|
...(author?.email ? { authorEmail: author.email } : {})
|
|
375
465
|
}
|
|
376
466
|
|
|
377
|
-
return { markdown, frontMatter }
|
|
467
|
+
return { markdown, frontMatter, prepared }
|
|
378
468
|
})
|
|
379
469
|
|
|
380
470
|
/**
|
|
@@ -387,7 +477,11 @@ export const layer: Layer.Layer<
|
|
|
387
477
|
options: PullOptions,
|
|
388
478
|
gitInitialized: boolean,
|
|
389
479
|
knownParentId?: string
|
|
390
|
-
): Effect.Effect<
|
|
480
|
+
): Effect.Effect<
|
|
481
|
+
{ pulled: number; commits: number },
|
|
482
|
+
SyncError | PlatformError.PlatformError,
|
|
483
|
+
Terminal.Terminal
|
|
484
|
+
> =>
|
|
391
485
|
Effect.gen(function*() {
|
|
392
486
|
const pageId = page.id as PageId
|
|
393
487
|
// Get children to determine if this is a folder
|
|
@@ -448,7 +542,7 @@ export const layer: Layer.Layer<
|
|
|
448
542
|
versionIdx++
|
|
449
543
|
// Report progress
|
|
450
544
|
if (options.onProgress) {
|
|
451
|
-
options.onProgress(versionIdx, totalVersions, `${fullPage.title} v${versionInfo.number}`)
|
|
545
|
+
yield* options.onProgress(versionIdx, totalVersions, `${fullPage.title} v${versionInfo.number}`)
|
|
452
546
|
}
|
|
453
547
|
|
|
454
548
|
// Check if body content is available from the versions list
|
|
@@ -472,7 +566,8 @@ export const layer: Layer.Layer<
|
|
|
472
566
|
}
|
|
473
567
|
}
|
|
474
568
|
}
|
|
475
|
-
const { frontMatter,
|
|
569
|
+
const { frontMatter, prepared } = yield* versionToMarkdown(
|
|
570
|
+
filePath,
|
|
476
571
|
pageId,
|
|
477
572
|
versionContent,
|
|
478
573
|
versionInfo.page?.title ?? fullPage.title,
|
|
@@ -481,7 +576,7 @@ export const layer: Layer.Layer<
|
|
|
481
576
|
)
|
|
482
577
|
|
|
483
578
|
// Write file
|
|
484
|
-
yield*
|
|
579
|
+
yield* writePreparedMarkdownWithAdfMetadata(filePath, frontMatter, prepared)
|
|
485
580
|
|
|
486
581
|
// Save source ADF JSON if configured
|
|
487
582
|
if (config.saveSource && versionContent.body?.atlas_doc_format?.value) {
|
|
@@ -520,7 +615,7 @@ export const layer: Layer.Layer<
|
|
|
520
615
|
|
|
521
616
|
// Simple pull without history replay
|
|
522
617
|
const adfJson = fullPage.body?.atlas_doc_format?.value ?? ""
|
|
523
|
-
let
|
|
618
|
+
let rawMarkdown = yield* converter.adfToMarkdown(adfJson)
|
|
524
619
|
|
|
525
620
|
// Add child page links for index pages
|
|
526
621
|
if (hasChildren && config.spaceKey) {
|
|
@@ -530,9 +625,11 @@ export const layer: Layer.Layer<
|
|
|
530
625
|
return `- [${child.title}](${pageUrl})`
|
|
531
626
|
})
|
|
532
627
|
.join("\n")
|
|
533
|
-
|
|
628
|
+
rawMarkdown = rawMarkdown.trim() + "\n\n## Child Pages\n\n" + childLinks + "\n"
|
|
534
629
|
}
|
|
535
630
|
|
|
631
|
+
const prepared = prepareMarkdownForFile(filePath, rawMarkdown, pageId)
|
|
632
|
+
const { markdown } = prepared
|
|
536
633
|
const contentHash = yield* hashBody(markdown)
|
|
537
634
|
|
|
538
635
|
// Get author info
|
|
@@ -552,7 +649,7 @@ export const layer: Layer.Layer<
|
|
|
552
649
|
...(author?.email ? { authorEmail: author.email } : {})
|
|
553
650
|
}
|
|
554
651
|
|
|
555
|
-
yield*
|
|
652
|
+
yield* writePreparedMarkdownWithAdfMetadata(filePath, frontMatter, prepared)
|
|
556
653
|
|
|
557
654
|
// Save source ADF JSON if configured
|
|
558
655
|
if (config.saveSource && adfJson) {
|
|
@@ -574,7 +671,9 @@ export const layer: Layer.Layer<
|
|
|
574
671
|
return { pulled: 1 + childPulled, commits: totalCommits + childCommits }
|
|
575
672
|
})
|
|
576
673
|
|
|
577
|
-
const pull = (
|
|
674
|
+
const pull = (
|
|
675
|
+
options: PullOptions
|
|
676
|
+
): Effect.Effect<PullResult, SyncError | PlatformError.PlatformError, Terminal.Terminal> =>
|
|
578
677
|
Effect.gen(function*() {
|
|
579
678
|
yield* localFs.ensureDir(docsPath)
|
|
580
679
|
|
|
@@ -609,7 +708,7 @@ export const layer: Layer.Layer<
|
|
|
609
708
|
yield* git.checkout(originalBranch)
|
|
610
709
|
yield* git.merge("origin/confluence", {
|
|
611
710
|
message: `Merge remote changes from Confluence`
|
|
612
|
-
}).pipe(Effect.
|
|
711
|
+
}).pipe(Effect.catchIf(() => true, () => Effect.void)) // May fail if no changes
|
|
613
712
|
}
|
|
614
713
|
|
|
615
714
|
return {
|
|
@@ -629,11 +728,11 @@ export const layer: Layer.Layer<
|
|
|
629
728
|
Effect.ensuring(
|
|
630
729
|
hasRemoteBranch && originalBranch
|
|
631
730
|
? git.checkout(originalBranch).pipe(
|
|
632
|
-
Effect.
|
|
731
|
+
Effect.catchCause((cause) =>
|
|
633
732
|
Effect.logWarning(
|
|
634
733
|
`pull: could not restore branch '${originalBranch}' — the repo may still be on origin/confluence. ` +
|
|
635
734
|
`Restore manually with \`git checkout ${originalBranch}\` (stash local changes first if needed). Cause: ${
|
|
636
|
-
String(
|
|
735
|
+
String(cause)
|
|
637
736
|
}`
|
|
638
737
|
)
|
|
639
738
|
)
|
|
@@ -667,22 +766,18 @@ export const layer: Layer.Layer<
|
|
|
667
766
|
|
|
668
767
|
// For new pages, re-parse front-matter to get title
|
|
669
768
|
// The localFile only has the content (body), not the original front-matter
|
|
670
|
-
const
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
const parsed = matter.default(rawFile)
|
|
676
|
-
return (parsed.data as { title?: string }).title ?? baseName
|
|
677
|
-
},
|
|
678
|
-
catch: (cause) => new FileSystemError({ operation: "read", path: filePath, cause })
|
|
679
|
-
})
|
|
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
|
|
680
774
|
|
|
681
775
|
// Resolve parent from directory structure
|
|
682
776
|
const parentId = yield* resolveParent(filePath, pageIdMap)
|
|
683
777
|
|
|
684
778
|
// Convert markdown to ADF
|
|
685
|
-
const
|
|
779
|
+
const hydratedContent = yield* hydrateMarkdownForFile(filePath, localFile.content)
|
|
780
|
+
const adfValue = yield* converter.markdownToAdf(hydratedContent)
|
|
686
781
|
|
|
687
782
|
// Create the page
|
|
688
783
|
const createdPage = yield* client.createPage({
|
|
@@ -697,7 +792,7 @@ export const layer: Layer.Layer<
|
|
|
697
792
|
|
|
698
793
|
// Set editor version to v2 (new editor)
|
|
699
794
|
yield* client.setEditorVersion(createdPage.id as PageId, "v2").pipe(
|
|
700
|
-
Effect.
|
|
795
|
+
Effect.catchIf(() => true, (error) => {
|
|
701
796
|
// Log warning but don't fail the push
|
|
702
797
|
return Effect.logWarning(`Failed to set editor v2 for page ${createdPage.id}: ${error.message}`)
|
|
703
798
|
})
|
|
@@ -706,7 +801,9 @@ export const layer: Layer.Layer<
|
|
|
706
801
|
// Fetch canonical content back from Confluence
|
|
707
802
|
const canonicalPage = yield* client.getPage(createdPage.id as PageId)
|
|
708
803
|
const canonicalAdf = canonicalPage.body?.atlas_doc_format?.value ?? ""
|
|
709
|
-
const
|
|
804
|
+
const rawCanonicalMarkdown = yield* converter.adfToMarkdown(canonicalAdf)
|
|
805
|
+
const preparedCanonicalMarkdown = prepareMarkdownForFile(filePath, rawCanonicalMarkdown, createdPage.id)
|
|
806
|
+
const { markdown: canonicalMarkdown } = preparedCanonicalMarkdown
|
|
710
807
|
const canonicalHash = yield* hashBody(canonicalMarkdown)
|
|
711
808
|
|
|
712
809
|
// Write canonical content with full front-matter
|
|
@@ -718,7 +815,7 @@ export const layer: Layer.Layer<
|
|
|
718
815
|
parentId: parentId as PageId,
|
|
719
816
|
contentHash: canonicalHash
|
|
720
817
|
}
|
|
721
|
-
yield*
|
|
818
|
+
yield* writePreparedMarkdownWithAdfMetadata(filePath, newFrontMatter, preparedCanonicalMarkdown)
|
|
722
819
|
|
|
723
820
|
// Update pageIdMap with new page
|
|
724
821
|
const key = relativePath.replace(/\.md$/, "")
|
|
@@ -736,7 +833,8 @@ export const layer: Layer.Layer<
|
|
|
736
833
|
|
|
737
834
|
// Fetch current version to avoid conflicts
|
|
738
835
|
const remotePage = yield* client.getPage(fm.pageId)
|
|
739
|
-
const
|
|
836
|
+
const hydratedContent = yield* hydrateMarkdownForFile(filePath, localFile.content)
|
|
837
|
+
const adfValue = yield* converter.markdownToAdf(hydratedContent)
|
|
740
838
|
const updatedPage = yield* client.updatePage({
|
|
741
839
|
id: fm.pageId,
|
|
742
840
|
title: fm.title,
|
|
@@ -754,7 +852,9 @@ export const layer: Layer.Layer<
|
|
|
754
852
|
// Fetch canonical content back from Confluence
|
|
755
853
|
const canonicalPage = yield* client.getPage(fm.pageId)
|
|
756
854
|
const canonicalAdf = canonicalPage.body?.atlas_doc_format?.value ?? ""
|
|
757
|
-
const
|
|
855
|
+
const rawCanonicalMarkdown = yield* converter.adfToMarkdown(canonicalAdf)
|
|
856
|
+
const preparedCanonicalMarkdown = prepareMarkdownForFile(filePath, rawCanonicalMarkdown, fm.pageId)
|
|
857
|
+
const { markdown: canonicalMarkdown } = preparedCanonicalMarkdown
|
|
758
858
|
const canonicalHash = yield* hashBody(canonicalMarkdown)
|
|
759
859
|
|
|
760
860
|
// Write canonical content with updated front-matter
|
|
@@ -764,7 +864,7 @@ export const layer: Layer.Layer<
|
|
|
764
864
|
updated: new Date(canonicalPage.version.createdAt ?? new Date().toISOString()),
|
|
765
865
|
contentHash: canonicalHash
|
|
766
866
|
}
|
|
767
|
-
yield*
|
|
867
|
+
yield* writePreparedMarkdownWithAdfMetadata(filePath, newFrontMatter, preparedCanonicalMarkdown)
|
|
768
868
|
|
|
769
869
|
return { pushed: true, created: false }
|
|
770
870
|
})
|
|
@@ -874,13 +974,12 @@ export const layer: Layer.Layer<
|
|
|
874
974
|
spaceId,
|
|
875
975
|
pageIdMap
|
|
876
976
|
).pipe(
|
|
877
|
-
Effect.
|
|
977
|
+
Effect.catchIf(() => true, (error) =>
|
|
878
978
|
Effect.succeed({
|
|
879
979
|
pushed: false,
|
|
880
980
|
created: false,
|
|
881
981
|
error: `Failed: ${error._tag}`
|
|
882
|
-
})
|
|
883
|
-
)
|
|
982
|
+
}))
|
|
884
983
|
)
|
|
885
984
|
if (result.error) errors.push(result.error)
|
|
886
985
|
if (result.pushed) pushed++
|
|
@@ -937,13 +1036,13 @@ export const layer: Layer.Layer<
|
|
|
937
1036
|
const match = content.match(/pageId:\s*['"]?(\d+)['"]?/)
|
|
938
1037
|
return match ? match[1] : null
|
|
939
1038
|
}),
|
|
940
|
-
Effect.
|
|
1039
|
+
Effect.catchIf(() => true, () => Effect.succeed(null))
|
|
941
1040
|
)
|
|
942
1041
|
|
|
943
1042
|
if (pageIdFromOrigin) {
|
|
944
1043
|
yield* client.deletePage(PageId(pageIdFromOrigin)).pipe(
|
|
945
1044
|
Effect.tap(() => Effect.sync(() => deleted++)),
|
|
946
|
-
Effect.
|
|
1045
|
+
Effect.catchIf(() => true, (error) => {
|
|
947
1046
|
errors.push(`Failed to delete page ${pageIdFromOrigin}: ${error.message}`)
|
|
948
1047
|
return Effect.void
|
|
949
1048
|
})
|
|
@@ -954,13 +1053,12 @@ export const layer: Layer.Layer<
|
|
|
954
1053
|
|
|
955
1054
|
for (const filePath of sortedFiles) {
|
|
956
1055
|
const result = yield* pushFile(filePath, revisionMessage, spaceId, pageIdMap).pipe(
|
|
957
|
-
Effect.
|
|
1056
|
+
Effect.catchIf(() => true, (error) =>
|
|
958
1057
|
Effect.succeed({
|
|
959
1058
|
pushed: false,
|
|
960
1059
|
created: false,
|
|
961
1060
|
error: `Failed to push ${filePath}: ${error._tag}`
|
|
962
|
-
})
|
|
963
|
-
)
|
|
1061
|
+
}))
|
|
964
1062
|
)
|
|
965
1063
|
if (result.error) errors.push(result.error)
|
|
966
1064
|
if (result.pushed) pushed++
|
|
@@ -970,7 +1068,7 @@ export const layer: Layer.Layer<
|
|
|
970
1068
|
// Amend the last commit with canonical content
|
|
971
1069
|
yield* git.addAll()
|
|
972
1070
|
yield* git.amend({ noEdit: true }).pipe(
|
|
973
|
-
Effect.
|
|
1071
|
+
Effect.catchIf(() => true, () => Effect.void)
|
|
974
1072
|
)
|
|
975
1073
|
|
|
976
1074
|
// Two-branch model: update origin/confluence to match HEAD
|
|
@@ -1006,15 +1104,15 @@ export const layer: Layer.Layer<
|
|
|
1006
1104
|
const currentHash = yield* computeHash(localFile.content).pipe(Effect.provide(HashServiceLive))
|
|
1007
1105
|
|
|
1008
1106
|
// Fetch remote page
|
|
1009
|
-
const remotePage = yield* Effect.
|
|
1107
|
+
const remotePage = yield* Effect.result(client.getPage(fm.pageId))
|
|
1010
1108
|
|
|
1011
|
-
if (remotePage
|
|
1109
|
+
if (Result.isFailure(remotePage)) {
|
|
1012
1110
|
statuses.push({ _tag: "LocalOnly", path: filePath, title: fm.title })
|
|
1013
1111
|
localOnly++
|
|
1014
1112
|
continue
|
|
1015
1113
|
}
|
|
1016
1114
|
|
|
1017
|
-
const page = remotePage.
|
|
1115
|
+
const page = remotePage.success
|
|
1018
1116
|
const localChanged = currentHash !== fm.contentHash
|
|
1019
1117
|
const remoteChanged = page.version.number > fm.version
|
|
1020
1118
|
|