@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
|
@@ -75,7 +75,7 @@ describe("MarkdownConverter", () => {
|
|
|
75
75
|
expect(md).toContain("const x = 1")
|
|
76
76
|
}).pipe(Effect.provide(TestLayer)))
|
|
77
77
|
|
|
78
|
-
it.effect("converts a panel to a
|
|
78
|
+
it.effect("converts a panel to a Confluence-preserving placeholder", () =>
|
|
79
79
|
Effect.gen(function*() {
|
|
80
80
|
const converter = yield* MarkdownConverter
|
|
81
81
|
const md = yield* converter.adfToMarkdown(
|
|
@@ -85,18 +85,19 @@ describe("MarkdownConverter", () => {
|
|
|
85
85
|
content: [{ type: "paragraph", content: [{ type: "text", text: "heads up" }] }]
|
|
86
86
|
}])
|
|
87
87
|
)
|
|
88
|
-
expect(md).toContain("
|
|
88
|
+
expect(md).toContain("<!-- adf:panel type=info attrs=")
|
|
89
89
|
expect(md).toContain("heads up")
|
|
90
|
+
expect(md).toContain("<!-- adf:/panel -->")
|
|
90
91
|
}).pipe(Effect.provide(TestLayer)))
|
|
91
92
|
|
|
92
93
|
it.effect("fails with ConversionError on invalid JSON", () =>
|
|
93
94
|
Effect.gen(function*() {
|
|
94
95
|
const converter = yield* MarkdownConverter
|
|
95
|
-
const result = yield* Effect.
|
|
96
|
-
expect(result._tag).toBe("
|
|
97
|
-
if (result._tag === "
|
|
98
|
-
expect(result.
|
|
99
|
-
expect(result.
|
|
96
|
+
const result = yield* Effect.result(converter.adfToMarkdown("not json"))
|
|
97
|
+
expect(result._tag).toBe("Failure")
|
|
98
|
+
if (result._tag === "Failure") {
|
|
99
|
+
expect(result.failure._tag).toBe("ConversionError")
|
|
100
|
+
expect(result.failure.direction).toBe("adfToMarkdown")
|
|
100
101
|
}
|
|
101
102
|
}).pipe(Effect.provide(TestLayer)))
|
|
102
103
|
|
|
@@ -124,10 +125,10 @@ describe("MarkdownConverter", () => {
|
|
|
124
125
|
// page that could overwrite a real local file.
|
|
125
126
|
const converter = yield* MarkdownConverter
|
|
126
127
|
for (const bad of ["null", "{}", "[1,2]", `{"type":"doc","content":"not an array"}`]) {
|
|
127
|
-
const result = yield* Effect.
|
|
128
|
-
expect(result._tag).toBe("
|
|
129
|
-
if (result._tag === "
|
|
130
|
-
expect(result.
|
|
128
|
+
const result = yield* Effect.result(converter.adfToMarkdown(bad))
|
|
129
|
+
expect(result._tag).toBe("Failure")
|
|
130
|
+
if (result._tag === "Failure") {
|
|
131
|
+
expect(result.failure._tag).toBe("ConversionError")
|
|
131
132
|
}
|
|
132
133
|
}
|
|
133
134
|
}).pipe(Effect.provide(TestLayer)))
|
package/test/RoundTrip.test.ts
CHANGED
|
@@ -131,12 +131,20 @@ describe("MarkdownConverter round-trip", () => {
|
|
|
131
131
|
expect(md).toContain(`<span class="adf-status" data-color="blue">TESTING</span>`)
|
|
132
132
|
}).pipe(Effect.provide(TestLayer)))
|
|
133
133
|
|
|
134
|
-
it.effect("upgrades a legacy block extension placeholder to the attrs form, then stays fixed", () =>
|
|
134
|
+
it.effect("upgrades a legacy generic block extension placeholder to the attrs form, then stays fixed", () =>
|
|
135
135
|
Effect.gen(function*() {
|
|
136
136
|
const md = yield* roundTrip(
|
|
137
|
-
`<!-- adf:extension key=
|
|
137
|
+
`<!-- adf:extension key=anchor type=com.atlassian.confluence.macro.core -->\n`
|
|
138
138
|
)
|
|
139
|
-
expect(md).toContain("<!-- adf:extension key=
|
|
139
|
+
expect(md).toContain("<!-- adf:extension key=anchor type=com.atlassian.confluence.macro.core attrs=")
|
|
140
|
+
const again = yield* roundTrip(md)
|
|
141
|
+
expect(again).toBe(md)
|
|
142
|
+
}).pipe(Effect.provide(TestLayer)))
|
|
143
|
+
|
|
144
|
+
it.effect("round-trips native TOC syntax as a fixed point", () =>
|
|
145
|
+
Effect.gen(function*() {
|
|
146
|
+
const md = yield* roundTrip("[[toc:min=2,max=4]]\n")
|
|
147
|
+
expect(md).toContain("[[toc:min=2,max=4]]")
|
|
140
148
|
const again = yield* roundTrip(md)
|
|
141
149
|
expect(again).toBe(md)
|
|
142
150
|
}).pipe(Effect.provide(TestLayer)))
|
|
@@ -162,6 +170,34 @@ describe("MarkdownConverter round-trip", () => {
|
|
|
162
170
|
expect(adfOut.content[0]).toEqual({ type: "extension", attrs })
|
|
163
171
|
}).pipe(Effect.provide(TestLayer)))
|
|
164
172
|
|
|
173
|
+
it.effect("round-trips Confluence TOC macroMetadata through the placeholder attrs blob", () =>
|
|
174
|
+
Effect.gen(function*() {
|
|
175
|
+
const converter = yield* MarkdownConverter
|
|
176
|
+
const attrs = {
|
|
177
|
+
extensionKey: "toc",
|
|
178
|
+
extensionType: "com.atlassian.confluence.macro.core",
|
|
179
|
+
layout: "default",
|
|
180
|
+
parameters: {
|
|
181
|
+
macroMetadata: {
|
|
182
|
+
schemaVersion: { value: "1" },
|
|
183
|
+
title: "Table of Contents"
|
|
184
|
+
},
|
|
185
|
+
macroParams: {}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const md = yield* converter.adfToMarkdown(JSON.stringify({
|
|
189
|
+
version: 1,
|
|
190
|
+
type: "doc",
|
|
191
|
+
content: [{ type: "extension", attrs }]
|
|
192
|
+
}))
|
|
193
|
+
expect(md).toContain("<!-- adf:extension key=toc type=com.atlassian.confluence.macro.core attrs=")
|
|
194
|
+
expect(md).not.toContain("[[toc")
|
|
195
|
+
const adfOut = JSON.parse(yield* converter.markdownToAdf(md)) as {
|
|
196
|
+
content: Array<{ type: string; attrs: Record<string, unknown> }>
|
|
197
|
+
}
|
|
198
|
+
expect(adfOut.content[0]).toEqual({ type: "extension", attrs })
|
|
199
|
+
}).pipe(Effect.provide(TestLayer)))
|
|
200
|
+
|
|
165
201
|
it.effect("round-trips a bodiedExtension with its body re-attached", () =>
|
|
166
202
|
Effect.gen(function*() {
|
|
167
203
|
const converter = yield* MarkdownConverter
|
|
@@ -189,6 +225,225 @@ describe("MarkdownConverter round-trip", () => {
|
|
|
189
225
|
])
|
|
190
226
|
}).pipe(Effect.provide(TestLayer)))
|
|
191
227
|
|
|
228
|
+
it.effect("round-trips a Confluence panel as a panel node", () =>
|
|
229
|
+
Effect.gen(function*() {
|
|
230
|
+
const converter = yield* MarkdownConverter
|
|
231
|
+
const attrs = { panelType: "warning" }
|
|
232
|
+
const md = yield* converter.adfToMarkdown(JSON.stringify({
|
|
233
|
+
version: 1,
|
|
234
|
+
type: "doc",
|
|
235
|
+
content: [{
|
|
236
|
+
type: "panel",
|
|
237
|
+
attrs,
|
|
238
|
+
content: [{ type: "paragraph", content: [{ type: "text", text: "watch this" }] }]
|
|
239
|
+
}]
|
|
240
|
+
}))
|
|
241
|
+
const adfOut = JSON.parse(yield* converter.markdownToAdf(md)) as {
|
|
242
|
+
content: Array<{ type: string; attrs: Record<string, unknown>; content: Array<unknown> }>
|
|
243
|
+
}
|
|
244
|
+
expect(adfOut.content[0]).toEqual({
|
|
245
|
+
type: "panel",
|
|
246
|
+
attrs,
|
|
247
|
+
content: [{ type: "paragraph", content: [{ type: "text", text: "watch this" }] }]
|
|
248
|
+
})
|
|
249
|
+
}).pipe(Effect.provide(TestLayer)))
|
|
250
|
+
|
|
251
|
+
it.effect("round-trips Confluence-only inline marks as native marks", () =>
|
|
252
|
+
Effect.gen(function*() {
|
|
253
|
+
const converter = yield* MarkdownConverter
|
|
254
|
+
const source = {
|
|
255
|
+
version: 1,
|
|
256
|
+
type: "doc",
|
|
257
|
+
content: [{
|
|
258
|
+
type: "paragraph",
|
|
259
|
+
content: [
|
|
260
|
+
{ type: "text", text: "underline", marks: [{ type: "underline" }] },
|
|
261
|
+
{ type: "text", text: "2", marks: [{ type: "subsup", attrs: { type: "sub" } }] },
|
|
262
|
+
{ type: "text", text: "2", marks: [{ type: "subsup", attrs: { type: "sup" } }] },
|
|
263
|
+
{ type: "text", text: "Colored", marks: [{ type: "textColor", attrs: { color: "#ff5630" } }] },
|
|
264
|
+
{ type: "text", text: "highlighted", marks: [{ type: "backgroundColor", attrs: { color: "#f8e6a0" } }] }
|
|
265
|
+
]
|
|
266
|
+
}]
|
|
267
|
+
}
|
|
268
|
+
const md = yield* converter.adfToMarkdown(JSON.stringify(source))
|
|
269
|
+
const adfOut = JSON.parse(yield* converter.markdownToAdf(md)) as typeof source
|
|
270
|
+
expect(adfOut.content[0]).toEqual(source.content[0])
|
|
271
|
+
}).pipe(Effect.provide(TestLayer)))
|
|
272
|
+
|
|
273
|
+
it.effect("round-trips paragraph alignment and indentation marks", () =>
|
|
274
|
+
Effect.gen(function*() {
|
|
275
|
+
const converter = yield* MarkdownConverter
|
|
276
|
+
const source = {
|
|
277
|
+
version: 1,
|
|
278
|
+
type: "doc",
|
|
279
|
+
content: [
|
|
280
|
+
{
|
|
281
|
+
type: "paragraph",
|
|
282
|
+
marks: [{ type: "alignment", attrs: { align: "center" } }],
|
|
283
|
+
content: [{ type: "text", text: "centered" }]
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
type: "paragraph",
|
|
287
|
+
marks: [{ type: "alignment", attrs: { align: "end" } }],
|
|
288
|
+
content: [{ type: "text", text: "right" }]
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
type: "paragraph",
|
|
292
|
+
marks: [{ type: "indentation", attrs: { level: 2 } }],
|
|
293
|
+
content: [{ type: "text", text: "indented" }]
|
|
294
|
+
}
|
|
295
|
+
]
|
|
296
|
+
}
|
|
297
|
+
const md = yield* converter.adfToMarkdown(JSON.stringify(source))
|
|
298
|
+
const adfOut = JSON.parse(yield* converter.markdownToAdf(md)) as typeof source
|
|
299
|
+
expect(adfOut.content).toEqual(source.content)
|
|
300
|
+
}).pipe(Effect.provide(TestLayer)))
|
|
301
|
+
|
|
302
|
+
it.effect("round-trips inline smart links as native inlineCard nodes", () =>
|
|
303
|
+
Effect.gen(function*() {
|
|
304
|
+
const converter = yield* MarkdownConverter
|
|
305
|
+
const source = {
|
|
306
|
+
version: 1,
|
|
307
|
+
type: "doc",
|
|
308
|
+
content: [{
|
|
309
|
+
type: "paragraph",
|
|
310
|
+
content: [
|
|
311
|
+
{ type: "text", text: "Inline smart link: " },
|
|
312
|
+
{ type: "inlineCard", attrs: { url: "https://www.atlassian.com" } },
|
|
313
|
+
{ type: "text", text: "." }
|
|
314
|
+
]
|
|
315
|
+
}]
|
|
316
|
+
}
|
|
317
|
+
const md = yield* converter.adfToMarkdown(JSON.stringify(source))
|
|
318
|
+
const adfOut = JSON.parse(yield* converter.markdownToAdf(md)) as typeof source
|
|
319
|
+
expect(adfOut.content[0]).toEqual(source.content[0])
|
|
320
|
+
}).pipe(Effect.provide(TestLayer)))
|
|
321
|
+
|
|
322
|
+
it.effect("round-trips task lists as native task nodes", () =>
|
|
323
|
+
Effect.gen(function*() {
|
|
324
|
+
const converter = yield* MarkdownConverter
|
|
325
|
+
const source = {
|
|
326
|
+
version: 1,
|
|
327
|
+
type: "doc",
|
|
328
|
+
content: [{
|
|
329
|
+
type: "taskList",
|
|
330
|
+
attrs: { localId: "tasks-1" },
|
|
331
|
+
content: [
|
|
332
|
+
{
|
|
333
|
+
type: "taskItem",
|
|
334
|
+
attrs: { localId: "task-1", state: "DONE" },
|
|
335
|
+
content: [{ type: "text", text: "Existing primitive coverage reviewed" }]
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
type: "taskItem",
|
|
339
|
+
attrs: { localId: "task-2", state: "TODO" },
|
|
340
|
+
content: [{ type: "text", text: "Insert real @mention in editor" }]
|
|
341
|
+
}
|
|
342
|
+
]
|
|
343
|
+
}]
|
|
344
|
+
}
|
|
345
|
+
const md = yield* converter.adfToMarkdown(JSON.stringify(source))
|
|
346
|
+
const adfOut = JSON.parse(yield* converter.markdownToAdf(md)) as typeof source
|
|
347
|
+
expect(adfOut.content[0]).toEqual(source.content[0])
|
|
348
|
+
}).pipe(Effect.provide(TestLayer)))
|
|
349
|
+
|
|
350
|
+
it.effect("round-trips decision lists as native decision nodes", () =>
|
|
351
|
+
Effect.gen(function*() {
|
|
352
|
+
const converter = yield* MarkdownConverter
|
|
353
|
+
const source = {
|
|
354
|
+
version: 1,
|
|
355
|
+
type: "doc",
|
|
356
|
+
content: [{
|
|
357
|
+
type: "decisionList",
|
|
358
|
+
attrs: { localId: "decisions-1" },
|
|
359
|
+
content: [{
|
|
360
|
+
type: "decisionItem",
|
|
361
|
+
attrs: { localId: "decision-1", state: "DECIDED" },
|
|
362
|
+
content: [{ type: "text", text: "Decide whether to maintain a separate asset for advanced macros." }]
|
|
363
|
+
}]
|
|
364
|
+
}]
|
|
365
|
+
}
|
|
366
|
+
const md = yield* converter.adfToMarkdown(JSON.stringify(source))
|
|
367
|
+
const adfOut = JSON.parse(yield* converter.markdownToAdf(md)) as typeof source
|
|
368
|
+
expect(adfOut.content[0]).toEqual(source.content[0])
|
|
369
|
+
}).pipe(Effect.provide(TestLayer)))
|
|
370
|
+
|
|
371
|
+
it.effect("round-trips expand, table, layout, cards, date, and emoji as native nodes", () =>
|
|
372
|
+
Effect.gen(function*() {
|
|
373
|
+
const converter = yield* MarkdownConverter
|
|
374
|
+
const source = {
|
|
375
|
+
version: 1,
|
|
376
|
+
type: "doc",
|
|
377
|
+
content: [
|
|
378
|
+
{
|
|
379
|
+
type: "expand",
|
|
380
|
+
attrs: { title: "Expandable supplementary content" },
|
|
381
|
+
content: [{ type: "paragraph", content: [{ type: "text", text: "This section can be expanded." }] }]
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
type: "table",
|
|
385
|
+
content: [{
|
|
386
|
+
type: "tableRow",
|
|
387
|
+
content: [
|
|
388
|
+
{
|
|
389
|
+
type: "tableHeader",
|
|
390
|
+
content: [{ type: "paragraph", content: [{ type: "text", text: "Primitive" }] }]
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
type: "tableHeader",
|
|
394
|
+
content: [{ type: "paragraph", content: [{ type: "text", text: "Example" }] }]
|
|
395
|
+
}
|
|
396
|
+
]
|
|
397
|
+
}, {
|
|
398
|
+
type: "tableRow",
|
|
399
|
+
content: [
|
|
400
|
+
{ type: "tableCell", content: [{ type: "paragraph", content: [{ type: "text", text: "Date" }] }] },
|
|
401
|
+
{
|
|
402
|
+
type: "tableCell",
|
|
403
|
+
content: [{
|
|
404
|
+
type: "paragraph",
|
|
405
|
+
content: [{ type: "date", attrs: { timestamp: "1782259200000" } }]
|
|
406
|
+
}]
|
|
407
|
+
}
|
|
408
|
+
]
|
|
409
|
+
}, {
|
|
410
|
+
type: "tableRow",
|
|
411
|
+
content: [
|
|
412
|
+
{ type: "tableCell", content: [{ type: "paragraph", content: [{ type: "text", text: "Emoji" }] }] },
|
|
413
|
+
{
|
|
414
|
+
type: "tableCell",
|
|
415
|
+
content: [{
|
|
416
|
+
type: "paragraph",
|
|
417
|
+
content: [{ type: "emoji", attrs: { shortName: ":white_check_mark:", text: "✅" } }]
|
|
418
|
+
}]
|
|
419
|
+
}
|
|
420
|
+
]
|
|
421
|
+
}]
|
|
422
|
+
},
|
|
423
|
+
{
|
|
424
|
+
type: "layoutSection",
|
|
425
|
+
content: [
|
|
426
|
+
{
|
|
427
|
+
type: "layoutColumn",
|
|
428
|
+
attrs: { width: 50 },
|
|
429
|
+
content: [{ type: "paragraph", content: [{ type: "text", text: "Left column" }] }]
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
type: "layoutColumn",
|
|
433
|
+
attrs: { width: 50 },
|
|
434
|
+
content: [{ type: "paragraph", content: [{ type: "text", text: "Right column" }] }]
|
|
435
|
+
}
|
|
436
|
+
]
|
|
437
|
+
},
|
|
438
|
+
{ type: "blockCard", attrs: { url: "https://www.atlassian.com/software/confluence" } },
|
|
439
|
+
{ type: "embedCard", attrs: { url: "https://www.atlassian.com/software/confluence", layout: "center" } }
|
|
440
|
+
]
|
|
441
|
+
}
|
|
442
|
+
const md = yield* converter.adfToMarkdown(JSON.stringify(source))
|
|
443
|
+
const adfOut = JSON.parse(yield* converter.markdownToAdf(md)) as typeof source
|
|
444
|
+
expect(adfOut.content).toEqual(source.content)
|
|
445
|
+
}).pipe(Effect.provide(TestLayer)))
|
|
446
|
+
|
|
192
447
|
// Regression: `|` in a cell was escaped twice (escapeText + the table-cell
|
|
193
448
|
// pass), emitting `\\|` — GFM reads that as literal backslash + bare pipe,
|
|
194
449
|
// which opens a phantom column and breaks the row.
|
package/test/Schemas.test.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from "@effect/vitest"
|
|
2
|
-
import * as
|
|
2
|
+
import * as Result from "effect/Result"
|
|
3
3
|
import * as Schema from "effect/Schema"
|
|
4
4
|
import type { ContentHash, PageId } from "../src/Brand.js"
|
|
5
5
|
import {
|
|
@@ -17,11 +17,11 @@ describe("Schemas", () => {
|
|
|
17
17
|
rootPageId: "123456",
|
|
18
18
|
baseUrl: "https://mysite.atlassian.net"
|
|
19
19
|
}
|
|
20
|
-
const result = Schema.
|
|
21
|
-
expect(
|
|
22
|
-
if (
|
|
23
|
-
expect(result.
|
|
24
|
-
expect(result.
|
|
20
|
+
const result = Schema.decodeUnknownResult(ConfluenceConfigFileSchema)(config)
|
|
21
|
+
expect(Result.isSuccess(result)).toBe(true)
|
|
22
|
+
if (Result.isSuccess(result)) {
|
|
23
|
+
expect(result.success.docsPath).toBe(".confluence/docs")
|
|
24
|
+
expect(result.success.excludePatterns).toEqual([])
|
|
25
25
|
}
|
|
26
26
|
})
|
|
27
27
|
|
|
@@ -33,11 +33,11 @@ describe("Schemas", () => {
|
|
|
33
33
|
docsPath: "docs",
|
|
34
34
|
excludePatterns: ["*.tmp"]
|
|
35
35
|
}
|
|
36
|
-
const result = Schema.
|
|
37
|
-
expect(
|
|
38
|
-
if (
|
|
39
|
-
expect(result.
|
|
40
|
-
expect(result.
|
|
36
|
+
const result = Schema.decodeUnknownResult(ConfluenceConfigFileSchema)(config)
|
|
37
|
+
expect(Result.isSuccess(result)).toBe(true)
|
|
38
|
+
if (Result.isSuccess(result)) {
|
|
39
|
+
expect(result.success.spaceKey).toBe("DEV")
|
|
40
|
+
expect(result.success.docsPath).toBe("docs")
|
|
41
41
|
}
|
|
42
42
|
})
|
|
43
43
|
|
|
@@ -46,14 +46,14 @@ describe("Schemas", () => {
|
|
|
46
46
|
rootPageId: "123456",
|
|
47
47
|
baseUrl: "http://invalid.com"
|
|
48
48
|
}
|
|
49
|
-
const result = Schema.
|
|
50
|
-
expect(
|
|
49
|
+
const result = Schema.decodeUnknownResult(ConfluenceConfigFileSchema)(config)
|
|
50
|
+
expect(Result.isFailure(result)).toBe(true)
|
|
51
51
|
})
|
|
52
52
|
|
|
53
53
|
it("rejects missing required fields", () => {
|
|
54
54
|
const config = { baseUrl: "https://mysite.atlassian.net" }
|
|
55
|
-
const result = Schema.
|
|
56
|
-
expect(
|
|
55
|
+
const result = Schema.decodeUnknownResult(ConfluenceConfigFileSchema)(config)
|
|
56
|
+
expect(Result.isFailure(result)).toBe(true)
|
|
57
57
|
})
|
|
58
58
|
})
|
|
59
59
|
|
|
@@ -68,8 +68,8 @@ describe("Schemas", () => {
|
|
|
68
68
|
updated: new Date().toISOString(),
|
|
69
69
|
contentHash: validHash
|
|
70
70
|
}
|
|
71
|
-
const result = Schema.
|
|
72
|
-
expect(
|
|
71
|
+
const result = Schema.decodeUnknownResult(PageFrontMatterSchema)(fm)
|
|
72
|
+
expect(Result.isSuccess(result)).toBe(true)
|
|
73
73
|
})
|
|
74
74
|
|
|
75
75
|
it("decodes front matter with optional fields", () => {
|
|
@@ -82,11 +82,11 @@ describe("Schemas", () => {
|
|
|
82
82
|
position: 0,
|
|
83
83
|
contentHash: validHash
|
|
84
84
|
}
|
|
85
|
-
const result = Schema.
|
|
86
|
-
expect(
|
|
87
|
-
if (
|
|
88
|
-
expect(result.
|
|
89
|
-
expect(result.
|
|
85
|
+
const result = Schema.decodeUnknownResult(PageFrontMatterSchema)(fm)
|
|
86
|
+
expect(Result.isSuccess(result)).toBe(true)
|
|
87
|
+
if (Result.isSuccess(result)) {
|
|
88
|
+
expect(result.success.parentId).toBe("456")
|
|
89
|
+
expect(result.success.position).toBe(0)
|
|
90
90
|
}
|
|
91
91
|
})
|
|
92
92
|
|
|
@@ -98,8 +98,8 @@ describe("Schemas", () => {
|
|
|
98
98
|
updated: new Date().toISOString(),
|
|
99
99
|
contentHash: validHash
|
|
100
100
|
}
|
|
101
|
-
const result = Schema.
|
|
102
|
-
expect(
|
|
101
|
+
const result = Schema.decodeUnknownResult(PageFrontMatterSchema)(fm)
|
|
102
|
+
expect(Result.isFailure(result)).toBe(true)
|
|
103
103
|
})
|
|
104
104
|
})
|
|
105
105
|
|
|
@@ -113,8 +113,8 @@ describe("Schemas", () => {
|
|
|
113
113
|
cloud_id: "abc123",
|
|
114
114
|
site_url: "https://mysite.atlassian.net"
|
|
115
115
|
}
|
|
116
|
-
const result = Schema.
|
|
117
|
-
expect(
|
|
116
|
+
const result = Schema.decodeUnknownResult(OAuthTokenSchema)(token)
|
|
117
|
+
expect(Result.isSuccess(result)).toBe(true)
|
|
118
118
|
})
|
|
119
119
|
|
|
120
120
|
it("decodes token with user info", () => {
|
|
@@ -131,10 +131,10 @@ describe("Schemas", () => {
|
|
|
131
131
|
email: "test@example.com"
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
|
-
const result = Schema.
|
|
135
|
-
expect(
|
|
136
|
-
if (
|
|
137
|
-
expect(result.
|
|
134
|
+
const result = Schema.decodeUnknownResult(OAuthTokenSchema)(token)
|
|
135
|
+
expect(Result.isSuccess(result)).toBe(true)
|
|
136
|
+
if (Result.isSuccess(result)) {
|
|
137
|
+
expect(result.success.user?.name).toBe("Test User")
|
|
138
138
|
}
|
|
139
139
|
})
|
|
140
140
|
|
|
@@ -147,8 +147,8 @@ describe("Schemas", () => {
|
|
|
147
147
|
cloud_id: "abc123",
|
|
148
148
|
site_url: "https://mysite.atlassian.net"
|
|
149
149
|
}
|
|
150
|
-
const result = Schema.
|
|
151
|
-
expect(
|
|
150
|
+
const result = Schema.decodeUnknownResult(OAuthTokenSchema)(token)
|
|
151
|
+
expect(Result.isFailure(result)).toBe(true)
|
|
152
152
|
})
|
|
153
153
|
})
|
|
154
154
|
|
|
@@ -158,16 +158,16 @@ describe("Schemas", () => {
|
|
|
158
158
|
clientId: "client_id_value",
|
|
159
159
|
clientSecret: "client_secret_value"
|
|
160
160
|
}
|
|
161
|
-
const result = Schema.
|
|
162
|
-
expect(
|
|
161
|
+
const result = Schema.decodeUnknownResult(OAuthConfigSchema)(config)
|
|
162
|
+
expect(Result.isSuccess(result)).toBe(true)
|
|
163
163
|
})
|
|
164
164
|
|
|
165
165
|
it("rejects missing clientSecret", () => {
|
|
166
166
|
const config = {
|
|
167
167
|
clientId: "client_id_value"
|
|
168
168
|
}
|
|
169
|
-
const result = Schema.
|
|
170
|
-
expect(
|
|
169
|
+
const result = Schema.decodeUnknownResult(OAuthConfigSchema)(config)
|
|
170
|
+
expect(Result.isFailure(result)).toBe(true)
|
|
171
171
|
})
|
|
172
172
|
})
|
|
173
173
|
|
|
@@ -178,8 +178,8 @@ describe("Schemas", () => {
|
|
|
178
178
|
name: "Test User",
|
|
179
179
|
email: "test@example.com"
|
|
180
180
|
}
|
|
181
|
-
const result = Schema.
|
|
182
|
-
expect(
|
|
181
|
+
const result = Schema.decodeUnknownResult(OAuthUserSchema)(user)
|
|
182
|
+
expect(Result.isSuccess(result)).toBe(true)
|
|
183
183
|
})
|
|
184
184
|
|
|
185
185
|
it("rejects missing email", () => {
|
|
@@ -187,8 +187,8 @@ describe("Schemas", () => {
|
|
|
187
187
|
account_id: "user123",
|
|
188
188
|
name: "Test User"
|
|
189
189
|
}
|
|
190
|
-
const result = Schema.
|
|
191
|
-
expect(
|
|
190
|
+
const result = Schema.decodeUnknownResult(OAuthUserSchema)(user)
|
|
191
|
+
expect(Result.isFailure(result)).toBe(true)
|
|
192
192
|
})
|
|
193
193
|
})
|
|
194
194
|
})
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { describe, expect, it } from "@effect/vitest"
|
|
2
|
+
import { collectAdfMetadataHrefs, externalizeAdfMetadata, hydrateAdfMetadata } from "../src/internal/adfMetadata.js"
|
|
3
|
+
|
|
4
|
+
const toBase64 = (text: string): string => {
|
|
5
|
+
const bytes = new TextEncoder().encode(text)
|
|
6
|
+
return btoa(String.fromCharCode(...bytes))
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
describe("ADF metadata sidecars", () => {
|
|
10
|
+
it("moves decoded placeholder metadata into a linked sidecar", () => {
|
|
11
|
+
const markdown = [
|
|
12
|
+
`<!-- adf:panel type=info attrs={"panelType":"info"} -->`,
|
|
13
|
+
"",
|
|
14
|
+
"Body",
|
|
15
|
+
"",
|
|
16
|
+
"<!-- adf:/panel -->",
|
|
17
|
+
"",
|
|
18
|
+
`Regular link: <!-- adf:inlineCard attrs={"url":"https://www.atlassian.com"} -->.`
|
|
19
|
+
].join("\n")
|
|
20
|
+
|
|
21
|
+
const prepared = externalizeAdfMetadata(markdown, "./123.adf.json")
|
|
22
|
+
|
|
23
|
+
expect(prepared.markdown).toContain("<!-- adf:panel type=info ref=./123.adf.json#panel-1 -->")
|
|
24
|
+
expect(prepared.markdown).toContain("<!-- adf:inlineCard ref=./123.adf.json#inlineCard-2 -->")
|
|
25
|
+
expect(prepared.markdown).not.toContain("attrs={")
|
|
26
|
+
expect(prepared.sidecar).toEqual({
|
|
27
|
+
version: 1,
|
|
28
|
+
entries: {
|
|
29
|
+
"panel-1": {
|
|
30
|
+
kind: "attrs",
|
|
31
|
+
value: { panelType: "info" }
|
|
32
|
+
},
|
|
33
|
+
"inlineCard-2": {
|
|
34
|
+
kind: "attrs",
|
|
35
|
+
value: { url: "https://www.atlassian.com" }
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it("moves base64 placeholder metadata into a linked sidecar", () => {
|
|
42
|
+
const attrs = {
|
|
43
|
+
extensionKey: "toc",
|
|
44
|
+
extensionType: "com.atlassian.confluence.macro.core",
|
|
45
|
+
parameters: {
|
|
46
|
+
macroMetadata: {
|
|
47
|
+
title: "Table of Contents"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const encodedAttrs = toBase64(JSON.stringify(attrs))
|
|
52
|
+
const markdown =
|
|
53
|
+
`| **On this page** | <!-- adf:extension key=toc type=com.atlassian.confluence.macro.core attrs=${encodedAttrs} --> |`
|
|
54
|
+
|
|
55
|
+
const prepared = externalizeAdfMetadata(markdown, "./2731114497.adf.json")
|
|
56
|
+
|
|
57
|
+
expect(prepared.markdown).toBe(
|
|
58
|
+
"| **On this page** | <!-- adf:extension key=toc type=com.atlassian.confluence.macro.core ref=./2731114497.adf.json#extension-1 --> |"
|
|
59
|
+
)
|
|
60
|
+
expect(prepared.markdown).not.toContain(encodedAttrs)
|
|
61
|
+
expect(prepared.sidecar).toEqual({
|
|
62
|
+
version: 1,
|
|
63
|
+
entries: {
|
|
64
|
+
"extension-1": {
|
|
65
|
+
kind: "attrs",
|
|
66
|
+
value: attrs
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it("hydrates linked sidecar metadata back into placeholders for push", () => {
|
|
73
|
+
const markdown = `<!-- adf:taskList ref=./123.adf.json#taskList-1 -->`
|
|
74
|
+
const hydrated = hydrateAdfMetadata(
|
|
75
|
+
markdown,
|
|
76
|
+
new Map([
|
|
77
|
+
[
|
|
78
|
+
"./123.adf.json",
|
|
79
|
+
{
|
|
80
|
+
version: 1,
|
|
81
|
+
entries: {
|
|
82
|
+
"taskList-1": {
|
|
83
|
+
kind: "node",
|
|
84
|
+
value: {
|
|
85
|
+
type: "taskList",
|
|
86
|
+
attrs: { localId: "task-list" },
|
|
87
|
+
content: [{ type: "taskItem", attrs: { state: "DONE" } }]
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
])
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
expect(hydrated).toBe(
|
|
97
|
+
`<!-- adf:taskList node={"attrs":{"localId":"task-list"},"content":[{"attrs":{"state":"DONE"},"type":"taskItem"}],"type":"taskList"} -->`
|
|
98
|
+
)
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it("collects each referenced sidecar href once", () => {
|
|
102
|
+
const hrefs = collectAdfMetadataHrefs([
|
|
103
|
+
"<!-- adf:panel ref=./123.adf.json#panel-1 -->",
|
|
104
|
+
"<!-- adf:taskList ref=./123.adf.json#taskList-2 -->",
|
|
105
|
+
"<!-- adf:panel ref=./456.adf.json#panel-1 -->"
|
|
106
|
+
].join("\n"))
|
|
107
|
+
|
|
108
|
+
expect([...hrefs].sort()).toEqual(["./123.adf.json", "./456.adf.json"])
|
|
109
|
+
})
|
|
110
|
+
})
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { describe, expect, it } from "@effect/vitest"
|
|
2
|
+
import { cleanMarkdown } from "../src/internal/cleanMarkdown.js"
|
|
3
|
+
|
|
4
|
+
describe("cleanMarkdown", () => {
|
|
5
|
+
it("removes full-line ADF metadata comments", () => {
|
|
6
|
+
const markdown = [
|
|
7
|
+
"# Title",
|
|
8
|
+
"",
|
|
9
|
+
"<!-- adf:panel type=info attrs={} -->",
|
|
10
|
+
"",
|
|
11
|
+
"Body",
|
|
12
|
+
"",
|
|
13
|
+
"<!-- adf:/panel -->"
|
|
14
|
+
].join("\n")
|
|
15
|
+
|
|
16
|
+
expect(cleanMarkdown(markdown)).toBe("# Title\n\nBody\n")
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it("removes inline ADF metadata comments", () => {
|
|
20
|
+
expect(cleanMarkdown("Card <!-- adf:inlineCard attrs={} --> text")).toBe("Card text\n")
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it("keeps regular markdown, native macros, status spans, and non-ADF comments", () => {
|
|
24
|
+
const markdown = [
|
|
25
|
+
"[[toc]]",
|
|
26
|
+
"",
|
|
27
|
+
"<span data-adf-status=\"todo\" data-adf-color=\"blue\">TODO</span>",
|
|
28
|
+
"",
|
|
29
|
+
"<!-- keep this comment -->",
|
|
30
|
+
"",
|
|
31
|
+
"- item"
|
|
32
|
+
].join("\n")
|
|
33
|
+
|
|
34
|
+
expect(cleanMarkdown(markdown)).toBe(`${markdown}\n`)
|
|
35
|
+
})
|
|
36
|
+
})
|