@knpkv/confluence-to-markdown 0.2.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 +12 -0
- package/README.md +62 -0
- package/dist/Brand.d.ts +77 -0
- package/dist/Brand.d.ts.map +1 -0
- package/dist/Brand.js +44 -0
- package/dist/Brand.js.map +1 -0
- package/dist/ConfluenceClient.d.ts +140 -0
- package/dist/ConfluenceClient.d.ts.map +1 -0
- package/dist/ConfluenceClient.js +195 -0
- package/dist/ConfluenceClient.js.map +1 -0
- package/dist/ConfluenceConfig.d.ts +83 -0
- package/dist/ConfluenceConfig.d.ts.map +1 -0
- package/dist/ConfluenceConfig.js +122 -0
- package/dist/ConfluenceConfig.js.map +1 -0
- package/dist/ConfluenceError.d.ts +178 -0
- package/dist/ConfluenceError.d.ts.map +1 -0
- package/dist/ConfluenceError.js +131 -0
- package/dist/ConfluenceError.js.map +1 -0
- package/dist/LocalFileSystem.d.ts +85 -0
- package/dist/LocalFileSystem.d.ts.map +1 -0
- package/dist/LocalFileSystem.js +101 -0
- package/dist/LocalFileSystem.js.map +1 -0
- package/dist/MarkdownConverter.d.ts +50 -0
- package/dist/MarkdownConverter.d.ts.map +1 -0
- package/dist/MarkdownConverter.js +151 -0
- package/dist/MarkdownConverter.js.map +1 -0
- package/dist/Schemas.d.ts +225 -0
- package/dist/Schemas.d.ts.map +1 -0
- package/dist/Schemas.js +164 -0
- package/dist/Schemas.js.map +1 -0
- package/dist/SyncEngine.d.ts +132 -0
- package/dist/SyncEngine.d.ts.map +1 -0
- package/dist/SyncEngine.js +267 -0
- package/dist/SyncEngine.js.map +1 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +163 -0
- package/dist/bin.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/frontmatter.d.ts +38 -0
- package/dist/internal/frontmatter.d.ts.map +1 -0
- package/dist/internal/frontmatter.js +69 -0
- package/dist/internal/frontmatter.js.map +1 -0
- package/dist/internal/hashUtils.d.ts +11 -0
- package/dist/internal/hashUtils.d.ts.map +1 -0
- package/dist/internal/hashUtils.js +17 -0
- package/dist/internal/hashUtils.js.map +1 -0
- package/dist/internal/pathUtils.d.ts +41 -0
- package/dist/internal/pathUtils.d.ts.map +1 -0
- package/dist/internal/pathUtils.js +69 -0
- package/dist/internal/pathUtils.js.map +1 -0
- package/package.json +113 -0
- package/src/Brand.ts +104 -0
- package/src/ConfluenceClient.ts +387 -0
- package/src/ConfluenceConfig.ts +184 -0
- package/src/ConfluenceError.ts +193 -0
- package/src/LocalFileSystem.ts +225 -0
- package/src/MarkdownConverter.ts +187 -0
- package/src/Schemas.ts +235 -0
- package/src/SyncEngine.ts +429 -0
- package/src/bin.ts +269 -0
- package/src/index.ts +35 -0
- package/src/internal/frontmatter.ts +98 -0
- package/src/internal/hashUtils.ts +19 -0
- package/src/internal/pathUtils.ts +77 -0
- package/test/Brand.test.ts +72 -0
- package/test/MarkdownConverter.test.ts +108 -0
- package/test/Schemas.test.ts +99 -0
- package/tsconfig.json +32 -0
- package/vitest.config.integration.ts +12 -0
- package/vitest.config.ts +13 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration service for Confluence sync.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import * as FileSystem from "@effect/platform/FileSystem";
|
|
7
|
+
import * as Path from "@effect/platform/Path";
|
|
8
|
+
import * as Context from "effect/Context";
|
|
9
|
+
import * as Effect from "effect/Effect";
|
|
10
|
+
import * as Layer from "effect/Layer";
|
|
11
|
+
import * as Schema from "effect/Schema";
|
|
12
|
+
import { ConfigNotFoundError, ConfigParseError } from "./ConfluenceError.js";
|
|
13
|
+
import { ConfluenceConfigFileSchema } from "./Schemas.js";
|
|
14
|
+
/**
|
|
15
|
+
* Configuration service for Confluence operations.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import { ConfluenceConfig } from "@knpkv/confluence-to-markdown/ConfluenceConfig"
|
|
20
|
+
* import { Effect } from "effect"
|
|
21
|
+
*
|
|
22
|
+
* const program = Effect.gen(function* () {
|
|
23
|
+
* const config = yield* ConfluenceConfig
|
|
24
|
+
* console.log(config.rootPageId)
|
|
25
|
+
* console.log(config.baseUrl)
|
|
26
|
+
* })
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @category Config
|
|
30
|
+
*/
|
|
31
|
+
export class ConfluenceConfig extends Context.Tag("@knpkv/confluence-to-markdown/ConfluenceConfig")() {
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Default config file name.
|
|
35
|
+
*/
|
|
36
|
+
const CONFIG_FILE_NAME = ".confluence.json";
|
|
37
|
+
/**
|
|
38
|
+
* Load configuration from a file.
|
|
39
|
+
*/
|
|
40
|
+
const loadConfig = (configPath) => Effect.gen(function* () {
|
|
41
|
+
const fs = yield* FileSystem.FileSystem;
|
|
42
|
+
const exists = yield* fs.exists(configPath).pipe(Effect.catchAll(() => Effect.succeed(false)));
|
|
43
|
+
if (!exists) {
|
|
44
|
+
return yield* Effect.fail(new ConfigNotFoundError({ path: configPath }));
|
|
45
|
+
}
|
|
46
|
+
const content = yield* fs.readFileString(configPath).pipe(Effect.mapError((cause) => new ConfigParseError({ path: configPath, cause })));
|
|
47
|
+
const json = yield* Effect.try({
|
|
48
|
+
try: () => JSON.parse(content),
|
|
49
|
+
catch: (cause) => new ConfigParseError({ path: configPath, cause })
|
|
50
|
+
});
|
|
51
|
+
return yield* Schema.decodeUnknown(ConfluenceConfigFileSchema)(json).pipe(Effect.mapError((cause) => new ConfigParseError({ path: configPath, cause })));
|
|
52
|
+
});
|
|
53
|
+
/**
|
|
54
|
+
* Layer that provides ConfluenceConfig from a config file.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* import { ConfluenceConfig } from "@knpkv/confluence-to-markdown/ConfluenceConfig"
|
|
59
|
+
* import { NodeFileSystem } from "@effect/platform-node"
|
|
60
|
+
* import { Effect } from "effect"
|
|
61
|
+
*
|
|
62
|
+
* const program = Effect.gen(function* () {
|
|
63
|
+
* const config = yield* ConfluenceConfig
|
|
64
|
+
* console.log(config.rootPageId)
|
|
65
|
+
* })
|
|
66
|
+
*
|
|
67
|
+
* Effect.runPromise(
|
|
68
|
+
* program.pipe(
|
|
69
|
+
* Effect.provide(ConfluenceConfig.layer()),
|
|
70
|
+
* Effect.provide(NodeFileSystem.layer)
|
|
71
|
+
* )
|
|
72
|
+
* )
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* @category Layers
|
|
76
|
+
*/
|
|
77
|
+
export const layer = (configPath) => Layer.effect(ConfluenceConfig, Effect.gen(function* () {
|
|
78
|
+
const path = yield* Path.Path;
|
|
79
|
+
const resolvedPath = configPath ?? path.join(process.cwd(), CONFIG_FILE_NAME);
|
|
80
|
+
const config = yield* loadConfig(resolvedPath);
|
|
81
|
+
return ConfluenceConfig.of({
|
|
82
|
+
rootPageId: config.rootPageId,
|
|
83
|
+
baseUrl: config.baseUrl,
|
|
84
|
+
...(config.spaceKey !== undefined ? { spaceKey: config.spaceKey } : {}),
|
|
85
|
+
docsPath: config.docsPath,
|
|
86
|
+
excludePatterns: config.excludePatterns
|
|
87
|
+
});
|
|
88
|
+
}));
|
|
89
|
+
/**
|
|
90
|
+
* Layer that provides ConfluenceConfig with direct values.
|
|
91
|
+
*
|
|
92
|
+
* @category Layers
|
|
93
|
+
*/
|
|
94
|
+
export const layerFromValues = (config) => Layer.succeed(ConfluenceConfig, ConfluenceConfig.of({
|
|
95
|
+
rootPageId: config.rootPageId,
|
|
96
|
+
baseUrl: config.baseUrl,
|
|
97
|
+
...(config.spaceKey !== undefined ? { spaceKey: config.spaceKey } : {}),
|
|
98
|
+
docsPath: config.docsPath,
|
|
99
|
+
excludePatterns: config.excludePatterns
|
|
100
|
+
}));
|
|
101
|
+
/**
|
|
102
|
+
* Create a new config file.
|
|
103
|
+
*
|
|
104
|
+
* @category Utilities
|
|
105
|
+
*/
|
|
106
|
+
export const createConfigFile = (rootPageId, baseUrl, configPath) => Effect.gen(function* () {
|
|
107
|
+
const fs = yield* FileSystem.FileSystem;
|
|
108
|
+
const pathService = yield* Path.Path;
|
|
109
|
+
const resolvedPath = configPath ?? pathService.join(process.cwd(), CONFIG_FILE_NAME);
|
|
110
|
+
const config = {
|
|
111
|
+
rootPageId: rootPageId,
|
|
112
|
+
baseUrl,
|
|
113
|
+
docsPath: ".docs/confluence",
|
|
114
|
+
excludePatterns: []
|
|
115
|
+
};
|
|
116
|
+
// Validate the config
|
|
117
|
+
yield* Schema.decodeUnknown(ConfluenceConfigFileSchema)(config).pipe(Effect.mapError((cause) => new ConfigParseError({ path: resolvedPath, cause })));
|
|
118
|
+
const content = JSON.stringify(config, null, 2);
|
|
119
|
+
yield* fs.writeFileString(resolvedPath, content).pipe(Effect.mapError((cause) => new ConfigParseError({ path: resolvedPath, cause })));
|
|
120
|
+
return resolvedPath;
|
|
121
|
+
});
|
|
122
|
+
//# sourceMappingURL=ConfluenceConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfluenceConfig.js","sourceRoot":"","sources":["../src/ConfluenceConfig.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
declare const ConfigNotFoundError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
2
|
+
readonly _tag: "ConfigNotFoundError";
|
|
3
|
+
} & Readonly<A>;
|
|
4
|
+
/**
|
|
5
|
+
* Error thrown when .confluence.json is not found.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { Effect } from "effect"
|
|
10
|
+
* import { ConfigNotFoundError } from "@knpkv/confluence-to-markdown/ConfluenceError"
|
|
11
|
+
*
|
|
12
|
+
* Effect.gen(function* () {
|
|
13
|
+
* // ... operation that needs config
|
|
14
|
+
* }).pipe(
|
|
15
|
+
* Effect.catchTag("ConfigNotFoundError", (error) =>
|
|
16
|
+
* Effect.sync(() => console.error(`Config not found at: ${error.path}`))
|
|
17
|
+
* )
|
|
18
|
+
* )
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @category Errors
|
|
22
|
+
*/
|
|
23
|
+
export declare class ConfigNotFoundError extends ConfigNotFoundError_base<{
|
|
24
|
+
readonly path: string;
|
|
25
|
+
}> {
|
|
26
|
+
}
|
|
27
|
+
declare const ConfigParseError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
28
|
+
readonly _tag: "ConfigParseError";
|
|
29
|
+
} & Readonly<A>;
|
|
30
|
+
/**
|
|
31
|
+
* Error thrown when .confluence.json parsing fails.
|
|
32
|
+
*
|
|
33
|
+
* @category Errors
|
|
34
|
+
*/
|
|
35
|
+
export declare class ConfigParseError extends ConfigParseError_base<{
|
|
36
|
+
readonly path: string;
|
|
37
|
+
readonly cause: unknown;
|
|
38
|
+
}> {
|
|
39
|
+
}
|
|
40
|
+
declare const AuthMissingError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
41
|
+
readonly _tag: "AuthMissingError";
|
|
42
|
+
} & Readonly<A>;
|
|
43
|
+
/**
|
|
44
|
+
* Error thrown when authentication is missing.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* import { Effect } from "effect"
|
|
49
|
+
* import { AuthMissingError } from "@knpkv/confluence-to-markdown/ConfluenceError"
|
|
50
|
+
*
|
|
51
|
+
* Effect.gen(function* () {
|
|
52
|
+
* // ... operation that needs auth
|
|
53
|
+
* }).pipe(
|
|
54
|
+
* Effect.catchTag("AuthMissingError", () =>
|
|
55
|
+
* Effect.sync(() => console.error("Set CONFLUENCE_API_KEY or run: confluence auth login"))
|
|
56
|
+
* )
|
|
57
|
+
* )
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* @category Errors
|
|
61
|
+
*/
|
|
62
|
+
export declare class AuthMissingError extends AuthMissingError_base<{
|
|
63
|
+
readonly message: string;
|
|
64
|
+
}> {
|
|
65
|
+
constructor();
|
|
66
|
+
}
|
|
67
|
+
declare const ApiError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
68
|
+
readonly _tag: "ApiError";
|
|
69
|
+
} & Readonly<A>;
|
|
70
|
+
/**
|
|
71
|
+
* Error thrown when Confluence API request fails.
|
|
72
|
+
*
|
|
73
|
+
* @category Errors
|
|
74
|
+
*/
|
|
75
|
+
export declare class ApiError extends ApiError_base<{
|
|
76
|
+
readonly status: number;
|
|
77
|
+
readonly message: string;
|
|
78
|
+
readonly endpoint: string;
|
|
79
|
+
readonly pageId?: string;
|
|
80
|
+
}> {
|
|
81
|
+
}
|
|
82
|
+
declare const RateLimitError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
83
|
+
readonly _tag: "RateLimitError";
|
|
84
|
+
} & Readonly<A>;
|
|
85
|
+
/**
|
|
86
|
+
* Error thrown when rate limit is exceeded.
|
|
87
|
+
*
|
|
88
|
+
* @category Errors
|
|
89
|
+
*/
|
|
90
|
+
export declare class RateLimitError extends RateLimitError_base<{
|
|
91
|
+
readonly retryAfter?: number;
|
|
92
|
+
}> {
|
|
93
|
+
}
|
|
94
|
+
declare const ConversionError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
95
|
+
readonly _tag: "ConversionError";
|
|
96
|
+
} & Readonly<A>;
|
|
97
|
+
/**
|
|
98
|
+
* Error thrown when HTML/Markdown conversion fails.
|
|
99
|
+
*
|
|
100
|
+
* @category Errors
|
|
101
|
+
*/
|
|
102
|
+
export declare class ConversionError extends ConversionError_base<{
|
|
103
|
+
readonly direction: "htmlToMarkdown" | "markdownToHtml";
|
|
104
|
+
readonly cause: unknown;
|
|
105
|
+
}> {
|
|
106
|
+
}
|
|
107
|
+
declare const ConflictError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
108
|
+
readonly _tag: "ConflictError";
|
|
109
|
+
} & Readonly<A>;
|
|
110
|
+
/**
|
|
111
|
+
* Error thrown when sync conflict is detected.
|
|
112
|
+
*
|
|
113
|
+
* @category Errors
|
|
114
|
+
*/
|
|
115
|
+
export declare class ConflictError extends ConflictError_base<{
|
|
116
|
+
readonly pageId: string;
|
|
117
|
+
readonly localVersion: number;
|
|
118
|
+
readonly remoteVersion: number;
|
|
119
|
+
readonly path: string;
|
|
120
|
+
}> {
|
|
121
|
+
}
|
|
122
|
+
declare const FileSystemError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
123
|
+
readonly _tag: "FileSystemError";
|
|
124
|
+
} & Readonly<A>;
|
|
125
|
+
/**
|
|
126
|
+
* Error thrown when file system operation fails.
|
|
127
|
+
*
|
|
128
|
+
* @category Errors
|
|
129
|
+
*/
|
|
130
|
+
export declare class FileSystemError extends FileSystemError_base<{
|
|
131
|
+
readonly operation: "read" | "write" | "delete" | "mkdir" | "rename";
|
|
132
|
+
readonly path: string;
|
|
133
|
+
readonly cause: unknown;
|
|
134
|
+
}> {
|
|
135
|
+
}
|
|
136
|
+
declare const OAuthError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
137
|
+
readonly _tag: "OAuthError";
|
|
138
|
+
} & Readonly<A>;
|
|
139
|
+
/**
|
|
140
|
+
* Error thrown when OAuth2 flow fails.
|
|
141
|
+
*
|
|
142
|
+
* @category Errors
|
|
143
|
+
*/
|
|
144
|
+
export declare class OAuthError extends OAuthError_base<{
|
|
145
|
+
readonly step: "authorize" | "token" | "refresh";
|
|
146
|
+
readonly cause: unknown;
|
|
147
|
+
}> {
|
|
148
|
+
}
|
|
149
|
+
declare const FrontMatterError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
150
|
+
readonly _tag: "FrontMatterError";
|
|
151
|
+
} & Readonly<A>;
|
|
152
|
+
/**
|
|
153
|
+
* Error thrown when front-matter parsing fails.
|
|
154
|
+
*
|
|
155
|
+
* @category Errors
|
|
156
|
+
*/
|
|
157
|
+
export declare class FrontMatterError extends FrontMatterError_base<{
|
|
158
|
+
readonly path: string;
|
|
159
|
+
readonly cause: unknown;
|
|
160
|
+
}> {
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Union of all Confluence errors.
|
|
164
|
+
*
|
|
165
|
+
* @category Errors
|
|
166
|
+
*/
|
|
167
|
+
export type ConfluenceError = ConfigNotFoundError | ConfigParseError | AuthMissingError | ApiError | RateLimitError | ConversionError | ConflictError | FileSystemError | OAuthError | FrontMatterError;
|
|
168
|
+
/**
|
|
169
|
+
* Type guard to check if error is a ConfluenceError.
|
|
170
|
+
*
|
|
171
|
+
* @param error - The error to check
|
|
172
|
+
* @returns True if error is a ConfluenceError
|
|
173
|
+
*
|
|
174
|
+
* @category Utilities
|
|
175
|
+
*/
|
|
176
|
+
export declare const isConfluenceError: (error: unknown) => error is ConfluenceError;
|
|
177
|
+
export {};
|
|
178
|
+
//# sourceMappingURL=ConfluenceError.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfluenceError.d.ts","sourceRoot":"","sources":["../src/ConfluenceError.ts"],"names":[],"mappings":";;;AAOA;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,mBAAoB,SAAQ,yBAAwC;IAC/E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB,CAAC;CAAG;;;;AAEL;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,sBAAqC;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CACxB,CAAC;CAAG;;;;AAEL;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,gBAAiB,SAAQ,sBAAqC;IACzE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB,CAAC;;CAID;;;;AAED;;;;GAIG;AACH,qBAAa,QAAS,SAAQ,cAA6B;IACzD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB,CAAC;CAAG;;;;AAEL;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,oBAAmC;IACrE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAC7B,CAAC;CAAG;;;;AAEL;;;;GAIG;AACH,qBAAa,eAAgB,SAAQ,qBAAoC;IACvE,QAAQ,CAAC,SAAS,EAAE,gBAAgB,GAAG,gBAAgB,CAAA;IACvD,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CACxB,CAAC;CAAG;;;;AAEL;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,mBAAkC;IACnE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB,CAAC;CAAG;;;;AAEL;;;;GAIG;AACH,qBAAa,eAAgB,SAAQ,qBAAoC;IACvE,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAA;IACpE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CACxB,CAAC;CAAG;;;;AAEL;;;;GAIG;AACH,qBAAa,UAAW,SAAQ,gBAA+B;IAC7D,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,GAAG,SAAS,CAAA;IAChD,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CACxB,CAAC;CAAG;;;;AAEL;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,sBAAqC;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CACxB,CAAC;CAAG;AAEL;;;;GAIG;AACH,MAAM,MAAM,eAAe,GACvB,mBAAmB,GACnB,gBAAgB,GAChB,gBAAgB,GAChB,QAAQ,GACR,cAAc,GACd,eAAe,GACf,aAAa,GACb,eAAe,GACf,UAAU,GACV,gBAAgB,CAAA;AAEpB;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,eAed,CAAA"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error types for Confluence operations.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import * as Data from "effect/Data";
|
|
7
|
+
/**
|
|
8
|
+
* Error thrown when .confluence.json is not found.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { Effect } from "effect"
|
|
13
|
+
* import { ConfigNotFoundError } from "@knpkv/confluence-to-markdown/ConfluenceError"
|
|
14
|
+
*
|
|
15
|
+
* Effect.gen(function* () {
|
|
16
|
+
* // ... operation that needs config
|
|
17
|
+
* }).pipe(
|
|
18
|
+
* Effect.catchTag("ConfigNotFoundError", (error) =>
|
|
19
|
+
* Effect.sync(() => console.error(`Config not found at: ${error.path}`))
|
|
20
|
+
* )
|
|
21
|
+
* )
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @category Errors
|
|
25
|
+
*/
|
|
26
|
+
export class ConfigNotFoundError extends Data.TaggedError("ConfigNotFoundError") {
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Error thrown when .confluence.json parsing fails.
|
|
30
|
+
*
|
|
31
|
+
* @category Errors
|
|
32
|
+
*/
|
|
33
|
+
export class ConfigParseError extends Data.TaggedError("ConfigParseError") {
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Error thrown when authentication is missing.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* import { Effect } from "effect"
|
|
41
|
+
* import { AuthMissingError } from "@knpkv/confluence-to-markdown/ConfluenceError"
|
|
42
|
+
*
|
|
43
|
+
* Effect.gen(function* () {
|
|
44
|
+
* // ... operation that needs auth
|
|
45
|
+
* }).pipe(
|
|
46
|
+
* Effect.catchTag("AuthMissingError", () =>
|
|
47
|
+
* Effect.sync(() => console.error("Set CONFLUENCE_API_KEY or run: confluence auth login"))
|
|
48
|
+
* )
|
|
49
|
+
* )
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* @category Errors
|
|
53
|
+
*/
|
|
54
|
+
export class AuthMissingError extends Data.TaggedError("AuthMissingError") {
|
|
55
|
+
constructor() {
|
|
56
|
+
super({ message: "CONFLUENCE_API_KEY env var or OAuth2 credentials required" });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Error thrown when Confluence API request fails.
|
|
61
|
+
*
|
|
62
|
+
* @category Errors
|
|
63
|
+
*/
|
|
64
|
+
export class ApiError extends Data.TaggedError("ApiError") {
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Error thrown when rate limit is exceeded.
|
|
68
|
+
*
|
|
69
|
+
* @category Errors
|
|
70
|
+
*/
|
|
71
|
+
export class RateLimitError extends Data.TaggedError("RateLimitError") {
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Error thrown when HTML/Markdown conversion fails.
|
|
75
|
+
*
|
|
76
|
+
* @category Errors
|
|
77
|
+
*/
|
|
78
|
+
export class ConversionError extends Data.TaggedError("ConversionError") {
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Error thrown when sync conflict is detected.
|
|
82
|
+
*
|
|
83
|
+
* @category Errors
|
|
84
|
+
*/
|
|
85
|
+
export class ConflictError extends Data.TaggedError("ConflictError") {
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Error thrown when file system operation fails.
|
|
89
|
+
*
|
|
90
|
+
* @category Errors
|
|
91
|
+
*/
|
|
92
|
+
export class FileSystemError extends Data.TaggedError("FileSystemError") {
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Error thrown when OAuth2 flow fails.
|
|
96
|
+
*
|
|
97
|
+
* @category Errors
|
|
98
|
+
*/
|
|
99
|
+
export class OAuthError extends Data.TaggedError("OAuthError") {
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Error thrown when front-matter parsing fails.
|
|
103
|
+
*
|
|
104
|
+
* @category Errors
|
|
105
|
+
*/
|
|
106
|
+
export class FrontMatterError extends Data.TaggedError("FrontMatterError") {
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Type guard to check if error is a ConfluenceError.
|
|
110
|
+
*
|
|
111
|
+
* @param error - The error to check
|
|
112
|
+
* @returns True if error is a ConfluenceError
|
|
113
|
+
*
|
|
114
|
+
* @category Utilities
|
|
115
|
+
*/
|
|
116
|
+
export const isConfluenceError = (error) => typeof error === "object" &&
|
|
117
|
+
error !== null &&
|
|
118
|
+
"_tag" in error &&
|
|
119
|
+
[
|
|
120
|
+
"ConfigNotFoundError",
|
|
121
|
+
"ConfigParseError",
|
|
122
|
+
"AuthMissingError",
|
|
123
|
+
"ApiError",
|
|
124
|
+
"RateLimitError",
|
|
125
|
+
"ConversionError",
|
|
126
|
+
"ConflictError",
|
|
127
|
+
"FileSystemError",
|
|
128
|
+
"OAuthError",
|
|
129
|
+
"FrontMatterError"
|
|
130
|
+
].includes(error._tag);
|
|
131
|
+
//# sourceMappingURL=ConfluenceError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfluenceError.js","sourceRoot":"","sources":["../src/ConfluenceError.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,IAAI,MAAM,aAAa,CAAA;AAEnC;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,OAAO,mBAAoB,SAAQ,IAAI,CAAC,WAAW,CAAC,qBAAqB,CAE7E;CAAG;AAEL;;;;GAIG;AACH,MAAM,OAAO,gBAAiB,SAAQ,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAGvE;CAAG;AAEL;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,OAAO,gBAAiB,SAAQ,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAEvE;IACA;QACE,KAAK,CAAC,EAAE,OAAO,EAAE,2DAA2D,EAAE,CAAC,CAAA;IACjF,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,OAAO,QAAS,SAAQ,IAAI,CAAC,WAAW,CAAC,UAAU,CAKvD;CAAG;AAEL;;;;GAIG;AACH,MAAM,OAAO,cAAe,SAAQ,IAAI,CAAC,WAAW,CAAC,gBAAgB,CAEnE;CAAG;AAEL;;;;GAIG;AACH,MAAM,OAAO,eAAgB,SAAQ,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAGrE;CAAG;AAEL;;;;GAIG;AACH,MAAM,OAAO,aAAc,SAAQ,IAAI,CAAC,WAAW,CAAC,eAAe,CAKjE;CAAG;AAEL;;;;GAIG;AACH,MAAM,OAAO,eAAgB,SAAQ,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAIrE;CAAG;AAEL;;;;GAIG;AACH,MAAM,OAAO,UAAW,SAAQ,IAAI,CAAC,WAAW,CAAC,YAAY,CAG3D;CAAG;AAEL;;;;GAIG;AACH,MAAM,OAAO,gBAAiB,SAAQ,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAGvE;CAAG;AAmBL;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAc,EAA4B,EAAE,CAC5E,OAAO,KAAK,KAAK,QAAQ;IACzB,KAAK,KAAK,IAAI;IACd,MAAM,IAAI,KAAK;IACf;QACE,qBAAqB;QACrB,kBAAkB;QAClB,kBAAkB;QAClB,UAAU;QACV,gBAAgB;QAChB,iBAAiB;QACjB,eAAe;QACf,iBAAiB;QACjB,YAAY;QACZ,kBAAkB;KACnB,CAAC,QAAQ,CAAE,KAA0B,CAAC,IAAI,CAAC,CAAA"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local file system operations for markdown files.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import * as FileSystem from "@effect/platform/FileSystem";
|
|
7
|
+
import * as Path from "@effect/platform/Path";
|
|
8
|
+
import * as Context from "effect/Context";
|
|
9
|
+
import * as Effect from "effect/Effect";
|
|
10
|
+
import * as Layer from "effect/Layer";
|
|
11
|
+
import type { ContentHash } from "./Brand.js";
|
|
12
|
+
import type { FrontMatterError } from "./ConfluenceError.js";
|
|
13
|
+
import { FileSystemError } from "./ConfluenceError.js";
|
|
14
|
+
import type { PageFrontMatter } from "./Schemas.js";
|
|
15
|
+
/**
|
|
16
|
+
* Local markdown file representation.
|
|
17
|
+
*/
|
|
18
|
+
export interface LocalFile {
|
|
19
|
+
readonly path: string;
|
|
20
|
+
readonly frontMatter: PageFrontMatter | null;
|
|
21
|
+
readonly content: string;
|
|
22
|
+
readonly contentHash: ContentHash;
|
|
23
|
+
readonly isNew: boolean;
|
|
24
|
+
}
|
|
25
|
+
declare const LocalFileSystem_base: Context.TagClass<LocalFileSystem, "@knpkv/confluence-to-markdown/LocalFileSystem", {
|
|
26
|
+
/**
|
|
27
|
+
* Read a markdown file with front-matter.
|
|
28
|
+
*/
|
|
29
|
+
readonly readMarkdownFile: (filePath: string) => Effect.Effect<LocalFile, FileSystemError | FrontMatterError>;
|
|
30
|
+
/**
|
|
31
|
+
* Write a markdown file with front-matter.
|
|
32
|
+
*/
|
|
33
|
+
readonly writeMarkdownFile: (filePath: string, frontMatter: PageFrontMatter, content: string) => Effect.Effect<void, FileSystemError>;
|
|
34
|
+
/**
|
|
35
|
+
* List all markdown files in a directory recursively.
|
|
36
|
+
*/
|
|
37
|
+
readonly listMarkdownFiles: (dirPath: string) => Effect.Effect<ReadonlyArray<string>, FileSystemError>;
|
|
38
|
+
/**
|
|
39
|
+
* Ensure a directory exists.
|
|
40
|
+
*/
|
|
41
|
+
readonly ensureDir: (dirPath: string) => Effect.Effect<void, FileSystemError>;
|
|
42
|
+
/**
|
|
43
|
+
* Delete a file.
|
|
44
|
+
*/
|
|
45
|
+
readonly deleteFile: (filePath: string) => Effect.Effect<void, FileSystemError>;
|
|
46
|
+
/**
|
|
47
|
+
* Check if a file exists.
|
|
48
|
+
*/
|
|
49
|
+
readonly exists: (filePath: string) => Effect.Effect<boolean, FileSystemError>;
|
|
50
|
+
/**
|
|
51
|
+
* Get the file path for a page.
|
|
52
|
+
*/
|
|
53
|
+
readonly getPagePath: (title: string, hasChildren: boolean, parentPath: string) => string;
|
|
54
|
+
/**
|
|
55
|
+
* Get the directory path for a page's children.
|
|
56
|
+
*/
|
|
57
|
+
readonly getPageDir: (title: string, parentPath: string) => string;
|
|
58
|
+
}>;
|
|
59
|
+
/**
|
|
60
|
+
* Local file system service for markdown operations.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* import { LocalFileSystem } from "@knpkv/confluence-to-markdown/LocalFileSystem"
|
|
65
|
+
* import { Effect } from "effect"
|
|
66
|
+
*
|
|
67
|
+
* const program = Effect.gen(function* () {
|
|
68
|
+
* const fs = yield* LocalFileSystem
|
|
69
|
+
* const files = yield* fs.listMarkdownFiles(".docs/confluence")
|
|
70
|
+
* console.log(files)
|
|
71
|
+
* })
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* @category FileSystem
|
|
75
|
+
*/
|
|
76
|
+
export declare class LocalFileSystem extends LocalFileSystem_base {
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Layer that provides LocalFileSystem.
|
|
80
|
+
*
|
|
81
|
+
* @category Layers
|
|
82
|
+
*/
|
|
83
|
+
export declare const layer: Layer.Layer<LocalFileSystem, never, FileSystem.FileSystem | Path.Path>;
|
|
84
|
+
export {};
|
|
85
|
+
//# sourceMappingURL=LocalFileSystem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LocalFileSystem.d.ts","sourceRoot":"","sources":["../src/LocalFileSystem.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,UAAU,MAAM,6BAA6B,CAAA;AACzD,OAAO,KAAK,IAAI,MAAM,uBAAuB,CAAA;AAC7C,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AACzC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAC7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAKtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAEnD;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,EAAE,eAAe,GAAG,IAAI,CAAA;IAC5C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CACxB;;IAwBG;;OAEG;+BACwB,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,eAAe,GAAG,gBAAgB,CAAC;IAE7G;;OAEG;gCACyB,CAC1B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,eAAe,EAC5B,OAAO,EAAE,MAAM,KACZ,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAAC;IAEzC;;OAEG;gCACyB,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,eAAe,CAAC;IAEtG;;OAEG;wBACiB,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAAC;IAE7E;;OAEG;yBACkB,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAAC;IAE/E;;OAEG;qBACc,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,eAAe,CAAC;IAE9E;;OAEG;0BACmB,CACpB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,OAAO,EACpB,UAAU,EAAE,MAAM,KACf,MAAM;IAEX;;OAEG;yBACkB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,MAAM;;AApEtE;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,eAAgB,SAAQ,oBAqDlC;CAAG;AAEN;;;;GAIG;AACH,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,eAAe,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CAqHxF,CAAA"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local file system operations for markdown files.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import * as FileSystem from "@effect/platform/FileSystem";
|
|
7
|
+
import * as Path from "@effect/platform/Path";
|
|
8
|
+
import * as Context from "effect/Context";
|
|
9
|
+
import * as Effect from "effect/Effect";
|
|
10
|
+
import * as Layer from "effect/Layer";
|
|
11
|
+
import { FileSystemError } from "./ConfluenceError.js";
|
|
12
|
+
import { parseMarkdown, serializeMarkdown } from "./internal/frontmatter.js";
|
|
13
|
+
import { computeHash } from "./internal/hashUtils.js";
|
|
14
|
+
import { pageToDir, pageToPath } from "./internal/pathUtils.js";
|
|
15
|
+
/**
|
|
16
|
+
* Local file system service for markdown operations.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* import { LocalFileSystem } from "@knpkv/confluence-to-markdown/LocalFileSystem"
|
|
21
|
+
* import { Effect } from "effect"
|
|
22
|
+
*
|
|
23
|
+
* const program = Effect.gen(function* () {
|
|
24
|
+
* const fs = yield* LocalFileSystem
|
|
25
|
+
* const files = yield* fs.listMarkdownFiles(".docs/confluence")
|
|
26
|
+
* console.log(files)
|
|
27
|
+
* })
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @category FileSystem
|
|
31
|
+
*/
|
|
32
|
+
export class LocalFileSystem extends Context.Tag("@knpkv/confluence-to-markdown/LocalFileSystem")() {
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Layer that provides LocalFileSystem.
|
|
36
|
+
*
|
|
37
|
+
* @category Layers
|
|
38
|
+
*/
|
|
39
|
+
export const layer = Layer.effect(LocalFileSystem, Effect.gen(function* () {
|
|
40
|
+
const fs = yield* FileSystem.FileSystem;
|
|
41
|
+
const pathService = yield* Path.Path;
|
|
42
|
+
const readMarkdownFile = (filePath) => Effect.gen(function* () {
|
|
43
|
+
const content = yield* fs.readFileString(filePath).pipe(Effect.mapError((cause) => new FileSystemError({ operation: "read", path: filePath, cause })));
|
|
44
|
+
const parsed = yield* parseMarkdown(filePath, content);
|
|
45
|
+
const contentHash = computeHash(parsed.content);
|
|
46
|
+
return {
|
|
47
|
+
path: filePath,
|
|
48
|
+
frontMatter: parsed.frontMatter && "pageId" in parsed.frontMatter
|
|
49
|
+
? parsed.frontMatter
|
|
50
|
+
: null,
|
|
51
|
+
content: parsed.content,
|
|
52
|
+
contentHash,
|
|
53
|
+
isNew: parsed.isNew
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
const writeMarkdownFile = (filePath, frontMatter, content) => Effect.gen(function* () {
|
|
57
|
+
const dir = pathService.dirname(filePath);
|
|
58
|
+
yield* fs.makeDirectory(dir, { recursive: true }).pipe(Effect.catchAll(() => Effect.void));
|
|
59
|
+
const serialized = serializeMarkdown(frontMatter, content);
|
|
60
|
+
// Atomic write: write to temp file, then rename
|
|
61
|
+
const tempPath = `${filePath}.tmp.${Date.now()}`;
|
|
62
|
+
yield* fs.writeFileString(tempPath, serialized).pipe(Effect.mapError((cause) => new FileSystemError({ operation: "write", path: filePath, cause })));
|
|
63
|
+
yield* fs.rename(tempPath, filePath).pipe(Effect.mapError((cause) => new FileSystemError({ operation: "rename", path: filePath, cause })));
|
|
64
|
+
});
|
|
65
|
+
const listMarkdownFiles = (dirPath) => Effect.gen(function* () {
|
|
66
|
+
const exists = yield* fs.exists(dirPath).pipe(Effect.mapError((cause) => new FileSystemError({ operation: "read", path: dirPath, cause })));
|
|
67
|
+
if (!exists) {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
const files = [];
|
|
71
|
+
const walkDir = (dir) => Effect.gen(function* () {
|
|
72
|
+
const entries = yield* fs.readDirectory(dir).pipe(Effect.mapError((cause) => new FileSystemError({ operation: "read", path: dir, cause })));
|
|
73
|
+
for (const entryName of entries) {
|
|
74
|
+
const fullPath = pathService.join(dir, entryName);
|
|
75
|
+
const stat = yield* fs.stat(fullPath).pipe(Effect.mapError((cause) => new FileSystemError({ operation: "read", path: fullPath, cause })));
|
|
76
|
+
if (stat.type === "Directory") {
|
|
77
|
+
yield* walkDir(fullPath);
|
|
78
|
+
}
|
|
79
|
+
else if (stat.type === "File" && entryName.endsWith(".md")) {
|
|
80
|
+
files.push(fullPath);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
yield* walkDir(dirPath);
|
|
85
|
+
return files;
|
|
86
|
+
});
|
|
87
|
+
const ensureDir = (dirPath) => fs.makeDirectory(dirPath, { recursive: true }).pipe(Effect.mapError((cause) => new FileSystemError({ operation: "mkdir", path: dirPath, cause })), Effect.asVoid);
|
|
88
|
+
const deleteFile = (filePath) => fs.remove(filePath).pipe(Effect.mapError((cause) => new FileSystemError({ operation: "delete", path: filePath, cause })));
|
|
89
|
+
const exists = (filePath) => fs.exists(filePath).pipe(Effect.mapError((cause) => new FileSystemError({ operation: "read", path: filePath, cause })));
|
|
90
|
+
return LocalFileSystem.of({
|
|
91
|
+
readMarkdownFile,
|
|
92
|
+
writeMarkdownFile,
|
|
93
|
+
listMarkdownFiles,
|
|
94
|
+
ensureDir,
|
|
95
|
+
deleteFile,
|
|
96
|
+
exists,
|
|
97
|
+
getPagePath: pageToPath,
|
|
98
|
+
getPageDir: pageToDir
|
|
99
|
+
});
|
|
100
|
+
}));
|
|
101
|
+
//# sourceMappingURL=LocalFileSystem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LocalFileSystem.js","sourceRoot":"","sources":["../src/LocalFileSystem.ts"],"names":[],"mappings":"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"}
|