@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
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import * as Effect from "effect/Effect"
|
|
8
8
|
import * as Schema from "effect/Schema"
|
|
9
|
-
import
|
|
9
|
+
import * as yaml from "js-yaml"
|
|
10
10
|
import { FrontMatterError } from "../ConfluenceError.js"
|
|
11
11
|
import type { NewPageFrontMatter, PageFrontMatter } from "../Schemas.js"
|
|
12
12
|
import { NewPageFrontMatterSchema, PageFrontMatterSchema } from "../Schemas.js"
|
|
@@ -20,6 +20,33 @@ export interface ParsedMarkdown {
|
|
|
20
20
|
readonly isNew: boolean
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
const parseRawMarkdown = (content: string): { readonly data: Record<string, unknown>; readonly content: string } => {
|
|
24
|
+
if (!content.startsWith("---\n") && !content.startsWith("---\r\n")) {
|
|
25
|
+
return { data: {}, content }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const newline = content.startsWith("---\r\n") ? "\r\n" : "\n"
|
|
29
|
+
const headerStart = 3 + newline.length
|
|
30
|
+
const closingMarker = `${newline}---`
|
|
31
|
+
const closingStart = content.indexOf(closingMarker, headerStart)
|
|
32
|
+
if (closingStart === -1) {
|
|
33
|
+
return { data: {}, content }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const header = content.slice(headerStart, closingStart)
|
|
37
|
+
const afterClosingStart = closingStart + closingMarker.length
|
|
38
|
+
const afterClosing = content.startsWith("\r\n", afterClosingStart)
|
|
39
|
+
? content.slice(afterClosingStart + 2)
|
|
40
|
+
: content.startsWith("\n", afterClosingStart)
|
|
41
|
+
? content.slice(afterClosingStart + 1)
|
|
42
|
+
: content.slice(afterClosingStart)
|
|
43
|
+
const loaded = yaml.load(header)
|
|
44
|
+
const data = loaded !== null && typeof loaded === "object" && !Array.isArray(loaded)
|
|
45
|
+
? loaded as Record<string, unknown>
|
|
46
|
+
: {}
|
|
47
|
+
return { data, content: afterClosing }
|
|
48
|
+
}
|
|
49
|
+
|
|
23
50
|
/**
|
|
24
51
|
* Parse a markdown file with YAML front-matter.
|
|
25
52
|
*
|
|
@@ -35,7 +62,7 @@ export const parseMarkdown = (
|
|
|
35
62
|
): Effect.Effect<ParsedMarkdown, FrontMatterError> =>
|
|
36
63
|
Effect.gen(function*() {
|
|
37
64
|
const parsed = yield* Effect.try({
|
|
38
|
-
try: () =>
|
|
65
|
+
try: () => parseRawMarkdown(content),
|
|
39
66
|
catch: (cause) => new FrontMatterError({ path: filePath, cause })
|
|
40
67
|
})
|
|
41
68
|
|
|
@@ -49,21 +76,21 @@ export const parseMarkdown = (
|
|
|
49
76
|
}
|
|
50
77
|
|
|
51
78
|
// Try to parse as existing page front-matter
|
|
52
|
-
const existingResult = yield* Schema.
|
|
79
|
+
const existingResult = yield* Schema.decodeUnknownEffect(PageFrontMatterSchema)(parsed.data).pipe(
|
|
53
80
|
Effect.map((fm) => ({
|
|
54
81
|
frontMatter: fm,
|
|
55
82
|
content: parsed.content.trim(),
|
|
56
83
|
isNew: false
|
|
57
84
|
})),
|
|
58
|
-
Effect.
|
|
85
|
+
Effect.catchCause(() =>
|
|
59
86
|
// Try to parse as new page front-matter
|
|
60
|
-
Schema.
|
|
87
|
+
Schema.decodeUnknownEffect(NewPageFrontMatterSchema)(parsed.data).pipe(
|
|
61
88
|
Effect.map((fm) => ({
|
|
62
89
|
frontMatter: fm as NewPageFrontMatter,
|
|
63
90
|
content: parsed.content.trim(),
|
|
64
91
|
isNew: true
|
|
65
92
|
})),
|
|
66
|
-
Effect.
|
|
93
|
+
Effect.catchCause((cause) => Effect.fail(new FrontMatterError({ path: filePath, cause })))
|
|
67
94
|
)
|
|
68
95
|
)
|
|
69
96
|
)
|
|
@@ -94,7 +121,7 @@ export const serializeMarkdown = (
|
|
|
94
121
|
contentHash: frontMatter.contentHash
|
|
95
122
|
}
|
|
96
123
|
|
|
97
|
-
return
|
|
124
|
+
return stringifyFrontmatter(content, fm)
|
|
98
125
|
}
|
|
99
126
|
|
|
100
127
|
/**
|
|
@@ -115,5 +142,15 @@ export const serializeNewPageMarkdown = (
|
|
|
115
142
|
...(frontMatter.parentId !== undefined ? { parentId: frontMatter.parentId } : {})
|
|
116
143
|
}
|
|
117
144
|
|
|
118
|
-
return
|
|
145
|
+
return stringifyFrontmatter(content, fm)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const stringifyFrontmatter = (content: string, frontMatter: Record<string, unknown>): string => {
|
|
149
|
+
const header = yaml.dump(frontMatter, {
|
|
150
|
+
lineWidth: -1,
|
|
151
|
+
noRefs: true,
|
|
152
|
+
sortKeys: false
|
|
153
|
+
}).trimEnd()
|
|
154
|
+
const body = content.endsWith("\n") ? content : `${content}\n`
|
|
155
|
+
return `---\n${header}\n---\n${body}`
|
|
119
156
|
}
|
|
@@ -4,11 +4,10 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
* @internal
|
|
6
6
|
*/
|
|
7
|
-
import * as Command from "@effect/platform/Command"
|
|
8
|
-
import type * as CommandExecutor from "@effect/platform/CommandExecutor"
|
|
9
|
-
import type * as PlatformError from "@effect/platform/Error"
|
|
10
7
|
import * as Effect from "effect/Effect"
|
|
11
|
-
import * as
|
|
8
|
+
import * as EffectString from "effect/String"
|
|
9
|
+
import { ChildProcessSpawner } from "effect/unstable/process"
|
|
10
|
+
import * as ChildProcess from "effect/unstable/process/ChildProcess"
|
|
12
11
|
import { GitError, GitNotInstalledError } from "../GitError.js"
|
|
13
12
|
|
|
14
13
|
/**
|
|
@@ -48,17 +47,26 @@ export interface GitLogEntry {
|
|
|
48
47
|
* Convert PlatformError to GitError or GitNotInstalledError.
|
|
49
48
|
*/
|
|
50
49
|
const mapPlatformError = (
|
|
51
|
-
error:
|
|
50
|
+
error: unknown,
|
|
52
51
|
commandStr: string
|
|
53
52
|
): GitError | GitNotInstalledError => {
|
|
54
|
-
if (
|
|
53
|
+
if (
|
|
54
|
+
typeof error === "object"
|
|
55
|
+
&& error !== null
|
|
56
|
+
&& "_tag" in error
|
|
57
|
+
&& "reason" in error
|
|
58
|
+
&& error._tag === "SystemError"
|
|
59
|
+
&& error.reason === "NotFound"
|
|
60
|
+
) {
|
|
61
|
+
const message = "message" in error ? globalThis.String(error.message) : "command not found"
|
|
55
62
|
return new GitNotInstalledError({
|
|
56
|
-
message: `Git not found: ${
|
|
63
|
+
message: `Git not found: ${message}. Please install git.`
|
|
57
64
|
})
|
|
58
65
|
}
|
|
66
|
+
const message = error instanceof Error ? error.message : globalThis.String(error)
|
|
59
67
|
return new GitError({
|
|
60
68
|
command: commandStr,
|
|
61
|
-
message
|
|
69
|
+
message
|
|
62
70
|
})
|
|
63
71
|
}
|
|
64
72
|
|
|
@@ -74,15 +82,13 @@ const mapPlatformError = (
|
|
|
74
82
|
export const runGit = (
|
|
75
83
|
args: ReadonlyArray<string>,
|
|
76
84
|
cwd: string
|
|
77
|
-
): Effect.Effect<string, GitError | GitNotInstalledError,
|
|
85
|
+
): Effect.Effect<string, GitError | GitNotInstalledError, ChildProcessSpawner.ChildProcessSpawner> =>
|
|
78
86
|
Effect.gen(function*() {
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
)
|
|
82
|
-
|
|
87
|
+
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner
|
|
88
|
+
const command = ChildProcess.make("git", ["-C", cwd, ...args])
|
|
83
89
|
const commandStr = `git ${args.join(" ")}`
|
|
84
90
|
|
|
85
|
-
const result = yield*
|
|
91
|
+
const result = yield* spawner.string(command).pipe(
|
|
86
92
|
Effect.mapError((error) => mapPlatformError(error, commandStr))
|
|
87
93
|
)
|
|
88
94
|
|
|
@@ -98,7 +104,7 @@ export const runGit = (
|
|
|
98
104
|
export const runGitAllowEmpty = (
|
|
99
105
|
args: ReadonlyArray<string>,
|
|
100
106
|
cwd: string
|
|
101
|
-
): Effect.Effect<string, GitError | GitNotInstalledError,
|
|
107
|
+
): Effect.Effect<string, GitError | GitNotInstalledError, ChildProcessSpawner.ChildProcessSpawner> =>
|
|
102
108
|
runGit(args, cwd).pipe(
|
|
103
109
|
Effect.catchIf(
|
|
104
110
|
(e): e is GitError => e._tag === "GitError",
|
|
@@ -115,7 +121,7 @@ export const runGitAllowEmpty = (
|
|
|
115
121
|
* @internal
|
|
116
122
|
*/
|
|
117
123
|
export const parseGitStatus = (output: string): ReadonlyArray<GitStatusEntry> => {
|
|
118
|
-
if (
|
|
124
|
+
if (EffectString.isEmpty(output.trim())) {
|
|
119
125
|
return []
|
|
120
126
|
}
|
|
121
127
|
|
|
@@ -171,7 +177,7 @@ const parseStatusCode = (code: string): GitFileStatus => {
|
|
|
171
177
|
* @internal
|
|
172
178
|
*/
|
|
173
179
|
export const parseGitLog = (output: string): ReadonlyArray<GitLogEntry> => {
|
|
174
|
-
if (
|
|
180
|
+
if (EffectString.isEmpty(output.trim())) {
|
|
175
181
|
return []
|
|
176
182
|
}
|
|
177
183
|
|
|
@@ -24,10 +24,10 @@ export interface HashService {
|
|
|
24
24
|
*
|
|
25
25
|
* @category Services
|
|
26
26
|
*/
|
|
27
|
-
export class HashServiceTag extends Context.
|
|
27
|
+
export class HashServiceTag extends Context.Service<
|
|
28
28
|
HashServiceTag,
|
|
29
29
|
HashService
|
|
30
|
-
>() {}
|
|
30
|
+
>()("@knpkv/confluence-to-markdown/HashService") {}
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Create a HashService layer from a hash function.
|
|
@@ -3,20 +3,20 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
|
-
import * as HttpRouter from "@effect/platform/HttpRouter"
|
|
7
|
-
import * as HttpServer from "@effect/platform/HttpServer"
|
|
8
|
-
import type { ServeError } from "@effect/platform/HttpServerError"
|
|
9
|
-
import * as HttpServerRequest from "@effect/platform/HttpServerRequest"
|
|
10
|
-
import * as HttpServerResponse from "@effect/platform/HttpServerResponse"
|
|
11
6
|
import * as Context from "effect/Context"
|
|
12
7
|
import * as Deferred from "effect/Deferred"
|
|
13
8
|
import * as Effect from "effect/Effect"
|
|
9
|
+
import * as Exit from "effect/Exit"
|
|
14
10
|
import * as Fiber from "effect/Fiber"
|
|
15
11
|
import * as Layer from "effect/Layer"
|
|
12
|
+
import * as Scope from "effect/Scope"
|
|
13
|
+
import type { HttpServerError } from "effect/unstable/http"
|
|
14
|
+
import { HttpRouter, HttpServer, HttpServerRequest, HttpServerResponse } from "effect/unstable/http"
|
|
16
15
|
import { OAuthError } from "../ConfluenceError.js"
|
|
17
16
|
|
|
18
17
|
const DEFAULT_PORT = 8585
|
|
19
|
-
const
|
|
18
|
+
const MAX_PORT = 8594
|
|
19
|
+
type HttpServerInstance = Effect.Success<typeof HttpServer.HttpServer>
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Factory service for creating HTTP servers.
|
|
@@ -27,7 +27,7 @@ const MAX_PORT_ATTEMPTS = 10
|
|
|
27
27
|
export interface HttpServerFactory {
|
|
28
28
|
readonly createServerLayer: (port: number) => Layer.Layer<
|
|
29
29
|
HttpServer.HttpServer,
|
|
30
|
-
ServeError,
|
|
30
|
+
HttpServerError.ServeError,
|
|
31
31
|
never
|
|
32
32
|
>
|
|
33
33
|
}
|
|
@@ -37,10 +37,10 @@ export interface HttpServerFactory {
|
|
|
37
37
|
*
|
|
38
38
|
* @category Services
|
|
39
39
|
*/
|
|
40
|
-
export class HttpServerFactoryTag extends Context.
|
|
40
|
+
export class HttpServerFactoryTag extends Context.Service<
|
|
41
41
|
HttpServerFactoryTag,
|
|
42
42
|
HttpServerFactory
|
|
43
|
-
>() {}
|
|
43
|
+
>()("@knpkv/confluence-to-markdown/HttpServerFactory") {}
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
46
|
* Create a HttpServerFactory layer from a layer factory function.
|
|
@@ -52,51 +52,12 @@ export class HttpServerFactoryTag extends Context.Tag("@knpkv/confluence-to-mark
|
|
|
52
52
|
* @category Layers
|
|
53
53
|
*/
|
|
54
54
|
export const makeHttpServerFactory = (
|
|
55
|
-
createLayerFn: (port: number) => Layer.Layer<HttpServer.HttpServer, ServeError, never>
|
|
55
|
+
createLayerFn: (port: number) => Layer.Layer<HttpServer.HttpServer, HttpServerError.ServeError, never>
|
|
56
56
|
): Layer.Layer<HttpServerFactoryTag> =>
|
|
57
57
|
Layer.succeed(HttpServerFactoryTag, {
|
|
58
58
|
createServerLayer: createLayerFn
|
|
59
59
|
})
|
|
60
60
|
|
|
61
|
-
/**
|
|
62
|
-
* Check if a port is available by attempting to start a server.
|
|
63
|
-
*/
|
|
64
|
-
const isPortAvailable = (port: number): Effect.Effect<boolean, never, HttpServerFactoryTag> =>
|
|
65
|
-
Effect.gen(function*() {
|
|
66
|
-
const factory = yield* HttpServerFactoryTag
|
|
67
|
-
const serverLayer = factory.createServerLayer(port)
|
|
68
|
-
|
|
69
|
-
// Try to acquire and immediately release
|
|
70
|
-
const result = yield* Layer.build(serverLayer).pipe(
|
|
71
|
-
Effect.scoped,
|
|
72
|
-
Effect.as(true),
|
|
73
|
-
Effect.catchAll(() => Effect.succeed(false))
|
|
74
|
-
)
|
|
75
|
-
return result
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Find an available port starting from the default.
|
|
80
|
-
*/
|
|
81
|
-
const findAvailablePort = (): Effect.Effect<number, OAuthError, HttpServerFactoryTag> =>
|
|
82
|
-
Effect.gen(function*() {
|
|
83
|
-
for (let attempt = 0; attempt < MAX_PORT_ATTEMPTS; attempt++) {
|
|
84
|
-
const port = DEFAULT_PORT + attempt
|
|
85
|
-
const available = yield* isPortAvailable(port)
|
|
86
|
-
if (available) {
|
|
87
|
-
return port
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return yield* Effect.fail(
|
|
91
|
-
new OAuthError({
|
|
92
|
-
step: "authorize",
|
|
93
|
-
cause: `Could not find available port (tried ${DEFAULT_PORT}-${
|
|
94
|
-
DEFAULT_PORT + MAX_PORT_ATTEMPTS - 1
|
|
95
|
-
}). Close other applications using these ports.`
|
|
96
|
-
})
|
|
97
|
-
)
|
|
98
|
-
})
|
|
99
|
-
|
|
100
61
|
/**
|
|
101
62
|
* Result from the OAuth callback server.
|
|
102
63
|
*/
|
|
@@ -122,70 +83,85 @@ export const startCallbackServer = (
|
|
|
122
83
|
): Effect.Effect<CallbackServerResult, OAuthError, HttpServerFactoryTag> =>
|
|
123
84
|
Effect.gen(function*() {
|
|
124
85
|
const factory = yield* HttpServerFactoryTag
|
|
125
|
-
const port = yield* findAvailablePort()
|
|
126
86
|
const deferred = yield* Deferred.make<string, OAuthError>()
|
|
127
87
|
const readyDeferred = yield* Deferred.make<void, OAuthError>()
|
|
88
|
+
const scope = yield* Scope.make()
|
|
89
|
+
|
|
90
|
+
const buildServer = (port: number): Effect.Effect<HttpServerInstance, OAuthError> =>
|
|
91
|
+
Layer.build(factory.createServerLayer(port)).pipe(
|
|
92
|
+
Scope.provide(scope),
|
|
93
|
+
Effect.map((context) => Context.get(context, HttpServer.HttpServer)),
|
|
94
|
+
Effect.catchCause((cause) =>
|
|
95
|
+
port < MAX_PORT
|
|
96
|
+
? buildServer(port + 1)
|
|
97
|
+
: Effect.fail(new OAuthError({ step: "authorize", cause }))
|
|
98
|
+
)
|
|
99
|
+
)
|
|
128
100
|
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
return HttpServerResponse.html(
|
|
156
|
-
"<html><body><h1>Security Error</h1><p>State verification failed.</p></body></html>"
|
|
157
|
-
)
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (!code) {
|
|
161
|
-
yield* Deferred.fail(
|
|
162
|
-
deferred,
|
|
163
|
-
new OAuthError({ step: "authorize", cause: "No authorization code received" })
|
|
164
|
-
)
|
|
165
|
-
return HttpServerResponse.html(
|
|
166
|
-
"<html><body><h1>Error</h1><p>No authorization code received.</p></body></html>"
|
|
167
|
-
)
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
yield* Deferred.succeed(deferred, code)
|
|
101
|
+
const server = yield* buildServer(DEFAULT_PORT)
|
|
102
|
+
|
|
103
|
+
if (server.address._tag !== "TcpAddress") {
|
|
104
|
+
return yield* Effect.fail(
|
|
105
|
+
new OAuthError({ step: "authorize", cause: "OAuth callback server did not bind to a TCP address" })
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
const port = server.address.port
|
|
109
|
+
|
|
110
|
+
const router = yield* HttpRouter.make
|
|
111
|
+
yield* router.add(
|
|
112
|
+
"GET",
|
|
113
|
+
"/callback",
|
|
114
|
+
Effect.gen(function*() {
|
|
115
|
+
const req = yield* HttpServerRequest.HttpServerRequest
|
|
116
|
+
const url = new URL(req.url, `http://localhost:${port}`)
|
|
117
|
+
const code = url.searchParams.get("code")
|
|
118
|
+
const state = url.searchParams.get("state")
|
|
119
|
+
const error = url.searchParams.get("error")
|
|
120
|
+
const errorDescription = url.searchParams.get("error_description")
|
|
121
|
+
|
|
122
|
+
if (error) {
|
|
123
|
+
yield* Deferred.fail(
|
|
124
|
+
deferred,
|
|
125
|
+
new OAuthError({ step: "authorize", cause: errorDescription || error })
|
|
126
|
+
)
|
|
171
127
|
return HttpServerResponse.html(
|
|
172
|
-
"<html><body><h1>
|
|
128
|
+
"<html><body><h1>Authorization Failed</h1><p>You can close this window.</p></body></html>"
|
|
173
129
|
)
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (state !== expectedState) {
|
|
133
|
+
yield* Deferred.fail(
|
|
134
|
+
deferred,
|
|
135
|
+
new OAuthError({ step: "authorize", cause: "State mismatch - possible CSRF attack" })
|
|
136
|
+
)
|
|
137
|
+
return HttpServerResponse.html(
|
|
138
|
+
"<html><body><h1>Security Error</h1><p>State verification failed.</p></body></html>"
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (!code) {
|
|
143
|
+
yield* Deferred.fail(
|
|
144
|
+
deferred,
|
|
145
|
+
new OAuthError({ step: "authorize", cause: "No authorization code received" })
|
|
146
|
+
)
|
|
147
|
+
return HttpServerResponse.html(
|
|
148
|
+
"<html><body><h1>Error</h1><p>No authorization code received.</p></body></html>"
|
|
149
|
+
)
|
|
150
|
+
}
|
|
177
151
|
|
|
178
|
-
|
|
152
|
+
yield* Deferred.succeed(deferred, code)
|
|
153
|
+
return HttpServerResponse.html(
|
|
154
|
+
"<html><body><h1>Success!</h1><p>You can close this window and return to the terminal.</p></body></html>"
|
|
155
|
+
)
|
|
156
|
+
})
|
|
157
|
+
)
|
|
179
158
|
|
|
180
|
-
const serverFiber = yield* HttpServer.
|
|
181
|
-
|
|
182
|
-
|
|
159
|
+
const serverFiber = yield* HttpServer.serveEffect(router.asHttpEffect()).pipe(
|
|
160
|
+
Effect.provideService(HttpServer.HttpServer, server),
|
|
161
|
+
Scope.provide(scope),
|
|
183
162
|
Effect.tap(() => Deferred.succeed(readyDeferred, undefined)),
|
|
184
163
|
Effect.tapError((err) => Deferred.fail(readyDeferred, new OAuthError({ step: "authorize", cause: err }))),
|
|
185
|
-
|
|
186
|
-
Effect.flatMap(() => Effect.never),
|
|
187
|
-
Effect.scoped,
|
|
188
|
-
Effect.fork
|
|
164
|
+
Effect.forkIn(scope)
|
|
189
165
|
)
|
|
190
166
|
|
|
191
167
|
// Wait for server to be ready (or fail)
|
|
@@ -193,7 +169,10 @@ export const startCallbackServer = (
|
|
|
193
169
|
|
|
194
170
|
return {
|
|
195
171
|
codePromise: Deferred.await(deferred),
|
|
196
|
-
shutdown: Fiber.interrupt(serverFiber).pipe(
|
|
172
|
+
shutdown: Fiber.interrupt(serverFiber).pipe(
|
|
173
|
+
Effect.andThen(Scope.close(scope, Exit.void)),
|
|
174
|
+
Effect.asVoid
|
|
175
|
+
),
|
|
197
176
|
port
|
|
198
177
|
}
|
|
199
178
|
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process metadata service.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
import * as Context from "effect/Context"
|
|
8
|
+
import type * as Effect from "effect/Effect"
|
|
9
|
+
|
|
10
|
+
export class ProcessArgs extends Context.Service<
|
|
11
|
+
ProcessArgs,
|
|
12
|
+
{
|
|
13
|
+
readonly argv: Effect.Effect<ReadonlyArray<string>>
|
|
14
|
+
}
|
|
15
|
+
>()("@knpkv/confluence-to-markdown/ProcessArgs") {}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard output helpers backed by the Effect Stdio service.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
import * as Console from "effect/Console"
|
|
8
|
+
import * as Effect from "effect/Effect"
|
|
9
|
+
import type * as PlatformError from "effect/PlatformError"
|
|
10
|
+
import * as Terminal from "effect/Terminal"
|
|
11
|
+
|
|
12
|
+
export const writeStdout = (
|
|
13
|
+
message: string
|
|
14
|
+
): Effect.Effect<void, PlatformError.PlatformError, Terminal.Terminal> =>
|
|
15
|
+
Effect.gen(function*() {
|
|
16
|
+
const terminal = yield* Terminal.Terminal
|
|
17
|
+
yield* terminal.display(message)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
export const writeStderr = (
|
|
21
|
+
message: string
|
|
22
|
+
): Effect.Effect<void> => Console.error(message)
|
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
|
-
import * as
|
|
7
|
-
import * as Path from "@effect/platform/Path"
|
|
6
|
+
import * as Config from "effect/Config"
|
|
8
7
|
import * as Context from "effect/Context"
|
|
9
8
|
import * as Effect from "effect/Effect"
|
|
9
|
+
import * as FileSystem from "effect/FileSystem"
|
|
10
10
|
import * as Layer from "effect/Layer"
|
|
11
|
+
import * as Path from "effect/Path"
|
|
11
12
|
import * as Schema from "effect/Schema"
|
|
12
13
|
import { FileSystemError } from "../ConfluenceError.js"
|
|
13
14
|
import { type OAuthConfig, OAuthConfigSchema, type OAuthToken, OAuthTokenSchema } from "../Schemas.js"
|
|
@@ -16,6 +17,14 @@ const TOKEN_DIR_NAME = ".confluence"
|
|
|
16
17
|
const TOKEN_FILE_NAME = "auth.json"
|
|
17
18
|
const CONFIG_FILE_NAME = "config.json"
|
|
18
19
|
|
|
20
|
+
const parseJsonOrNull = (content: string): unknown | null => {
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(content) as unknown
|
|
23
|
+
} catch {
|
|
24
|
+
return null
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
19
28
|
/**
|
|
20
29
|
* Service for getting the home directory.
|
|
21
30
|
* This allows mocking in tests.
|
|
@@ -31,21 +40,31 @@ export interface HomeDirectory {
|
|
|
31
40
|
*
|
|
32
41
|
* @category Services
|
|
33
42
|
*/
|
|
34
|
-
export class HomeDirectoryTag extends Context.
|
|
43
|
+
export class HomeDirectoryTag extends Context.Service<
|
|
35
44
|
HomeDirectoryTag,
|
|
36
45
|
HomeDirectory
|
|
37
|
-
>() {}
|
|
46
|
+
>()("@knpkv/confluence-to-markdown/HomeDirectory") {}
|
|
38
47
|
|
|
39
48
|
/**
|
|
40
|
-
* Default implementation using
|
|
49
|
+
* Default implementation using Effect Config.
|
|
41
50
|
*
|
|
42
51
|
* @category Layers
|
|
43
52
|
*/
|
|
44
|
-
|
|
53
|
+
const homeDirectoryPath = Config.string("HOME").pipe(
|
|
54
|
+
Config.orElse(() => Config.string("USERPROFILE")),
|
|
55
|
+
Config.orElse(() => Config.succeed("/"))
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
export const HomeDirectoryLive: Layer.Layer<HomeDirectoryTag> = Layer.effect(
|
|
45
59
|
HomeDirectoryTag,
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
60
|
+
homeDirectoryPath.pipe(
|
|
61
|
+
Effect.catchCause(() => Effect.succeed("/")),
|
|
62
|
+
Effect.map((home) =>
|
|
63
|
+
HomeDirectoryTag.of({
|
|
64
|
+
get: () => Effect.succeed(home)
|
|
65
|
+
})
|
|
66
|
+
)
|
|
67
|
+
)
|
|
49
68
|
)
|
|
50
69
|
|
|
51
70
|
/**
|
|
@@ -96,7 +115,7 @@ export const loadToken = (): Effect.Effect<
|
|
|
96
115
|
const tokenPath = yield* getTokenPath()
|
|
97
116
|
|
|
98
117
|
const exists = yield* fs.exists(tokenPath).pipe(
|
|
99
|
-
Effect.
|
|
118
|
+
Effect.catchCause(() => Effect.succeed(false))
|
|
100
119
|
)
|
|
101
120
|
if (!exists) {
|
|
102
121
|
return null
|
|
@@ -106,15 +125,11 @@ export const loadToken = (): Effect.Effect<
|
|
|
106
125
|
Effect.mapError((cause) => new FileSystemError({ operation: "read", path: tokenPath, cause }))
|
|
107
126
|
)
|
|
108
127
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
parsed = JSON.parse(content)
|
|
112
|
-
} catch {
|
|
113
|
-
return null
|
|
114
|
-
}
|
|
128
|
+
const parsed = yield* Effect.sync(() => parseJsonOrNull(content))
|
|
129
|
+
if (parsed === null) return null
|
|
115
130
|
|
|
116
|
-
const decoded = yield* Schema.
|
|
117
|
-
Effect.
|
|
131
|
+
const decoded = yield* Schema.decodeUnknownEffect(OAuthTokenSchema)(parsed).pipe(
|
|
132
|
+
Effect.catchCause(() => Effect.succeed(null))
|
|
118
133
|
)
|
|
119
134
|
|
|
120
135
|
return decoded
|
|
@@ -164,8 +179,7 @@ export const deleteToken = (): Effect.Effect<
|
|
|
164
179
|
const tokenPath = yield* getTokenPath()
|
|
165
180
|
|
|
166
181
|
yield* fs.remove(tokenPath).pipe(
|
|
167
|
-
Effect.
|
|
168
|
-
Effect.mapError((cause) => new FileSystemError({ operation: "delete", path: tokenPath, cause }))
|
|
182
|
+
Effect.catchCause(() => Effect.void)
|
|
169
183
|
)
|
|
170
184
|
})
|
|
171
185
|
|
|
@@ -186,7 +200,7 @@ export const loadOAuthConfig = (): Effect.Effect<
|
|
|
186
200
|
const configPath = yield* getConfigPath()
|
|
187
201
|
|
|
188
202
|
const exists = yield* fs.exists(configPath).pipe(
|
|
189
|
-
Effect.
|
|
203
|
+
Effect.catchCause(() => Effect.succeed(false))
|
|
190
204
|
)
|
|
191
205
|
if (!exists) {
|
|
192
206
|
return null
|
|
@@ -196,15 +210,11 @@ export const loadOAuthConfig = (): Effect.Effect<
|
|
|
196
210
|
Effect.mapError((cause) => new FileSystemError({ operation: "read", path: configPath, cause }))
|
|
197
211
|
)
|
|
198
212
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
parsed = JSON.parse(content)
|
|
202
|
-
} catch {
|
|
203
|
-
return null
|
|
204
|
-
}
|
|
213
|
+
const parsed = yield* Effect.sync(() => parseJsonOrNull(content))
|
|
214
|
+
if (parsed === null) return null
|
|
205
215
|
|
|
206
|
-
const decoded = yield* Schema.
|
|
207
|
-
Effect.
|
|
216
|
+
const decoded = yield* Schema.decodeUnknownEffect(OAuthConfigSchema)(parsed).pipe(
|
|
217
|
+
Effect.catchCause(() => Effect.succeed(null))
|
|
208
218
|
)
|
|
209
219
|
|
|
210
220
|
return decoded
|
|
@@ -14,7 +14,7 @@ import type { AtlassianUser } from "../Schemas.js"
|
|
|
14
14
|
*
|
|
15
15
|
* @category Cache
|
|
16
16
|
*/
|
|
17
|
-
export class UserCache extends Context.
|
|
17
|
+
export class UserCache extends Context.Service<
|
|
18
18
|
UserCache,
|
|
19
19
|
{
|
|
20
20
|
/**
|
|
@@ -40,7 +40,7 @@ export class UserCache extends Context.Tag("@knpkv/confluence-to-markdown/UserCa
|
|
|
40
40
|
*/
|
|
41
41
|
readonly clear: () => Effect.Effect<void>
|
|
42
42
|
}
|
|
43
|
-
>() {}
|
|
43
|
+
>()("@knpkv/confluence-to-markdown/UserCache") {}
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
46
|
* Create the user cache service.
|