@herb-tools/rewriter 0.8.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.
@@ -0,0 +1,60 @@
1
+ import type { RewriteContext } from "./context.js"
2
+
3
+ /**
4
+ * Base class for string rewriters that transform the formatted output
5
+ *
6
+ * String rewriters receive the formatted string and can modify it before
7
+ * returning the final output. They run after the formatting step.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { StringRewriter } from "@herb-tools/rewriter"
12
+ *
13
+ * class AddTrailingNewline extends StringRewriter {
14
+ * get name() { return "add-trailing-newline" }
15
+ * get description() { return "Ensures file ends with a newline" }
16
+ *
17
+ * rewrite(formatted, context) {
18
+ * return formatted.endsWith("\n") ? formatted : formatted + "\n"
19
+ * }
20
+ * }
21
+ * ```
22
+ */
23
+ export abstract class StringRewriter {
24
+ /**
25
+ * Unique identifier for this rewriter
26
+ * Used in configuration and error messages
27
+ */
28
+ abstract get name(): string
29
+
30
+ /**
31
+ * Human-readable description of what this rewriter does
32
+ */
33
+ abstract get description(): string
34
+
35
+ /**
36
+ * Optional async initialization hook
37
+ *
38
+ * Called once before the first rewrite operation. Use this to:
39
+ * - Load configuration files
40
+ * - Initialize dependencies
41
+ * - Perform expensive setup operations
42
+ *
43
+ * @param context - Context with baseDir and optional filePath
44
+ */
45
+ async initialize(_context: RewriteContext): Promise<void> {
46
+ // Override in subclass if needed
47
+ }
48
+
49
+ /**
50
+ * Transform the formatted string
51
+ *
52
+ * This method is called synchronously for each file being formatted.
53
+ * Return the modified string.
54
+ *
55
+ * @param formatted - The formatted string output from the formatter
56
+ * @param context - Context with filePath and baseDir
57
+ * @returns The modified string
58
+ */
59
+ abstract rewrite(formatted: string, context: RewriteContext): string
60
+ }
@@ -0,0 +1,56 @@
1
+ import { ASTRewriter } from "./ast-rewriter.js"
2
+ import { StringRewriter } from "./string-rewriter.js"
3
+
4
+ /**
5
+ * Type guard to check if a class is an ASTRewriter
6
+ * Uses duck typing to work across module boundaries
7
+ */
8
+ export function isASTRewriterClass(obj: any): obj is new () => ASTRewriter {
9
+ if (typeof obj !== 'function') return false
10
+
11
+ if (obj.prototype instanceof ASTRewriter) return true
12
+
13
+ let proto = obj.prototype
14
+
15
+ while (proto) {
16
+ if (proto.constructor?.name === 'ASTRewriter') return true
17
+
18
+ proto = Object.getPrototypeOf(proto)
19
+ }
20
+
21
+ return false
22
+ }
23
+
24
+ /**
25
+ * Type guard to check if a class is a StringRewriter
26
+ * Uses duck typing to work across module boundaries
27
+ */
28
+ export function isStringRewriterClass(obj: any): obj is new () => StringRewriter {
29
+ if (typeof obj !== 'function') return false
30
+
31
+ if (obj.prototype instanceof StringRewriter) return true
32
+
33
+ let proto = obj.prototype
34
+
35
+ while (proto) {
36
+ if (proto.constructor?.name === 'StringRewriter') return true
37
+
38
+ proto = Object.getPrototypeOf(proto)
39
+ }
40
+
41
+ return false
42
+ }
43
+
44
+ /**
45
+ * Union type for all rewriter classes
46
+ */
47
+ export type RewriterClass =
48
+ | (new () => ASTRewriter)
49
+ | (new () => StringRewriter)
50
+
51
+ /**
52
+ * Type guard to check if a class is any kind of rewriter
53
+ */
54
+ export function isRewriterClass(obj: any): obj is RewriterClass {
55
+ return isASTRewriterClass(obj) || isStringRewriterClass(obj)
56
+ }