@codegraft/core 0.1.0-beta.0 → 0.1.0-beta.10

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.
@@ -1 +1 @@
1
- {"version":3,"file":"edit-collector.d.ts","sourceRoot":"","sources":["../src/edit-collector.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAE3C;;;;;;;;GAQG;AACH,qBAAa,aAAa;;gBAKZ,MAAM,EAAE,MAAM;IAK1B,yFAAyF;IACzF,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAMhE,6BAA6B;IAC7B,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAKxC;;;4BAGwB;IACxB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,mBAAmB,UAAQ,GAAG,IAAI;IAa1E;oGACgG;IAChG,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAI7C,6DAA6D;IAC7D,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAI9C,QAAQ,IAAI,MAAM;IAIlB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS;CAWvC"}
1
+ {"version":3,"file":"edit-collector.d.ts","sourceRoot":"","sources":["../src/edit-collector.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAE3C;;;;;;;;GAQG;AACH,qBAAa,aAAa;;gBAIZ,MAAM,EAAE,MAAM;IAI1B,yFAAyF;IACzF,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAMhE,6BAA6B;IAC7B,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAKxC;oGACgG;IAChG,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAI7C,6DAA6D;IAC7D,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAI9C,QAAQ,IAAI,MAAM;IAIlB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS;CAWvC"}
@@ -1,20 +1,18 @@
1
1
  import MagicString from 'magic-string';
2
2
  /**
3
- * Collects edits against a source string and produces the transformed code (and, on
4
- * demand, a source map) via magic-string.
3
+ * A pure edit buffer: collects text edits against a source string and produces the transformed code
4
+ * (and, on demand, a source map) via magic-string. It knows nothing about lines, indentation, or
5
+ * formatting — that policy lives in the {@link Formatter}, which drives this buffer.
5
6
  *
6
- * Overlap is resolved **first-wins**: an edit overlapping one already accepted is
7
- * dropped silently — the text-layer side of outer-wins. Because edits are applied
8
- * through magic-string at their original offsets, the kept text keeps its original
9
- * position, so the generated map is precise.
7
+ * Overlap is resolved **first-wins**: an edit overlapping one already accepted is dropped silently —
8
+ * the text-layer side of outer-wins. Because edits are applied through magic-string at their original
9
+ * offsets, the kept text keeps its original position, so the generated map is precise.
10
10
  */
11
11
  export class EditCollector {
12
12
  #magic;
13
- #source;
14
13
  #claimed = [];
15
14
  constructor(source) {
16
15
  this.#magic = new MagicString(source);
17
- this.#source = source;
18
16
  }
19
17
  /** Replace `[start, end)` with `replacement` (an empty range inserts before `start`). */
20
18
  overwrite(start, end, replacement) {
@@ -31,23 +29,6 @@ export class EditCollector {
31
29
  return;
32
30
  this.#magic.remove(start, end);
33
31
  }
34
- /** Delete the whole lines `[start, end)` touches — from the start of `start`'s line (leading
35
- * indentation included) through the newline after `end`'s line, so nothing blank is left behind.
36
- * With `collapseBlankBefore`, also absorb whole blank lines immediately above (a separator before
37
- * a dropped block). */
38
- removeLines(start, end, collapseBlankBefore = false) {
39
- let lineStart = this.#source.lastIndexOf('\n', start - 1) + 1;
40
- if (collapseBlankBefore) {
41
- while (lineStart > 0) {
42
- const prevStart = this.#source.lastIndexOf('\n', lineStart - 2) + 1;
43
- if (this.#source.slice(prevStart, lineStart - 1).trim() !== '')
44
- break; // a non-blank line stops it
45
- lineStart = prevStart;
46
- }
47
- }
48
- const newline = this.#source.indexOf('\n', end);
49
- this.remove(lineStart, newline === -1 ? this.#source.length : newline + 1);
50
- }
51
32
  /** Insert `text` at `index`, attached to the left chunk. A point insertion: it claims no
52
33
  * range, so it composes with edits on either side (and survives removal of the right side). */
53
34
  insertLeft(index, text) {
@@ -1 +1 @@
1
- {"version":3,"file":"edit-collector.js","sourceRoot":"","sources":["../src/edit-collector.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"edit-collector.js","sourceRoot":"","sources":["../src/edit-collector.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,cAAc,CAAA;AAGtC;;;;;;;;GAQG;AACH,MAAM,OAAO,aAAa;IACf,MAAM,CAAa;IACnB,QAAQ,GAA4B,EAAE,CAAA;IAE/C,YAAY,MAAc;QACxB,IAAI,CAAC,MAAM,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAA;IACvC,CAAC;IAED,yFAAyF;IACzF,SAAS,CAAC,KAAa,EAAE,GAAW,EAAE,WAAmB;QACvD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC;YAAE,OAAM;QACpC,IAAI,KAAK,KAAK,GAAG;YAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,WAAW,CAAC,CAAA;;YACxD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,EAAE,WAAW,CAAC,CAAA;IAClD,CAAC;IAED,6BAA6B;IAC7B,MAAM,CAAC,KAAa,EAAE,GAAW;QAC/B,IAAI,KAAK,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC;YAAE,OAAM;QACrD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IAChC,CAAC;IAED;oGACgG;IAChG,UAAU,CAAC,KAAa,EAAE,IAAY;QACpC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;IACrC,CAAC;IAED,6DAA6D;IAC7D,WAAW,CAAC,KAAa,EAAE,IAAY;QACrC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;IACtC,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAA;IAC/B,CAAC;IAED,WAAW,CAAC,MAAc;QACxB,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IAC/E,CAAC;IAED,sFAAsF;IACtF,iFAAiF;IACjF,MAAM,CAAC,KAAa,EAAE,GAAW;QAC/B,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,GAAG,IAAI,KAAK,GAAG,CAAC,CAAC;YAAE,OAAO,KAAK,CAAA;QACtE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAA;QAChC,OAAO,IAAI,CAAA;IACb,CAAC;CACF"}
package/dist/evaluate.js CHANGED
@@ -37,10 +37,15 @@ function evalNode(node, context) {
37
37
  return object[field(node, 'property').text];
38
38
  }
39
39
  case 'call_expression': {
40
- const callee = evalNode(field(node, 'function'), context);
41
- assert(typeof callee === 'function', `not callable: '${field(node, 'function').text}'`);
40
+ // A condition's only calls are methods on the context (`$$.BATI.has(x)`); calling the method on
41
+ // its object preserves the receiver, so one whose `this` matters (a real `Set`'s `has`) works.
42
+ const callee = field(node, 'function');
43
+ assert(callee.type === 'member_expression', `only method calls are supported: '${node.text}'`);
44
+ const object = evalNode(field(callee, 'object'), context);
45
+ const method = object[field(callee, 'property').text];
46
+ assert(typeof method === 'function', `not callable: '${callee.text}'`);
42
47
  const args = field(node, 'arguments').children.map((arg) => evalNode(arg, context));
43
- return callee(...args);
48
+ return method.apply(object, args);
44
49
  }
45
50
  case 'identifier':
46
51
  return context; // the namespace root resolves to the context value
@@ -1 +1 @@
1
- {"version":3,"file":"evaluate.js","sourceRoot":"","sources":["../src/evaluate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"evaluate.js","sourceRoot":"","sources":["../src/evaluate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /** A source file's resolved formatting: the indent unit (`'\t'` or N spaces) and line ending. */
2
+ export interface FormatStyle {
3
+ indentUnit: string;
4
+ eol: string;
5
+ }
6
+ /** Per-apply formatting configuration (`transform(src, ctx, options)`) — each field overrides what
7
+ * would otherwise be detected from the source. The extension point prettier-like options (trailing
8
+ * comma, semicolons, quotes, print width) would grow on. */
9
+ export interface FormatOptions {
10
+ /** Force the indent unit (`'\t'` or N spaces) instead of guessing it. */
11
+ indentUnit?: string;
12
+ /** Force the line ending (`'\n'` / `'\r\n'`) instead of guessing it. */
13
+ eol?: string;
14
+ }
15
+ /** Guess the indent unit (most common indentation step, detect-indent style; tabs when they
16
+ * dominate) and EOL (first line break) of `source`, defaulting to two spaces and `'\n'`. */
17
+ export declare function detectStyle(source: string): FormatStyle;
18
+ /** The {@link FormatStyle} for an apply: detected from `source`, with any explicit `options` winning. */
19
+ export declare function resolveStyle(source: string, options?: FormatOptions): FormatStyle;
20
+ /** Re-indent a snippet for a line indented by `baseIndent`: the first line is left for the caller
21
+ * to position, every following non-blank line is re-anchored to `baseIndent` (its indentation
22
+ * relative to the block's own base preserved), and line breaks become `eol`.
23
+ *
24
+ * The block's base is the least-indented continuation line — *not* the first line, which a node's
25
+ * `.text` leaves at column 0 even when the node sits deep in the source. Stripping that base before
26
+ * applying `baseIndent` re-anchors a "hanging" block (continuation lines still at their source
27
+ * indent) to the target, instead of stacking `baseIndent` on top of the indent already there. */
28
+ export declare function reindent(text: string, baseIndent: string, eol: string): string;
29
+ /** Offset of the first character of the line containing `index`. */
30
+ export declare function lineStartOf(source: string, index: number): number;
31
+ /** The leading whitespace of the line containing `index` — the base indent an inserted block should
32
+ * match. Empty when the line starts with a non-whitespace character. */
33
+ export declare function indentOf(source: string, index: number): string;
34
+ /** A space or tab — the horizontal whitespace separating inline list elements (`undefined` past
35
+ * either end of the source is not whitespace). */
36
+ export declare function isHSpace(char: string | undefined): boolean;
37
+ /** The start of the run of whole blank lines immediately above the line beginning at `lineStart`
38
+ * — `lineStart` itself when the preceding line is non-blank. The "absorb blank lines above" step
39
+ * shared by whole-line removal and the line-collapse of a removed last element. */
40
+ export declare function blankRunStart(source: string, lineStart: number): number;
41
+ /** The end of the run of whole blank lines beginning at line start `from` — the start of the first
42
+ * non-blank line at or after it (`from` itself when that line is non-blank, the source length when
43
+ * only blank lines remain). The forward mirror of {@link blankRunStart}: collapsing the blank lines
44
+ * that followed a removed first element, which would dangle after the container's opening delimiter. */
45
+ export declare function blankRunEnd(source: string, from: number): number;
46
+ /** The whole-line span `[from, to)` covering the lines `[start, end)` touches — from the start of
47
+ * `start`'s line (leading indentation included) through the newline after `end`'s line, so nothing
48
+ * blank is left behind. With `collapseBlankBefore`, also absorb whole blank lines immediately above
49
+ * (a separator before a dropped block). */
50
+ export declare function wholeLineRange(source: string, start: number, end: number, collapseBlankBefore?: boolean): [number, number];
51
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAIA,iGAAiG;AACjG,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,GAAG,EAAE,MAAM,CAAA;CACZ;AAED;;6DAE6D;AAC7D,MAAM,WAAW,aAAa;IAC5B,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,wEAAwE;IACxE,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED;6FAC6F;AAC7F,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CAEvD;AAED,yGAAyG;AACzG,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,WAAW,CAMjF;AA0CD;;;;;;;kGAOkG;AAClG,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAU9E;AAKD,oEAAoE;AACpE,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED;yEACyE;AACzE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED;mDACmD;AACnD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAE1D;AAED;;oFAEoF;AACpF,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQvE;AAED;;;yGAGyG;AACzG,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAShE;AAED;;;4CAG4C;AAC5C,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,mBAAmB,UAAQ,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAKxH"}
package/dist/format.js ADDED
@@ -0,0 +1,133 @@
1
+ // Guessing a file's formatting and re-indenting inserted code. Codegraft edits byte ranges, so
2
+ // code it doesn't touch keeps its formatting for free; these let an *inserted* snippet adopt the
3
+ // file's indent unit and line ending instead of landing at column 0. Opt-in (the `format` option).
4
+ /** Guess the indent unit (most common indentation step, detect-indent style; tabs when they
5
+ * dominate) and EOL (first line break) of `source`, defaulting to two spaces and `'\n'`. */
6
+ export function detectStyle(source) {
7
+ return { indentUnit: detectIndentUnit(source), eol: detectEol(source) };
8
+ }
9
+ /** The {@link FormatStyle} for an apply: detected from `source`, with any explicit `options` winning. */
10
+ export function resolveStyle(source, options) {
11
+ const detected = detectStyle(source);
12
+ return {
13
+ indentUnit: options?.indentUnit ?? detected.indentUnit,
14
+ eol: options?.eol ?? detected.eol,
15
+ };
16
+ }
17
+ function detectEol(source) {
18
+ return /\r\n|\n/.exec(source)?.[0] ?? '\n';
19
+ }
20
+ function detectIndentUnit(source) {
21
+ const steps = new Map(); // space-step size → occurrences
22
+ let tabLines = 0;
23
+ let prevSpaces = 0;
24
+ let prevWasSpace = false;
25
+ for (const raw of source.split('\n')) {
26
+ const line = raw.endsWith('\r') ? raw.slice(0, -1) : raw;
27
+ if (line.trim() === '') {
28
+ prevWasSpace = false;
29
+ continue;
30
+ }
31
+ const indent = /^[ \t]*/.exec(line)[0];
32
+ if (indent.includes('\t')) {
33
+ tabLines++;
34
+ prevWasSpace = false;
35
+ continue;
36
+ }
37
+ if (prevWasSpace) {
38
+ const step = Math.abs(indent.length - prevSpaces);
39
+ if (step > 0)
40
+ steps.set(step, (steps.get(step) ?? 0) + 1);
41
+ }
42
+ prevSpaces = indent.length;
43
+ prevWasSpace = true;
44
+ }
45
+ let unit = 0;
46
+ let best = 0;
47
+ for (const [step, count] of steps) {
48
+ if (count > best) {
49
+ best = count;
50
+ unit = step;
51
+ }
52
+ }
53
+ if (tabLines > best)
54
+ return '\t';
55
+ return ' '.repeat(unit || 2);
56
+ }
57
+ /** Re-indent a snippet for a line indented by `baseIndent`: the first line is left for the caller
58
+ * to position, every following non-blank line is re-anchored to `baseIndent` (its indentation
59
+ * relative to the block's own base preserved), and line breaks become `eol`.
60
+ *
61
+ * The block's base is the least-indented continuation line — *not* the first line, which a node's
62
+ * `.text` leaves at column 0 even when the node sits deep in the source. Stripping that base before
63
+ * applying `baseIndent` re-anchors a "hanging" block (continuation lines still at their source
64
+ * indent) to the target, instead of stacking `baseIndent` on top of the indent already there. */
65
+ export function reindent(text, baseIndent, eol) {
66
+ if (!text.includes('\n'))
67
+ return text;
68
+ const lines = text.split(/\r\n|\n/);
69
+ let base = Infinity;
70
+ for (let i = 1; i < lines.length; i++) {
71
+ if (lines[i].trim() === '')
72
+ continue;
73
+ base = Math.min(base, /^[ \t]*/.exec(lines[i])[0].length);
74
+ }
75
+ if (base === Infinity)
76
+ base = 0; // a single-or-blank-continuation snippet: nothing to strip
77
+ return lines.map((line, i) => (i === 0 || line.trim() === '' ? line : baseIndent + line.slice(base))).join(eol);
78
+ }
79
+ // —— Pure line/whitespace queries over a source string (shared by the formatter and whole-line
80
+ // removal). They take the source explicitly so they stay independent of the edit buffer. ——
81
+ /** Offset of the first character of the line containing `index`. */
82
+ export function lineStartOf(source, index) {
83
+ return source.lastIndexOf('\n', index - 1) + 1;
84
+ }
85
+ /** The leading whitespace of the line containing `index` — the base indent an inserted block should
86
+ * match. Empty when the line starts with a non-whitespace character. */
87
+ export function indentOf(source, index) {
88
+ return /^[ \t]*/.exec(source.slice(lineStartOf(source, index), index))[0];
89
+ }
90
+ /** A space or tab — the horizontal whitespace separating inline list elements (`undefined` past
91
+ * either end of the source is not whitespace). */
92
+ export function isHSpace(char) {
93
+ return char === ' ' || char === '\t';
94
+ }
95
+ /** The start of the run of whole blank lines immediately above the line beginning at `lineStart`
96
+ * — `lineStart` itself when the preceding line is non-blank. The "absorb blank lines above" step
97
+ * shared by whole-line removal and the line-collapse of a removed last element. */
98
+ export function blankRunStart(source, lineStart) {
99
+ let from = lineStart;
100
+ while (from > 0) {
101
+ const prevStart = lineStartOf(source, from - 1);
102
+ if (source.slice(prevStart, from - 1).trim() !== '')
103
+ break; // a non-blank line stops it
104
+ from = prevStart;
105
+ }
106
+ return from;
107
+ }
108
+ /** The end of the run of whole blank lines beginning at line start `from` — the start of the first
109
+ * non-blank line at or after it (`from` itself when that line is non-blank, the source length when
110
+ * only blank lines remain). The forward mirror of {@link blankRunStart}: collapsing the blank lines
111
+ * that followed a removed first element, which would dangle after the container's opening delimiter. */
112
+ export function blankRunEnd(source, from) {
113
+ let to = from;
114
+ while (to < source.length) {
115
+ const newline = source.indexOf('\n', to);
116
+ const lineEnd = newline === -1 ? source.length : newline;
117
+ if (source.slice(to, lineEnd).trim() !== '')
118
+ break; // a non-blank line stops it
119
+ to = newline === -1 ? source.length : newline + 1;
120
+ }
121
+ return to;
122
+ }
123
+ /** The whole-line span `[from, to)` covering the lines `[start, end)` touches — from the start of
124
+ * `start`'s line (leading indentation included) through the newline after `end`'s line, so nothing
125
+ * blank is left behind. With `collapseBlankBefore`, also absorb whole blank lines immediately above
126
+ * (a separator before a dropped block). */
127
+ export function wholeLineRange(source, start, end, collapseBlankBefore = false) {
128
+ const lineStart = lineStartOf(source, start);
129
+ const from = collapseBlankBefore ? blankRunStart(source, lineStart) : lineStart;
130
+ const newline = source.indexOf('\n', end);
131
+ return [from, newline === -1 ? source.length : newline + 1];
132
+ }
133
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ import type { RichNode } from './types.js';
2
+ import type { EditCollector } from './edit-collector.js';
3
+ import { type FormatStyle } from './format.js';
4
+ /**
5
+ * The layout-formatting policy: how an edit is *rendered* once the codemod has decided *what* to
6
+ * edit. Built per-apply from the source plus a resolved {@link FormatStyle}. The {@link Collection}
7
+ * delegates the rendering of each edit to it; the {@link EditCollector} it drives stays a pure edit
8
+ * buffer.
9
+ *
10
+ * This is the single home for indentation/EOL re-rendering, container layout (separators, trailing
11
+ * commas, brace padding), and line-collapse on removal — and the place prettier-like options
12
+ * (trailing-comma/semicolon/quote/print-width) would grow.
13
+ */
14
+ export declare class Formatter {
15
+ #private;
16
+ constructor(collector: EditCollector, source: string, style: FormatStyle);
17
+ /** The line ending — for inserting whole statements (`ensureImport`). */
18
+ get eol(): string;
19
+ /** The leading whitespace of the line containing `index` — for restoring a displaced node's indent. */
20
+ indentAt(index: number): string;
21
+ /** `text` re-indented to the line at `index` (single-line text is unchanged) — for a replaced or
22
+ * inserted snippet. */
23
+ reindent(text: string, index: number): string;
24
+ /** Append `text` as the last element of `node`: a fresh indented line in a block/class body, after
25
+ * the last element of a comma- or `;`-separated list, or as the sole element of an empty one. */
26
+ append(node: RichNode, text: string): void;
27
+ /** Prepend `text` as the first element of `node` — the mirror of {@link append}. */
28
+ prepend(node: RichNode, text: string): void;
29
+ /** Delete `[start, end)`, collapsing whitespace the way Prettier would: when the span owns its
30
+ * line(s) — only indentation before `start`, only whitespace after `end` up to the line break —
31
+ * drop the whole lines so no blank line is left; otherwise an in-line delete that also clears one
32
+ * residual separating space, so a removed mid-list element (`[1, two(), 3]`) leaves `[1, 3]`, not
33
+ * `[1, 3]`.
34
+ *
35
+ * In the own-line case the content, the leading indent, and the trailing line break are removed
36
+ * separately so the deletion composes after an abutting edit: a prior `unwrap`/`dropDirective` that
37
+ * already consumed the run up to `start` leaves the content abutting it (no overlap, so it lands),
38
+ * while the leading-indent removal it overlaps is dropped on its own (first-wins) instead of taking
39
+ * the whole line removal down with it.
40
+ *
41
+ * `collapse.before`/`collapse.after` (the node was the last / first surviving element of its
42
+ * container) additionally drop the run of blank lines directly above / below: a blank separator
43
+ * left against the container's closing / opening delimiter, which Prettier strips. Each is its own
44
+ * edit, abutting (not overlapping) the line removal, so a prior edit on the line is unaffected. */
45
+ removeNode(start: number, end: number, collapse?: {
46
+ before?: boolean;
47
+ after?: boolean;
48
+ }): void;
49
+ /** Delete `[start, end)` where `end` begins a following node, collapsing the lines before it: when
50
+ * `start` opens its own line and `end` sits on a later line, drop `[start's line, end's line)` so
51
+ * the leading run (a directive comment and any comments stacked under it) vanishes whole-line while
52
+ * `end`'s own line — its indentation included — is left for a later edit to collapse independently.
53
+ * Otherwise (an inline `start`, or `end` on the same line) a plain `[start, end)` delete. Used by
54
+ * `dropDirective` so it composes with a following `remove`. */
55
+ removeLeadingTo(start: number, end: number): void;
56
+ /** Delete the whole lines `[start, end)` touches — leading indentation through the trailing newline,
57
+ * so nothing blank is left. With `collapseBlankBefore`, also absorb whole blank lines immediately
58
+ * above (a separator before a dropped block). The explicit whole-line removal `remove({ wholeLines })`
59
+ * asks for, where collapsing per node isn't enough. */
60
+ removeWholeLines(start: number, end: number, collapseBlankBefore?: boolean): void;
61
+ /** Register a dedent of the lifted range `[from, to)` by `dedent` columns: every continuation line
62
+ * (the lines after the first) loses up to `dedent` leading-whitespace columns. Used by `unwrap`,
63
+ * whose kept statements drop a level — their first line inherits the wrapper's indent for free,
64
+ * but the rest keep their deeper source indent.
65
+ *
66
+ * Deferred to {@link flush} rather than applied now so it yields (first-wins) to the codemod's own
67
+ * edits on the kept nodes: a kept statement removed or replaced in the same pass wins the overlap,
68
+ * so only lines that actually survive get dedented. A no-op unless `dedent` is positive. */
69
+ deferReindent(from: number, to: number, dedent: number): void;
70
+ /** Apply every {@link deferReindent}, once, after the codemod has recorded its explicit edits. */
71
+ flush(): void;
72
+ }
73
+ //# sourceMappingURL=formatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../src/formatter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACxD,OAAO,EAAE,KAAK,WAAW,EAAyF,MAAM,aAAa,CAAA;AAGrI;;;;;;;;;GASG;AACH,qBAAa,SAAS;;gBAQR,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW;IAMxE,yEAAyE;IACzE,IAAI,GAAG,IAAI,MAAM,CAEhB;IAED,uGAAuG;IACvG,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAI/B;4BACwB;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAM7C;sGACkG;IAClG,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAY1C,oFAAoF;IACpF,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAW3C;;;;;;;;;;;;;;;wGAeoG;IACpG,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,IAAI;IAuBlG;;;;;oEAKgE;IAChE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAOjD;;;4DAGwD;IACxD,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,mBAAmB,UAAQ,GAAG,IAAI;IAO/E;;;;;;;iGAO6F;IAC7F,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAI7D,kGAAkG;IAClG,KAAK,IAAI,IAAI;CA+Ed"}
@@ -0,0 +1,225 @@
1
+ import { reindent, indentOf, isHSpace, lineStartOf, wholeLineRange, blankRunStart, blankRunEnd } from './format.js';
2
+ import { openDelimiter, trailingSeparator, isMultiline, NEWLINE_CONTAINERS, SEMI_CONTAINERS } from './containers.js';
3
+ /**
4
+ * The layout-formatting policy: how an edit is *rendered* once the codemod has decided *what* to
5
+ * edit. Built per-apply from the source plus a resolved {@link FormatStyle}. The {@link Collection}
6
+ * delegates the rendering of each edit to it; the {@link EditCollector} it drives stays a pure edit
7
+ * buffer.
8
+ *
9
+ * This is the single home for indentation/EOL re-rendering, container layout (separators, trailing
10
+ * commas, brace padding), and line-collapse on removal — and the place prettier-like options
11
+ * (trailing-comma/semicolon/quote/print-width) would grow.
12
+ */
13
+ export class Formatter {
14
+ #collector;
15
+ #source;
16
+ #style;
17
+ /** Reindents deferred to {@link flush} — registered by `unwrap`, applied after the codemod's
18
+ * explicit edits so they yield to them (see {@link deferReindent}). */
19
+ #deferred = [];
20
+ constructor(collector, source, style) {
21
+ this.#collector = collector;
22
+ this.#source = source;
23
+ this.#style = style;
24
+ }
25
+ /** The line ending — for inserting whole statements (`ensureImport`). */
26
+ get eol() {
27
+ return this.#style.eol;
28
+ }
29
+ /** The leading whitespace of the line containing `index` — for restoring a displaced node's indent. */
30
+ indentAt(index) {
31
+ return indentOf(this.#source, index);
32
+ }
33
+ /** `text` re-indented to the line at `index` (single-line text is unchanged) — for a replaced or
34
+ * inserted snippet. */
35
+ reindent(text, index) {
36
+ return reindent(text, indentOf(this.#source, index), this.#style.eol);
37
+ }
38
+ // —— append / prepend an element to a container ——
39
+ /** Append `text` as the last element of `node`: a fresh indented line in a block/class body, after
40
+ * the last element of a comma- or `;`-separated list, or as the sole element of an empty one. */
41
+ append(node, text) {
42
+ const elements = node.children;
43
+ if (NEWLINE_CONTAINERS.has(node.type)) {
44
+ if (elements.length === 0)
45
+ this.#fillBlock(node, text);
46
+ else {
47
+ const last = elements[elements.length - 1];
48
+ this.#collector.insertRight(last.documentEndIndex, this.#line(text, last.documentStartIndex));
49
+ }
50
+ }
51
+ else if (elements.length === 0)
52
+ this.#fillContainer(node, text);
53
+ else
54
+ this.#appendElement(node, elements[elements.length - 1], text);
55
+ }
56
+ /** Prepend `text` as the first element of `node` — the mirror of {@link append}. */
57
+ prepend(node, text) {
58
+ const elements = node.children;
59
+ if (NEWLINE_CONTAINERS.has(node.type)) {
60
+ if (elements.length === 0)
61
+ this.#fillBlock(node, text);
62
+ else
63
+ this.#collector.insertRight(openDelimiter(node).documentEndIndex, this.#line(text, elements[0].documentStartIndex));
64
+ }
65
+ else if (elements.length === 0)
66
+ this.#fillContainer(node, text);
67
+ else
68
+ this.#prependElement(node, elements[0], text);
69
+ }
70
+ // —— removal: emit the collapse edits ——
71
+ /** Delete `[start, end)`, collapsing whitespace the way Prettier would: when the span owns its
72
+ * line(s) — only indentation before `start`, only whitespace after `end` up to the line break —
73
+ * drop the whole lines so no blank line is left; otherwise an in-line delete that also clears one
74
+ * residual separating space, so a removed mid-list element (`[1, two(), 3]`) leaves `[1, 3]`, not
75
+ * `[1, 3]`.
76
+ *
77
+ * In the own-line case the content, the leading indent, and the trailing line break are removed
78
+ * separately so the deletion composes after an abutting edit: a prior `unwrap`/`dropDirective` that
79
+ * already consumed the run up to `start` leaves the content abutting it (no overlap, so it lands),
80
+ * while the leading-indent removal it overlaps is dropped on its own (first-wins) instead of taking
81
+ * the whole line removal down with it.
82
+ *
83
+ * `collapse.before`/`collapse.after` (the node was the last / first surviving element of its
84
+ * container) additionally drop the run of blank lines directly above / below: a blank separator
85
+ * left against the container's closing / opening delimiter, which Prettier strips. Each is its own
86
+ * edit, abutting (not overlapping) the line removal, so a prior edit on the line is unaffected. */
87
+ removeNode(start, end, collapse = {}) {
88
+ const lineStart = lineStartOf(this.#source, start);
89
+ const newline = this.#source.indexOf('\n', end);
90
+ const lineEnd = newline === -1 ? this.#source.length : newline;
91
+ const ownsLines = this.#source.slice(lineStart, start).trim() === '' && this.#source.slice(end, lineEnd).trim() === '';
92
+ if (!ownsLines) {
93
+ // Inline hole: drop one separating space when both sides are spaced (a mid-list element), so no
94
+ // double space is left. Never at a list edge (one side non-space) or across a line break.
95
+ const trim = isHSpace(this.#source[end]) && isHSpace(this.#source[start - 1]) ? 1 : 0;
96
+ this.#collector.remove(start, end + trim);
97
+ return;
98
+ }
99
+ this.#collector.remove(start, end); // the content — abuts any prior edit at `start`, so it lands
100
+ this.#collector.remove(lineStart, start); // leading indent — may be already gone under a prior edit
101
+ const lineBreakEnd = newline === -1 ? this.#source.length : newline + 1;
102
+ this.#collector.remove(end, lineBreakEnd); // trailing line break
103
+ // Collapse a blank-line separator the removal leaves dangling against a container edge: `before`
104
+ // the run above the node (against the close), `after` the run below (against the open). With no
105
+ // such run each helper returns the offset it was given, so the remove is a no-op.
106
+ if (collapse.before)
107
+ this.#collector.remove(blankRunStart(this.#source, lineStart), lineStart);
108
+ if (collapse.after)
109
+ this.#collector.remove(lineBreakEnd, blankRunEnd(this.#source, lineBreakEnd));
110
+ }
111
+ /** Delete `[start, end)` where `end` begins a following node, collapsing the lines before it: when
112
+ * `start` opens its own line and `end` sits on a later line, drop `[start's line, end's line)` so
113
+ * the leading run (a directive comment and any comments stacked under it) vanishes whole-line while
114
+ * `end`'s own line — its indentation included — is left for a later edit to collapse independently.
115
+ * Otherwise (an inline `start`, or `end` on the same line) a plain `[start, end)` delete. Used by
116
+ * `dropDirective` so it composes with a following `remove`. */
117
+ removeLeadingTo(start, end) {
118
+ const startLine = lineStartOf(this.#source, start);
119
+ const endLine = lineStartOf(this.#source, end);
120
+ if (endLine > startLine && this.#source.slice(startLine, start).trim() === '')
121
+ this.#collector.remove(startLine, endLine);
122
+ else
123
+ this.#collector.remove(start, end);
124
+ }
125
+ /** Delete the whole lines `[start, end)` touches — leading indentation through the trailing newline,
126
+ * so nothing blank is left. With `collapseBlankBefore`, also absorb whole blank lines immediately
127
+ * above (a separator before a dropped block). The explicit whole-line removal `remove({ wholeLines })`
128
+ * asks for, where collapsing per node isn't enough. */
129
+ removeWholeLines(start, end, collapseBlankBefore = false) {
130
+ const [from, to] = wholeLineRange(this.#source, start, end, collapseBlankBefore);
131
+ this.#collector.remove(from, to);
132
+ }
133
+ // —— unwrap reindent (deferred) ——
134
+ /** Register a dedent of the lifted range `[from, to)` by `dedent` columns: every continuation line
135
+ * (the lines after the first) loses up to `dedent` leading-whitespace columns. Used by `unwrap`,
136
+ * whose kept statements drop a level — their first line inherits the wrapper's indent for free,
137
+ * but the rest keep their deeper source indent.
138
+ *
139
+ * Deferred to {@link flush} rather than applied now so it yields (first-wins) to the codemod's own
140
+ * edits on the kept nodes: a kept statement removed or replaced in the same pass wins the overlap,
141
+ * so only lines that actually survive get dedented. A no-op unless `dedent` is positive. */
142
+ deferReindent(from, to, dedent) {
143
+ if (dedent > 0)
144
+ this.#deferred.push({ from, to, dedent });
145
+ }
146
+ /** Apply every {@link deferReindent}, once, after the codemod has recorded its explicit edits. */
147
+ flush() {
148
+ for (const { from, to, dedent } of this.#deferred)
149
+ this.#dedentLifted(from, to, dedent);
150
+ this.#deferred.length = 0;
151
+ }
152
+ // —— internals ——
153
+ /** Strip up to `dedent` leading-whitespace columns from each continuation line of `[from, to)`
154
+ * (blank lines skipped). Whitespace-only edits at line starts, so they compose with edits to the
155
+ * kept nodes' content; a line already consumed by another edit drops out via first-wins. */
156
+ #dedentLifted(from, to, dedent) {
157
+ for (let nl = this.#source.indexOf('\n', from); nl !== -1 && nl < to; nl = this.#source.indexOf('\n', nl + 1)) {
158
+ const lineStart = nl + 1;
159
+ let i = lineStart;
160
+ while (isHSpace(this.#source[i]))
161
+ i++;
162
+ if (i > lineStart)
163
+ this.#collector.remove(lineStart, lineStart + Math.min(dedent, i - lineStart));
164
+ }
165
+ }
166
+ /** `text` as a fresh line at the indentation of the sibling at `index`. */
167
+ #line(text, index) {
168
+ const indent = indentOf(this.#source, index);
169
+ return this.#style.eol + indent + reindent(text, indent, this.#style.eol);
170
+ }
171
+ /** Open an empty `{}` block onto its own indented line — `{}` → `{⏎ text⏎}`. */
172
+ #fillBlock(node, text) {
173
+ const blockIndent = indentOf(this.#source, node.documentStartIndex);
174
+ const indent = blockIndent + this.#style.indentUnit;
175
+ const eol = this.#style.eol;
176
+ this.#collector.insertRight(openDelimiter(node).documentEndIndex, eol + indent + reindent(text, indent, eol) + eol + blockIndent);
177
+ }
178
+ /** Fill an empty delimited container with its sole element: a brace container is padded
179
+ * (`{}` → `{ text }`); an array / argument list is not (`[]` → `[text]`). */
180
+ #fillContainer(node, text) {
181
+ const open = openDelimiter(node);
182
+ const pad = open.text === '{' ? ' ' : '';
183
+ this.#collector.insertRight(open.documentEndIndex, pad + text + pad);
184
+ }
185
+ /** Append `text` after the last element `last` of a delimited container. A multi-line container
186
+ * places it on a fresh line at the elements' indent, mirroring the trailing-separator style —
187
+ * extend an existing trailing `sep`, add the mandatory `,` a comma list omits, or rely on the
188
+ * newline alone for a `;` list (where the separator between members is optional); an inline one
189
+ * stays on one line. */
190
+ #appendElement(node, last, text) {
191
+ const sep = this.#separatorFor(node);
192
+ if (!isMultiline(node)) {
193
+ this.#collector.insertRight(last.documentEndIndex, `${sep} ${text}`);
194
+ return;
195
+ }
196
+ const trailing = trailingSeparator(last, sep);
197
+ const line = this.#line(text, last.documentStartIndex);
198
+ if (trailing)
199
+ this.#collector.insertRight(trailing.documentEndIndex, line + sep);
200
+ else if (sep === ';')
201
+ this.#collector.insertRight(last.documentEndIndex, line);
202
+ else
203
+ this.#collector.insertRight(last.documentEndIndex, sep + line);
204
+ }
205
+ /** Prepend `text` before the first element `first` — the mirror of {@link #appendElement}. The new
206
+ * element is always followed by the old first, so a multi-line container puts it on a fresh line
207
+ * after the open delimiter, separator-terminated (`;` only where the body terminates members with
208
+ * one); an inline one inserts before the first element so brace padding stays intact
209
+ * (`{ a }` → `{ x, a }`). */
210
+ #prependElement(node, first, text) {
211
+ const sep = this.#separatorFor(node);
212
+ if (!isMultiline(node)) {
213
+ this.#collector.insertLeft(first.documentStartIndex, `${text}${sep} `);
214
+ return;
215
+ }
216
+ const terminate = sep === ',' || trailingSeparator(first, sep) !== null;
217
+ this.#collector.insertRight(openDelimiter(node).documentEndIndex, this.#line(text, first.documentStartIndex) + (terminate ? sep : ''));
218
+ }
219
+ /** The token that separates a container's elements — `;` for a TS interface / object type, else
220
+ * `,`. The seam a future `semi`/separator option would hook into. */
221
+ #separatorFor(node) {
222
+ return SEMI_CONTAINERS.has(node.type) ? ';' : ',';
223
+ }
224
+ }
225
+ //# sourceMappingURL=formatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.js","sourceRoot":"","sources":["../src/formatter.ts"],"names":[],"mappings":"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"}