@motionscript/code 0.1.0-alpha.9 → 0.1.1-alpha.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.
Files changed (65) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +2 -2
  3. package/dist/browser/index.js +8 -8
  4. package/dist/browser/index.js.map +3 -3
  5. package/dist/browser/manifest.json +1 -1
  6. package/dist/code-range.d.ts +7 -47
  7. package/dist/code-range.d.ts.map +1 -1
  8. package/dist/code-range.js +8 -45
  9. package/dist/code-range.js.map +1 -1
  10. package/dist/diff.d.ts +5 -44
  11. package/dist/diff.d.ts.map +1 -1
  12. package/dist/diff.js +22 -69
  13. package/dist/diff.js.map +1 -1
  14. package/dist/engine.d.ts.map +1 -1
  15. package/dist/engine.js +3 -7
  16. package/dist/engine.js.map +1 -1
  17. package/dist/highlight.d.ts +13 -31
  18. package/dist/highlight.d.ts.map +1 -1
  19. package/dist/highlight.js +25 -87
  20. package/dist/highlight.js.map +1 -1
  21. package/dist/layout.d.ts +7 -26
  22. package/dist/layout.d.ts.map +1 -1
  23. package/dist/layout.js +5 -20
  24. package/dist/layout.js.map +1 -1
  25. package/dist/measure-cache.d.ts +5 -27
  26. package/dist/measure-cache.d.ts.map +1 -1
  27. package/dist/measure-cache.js +0 -0
  28. package/dist/measure-cache.js.map +1 -1
  29. package/dist/node.d.ts +4 -11
  30. package/dist/node.d.ts.map +1 -1
  31. package/dist/node.js +18 -41
  32. package/dist/node.js.map +1 -1
  33. package/dist/nodes.d.ts +0 -12
  34. package/dist/nodes.d.ts.map +1 -1
  35. package/dist/nodes.js +0 -12
  36. package/dist/nodes.js.map +1 -1
  37. package/dist/render.d.ts +5 -14
  38. package/dist/render.d.ts.map +1 -1
  39. package/dist/render.js +13 -54
  40. package/dist/render.js.map +1 -1
  41. package/dist/style.d.ts +6 -61
  42. package/dist/style.d.ts.map +1 -1
  43. package/dist/style.js +4 -40
  44. package/dist/style.js.map +1 -1
  45. package/dist/tokens.d.ts +1 -10
  46. package/dist/tokens.d.ts.map +1 -1
  47. package/dist/tokens.js +3 -38
  48. package/dist/tokens.js.map +1 -1
  49. package/dist/transitions.d.ts +16 -68
  50. package/dist/transitions.d.ts.map +1 -1
  51. package/dist/transitions.js +5 -17
  52. package/dist/transitions.js.map +1 -1
  53. package/package.json +4 -4
  54. package/src/code-range.ts +9 -53
  55. package/src/diff.ts +26 -92
  56. package/src/engine.ts +3 -7
  57. package/src/highlight.ts +25 -98
  58. package/src/layout.ts +10 -35
  59. package/src/measure-cache.ts +0 -0
  60. package/src/node.ts +21 -57
  61. package/src/nodes.ts +0 -12
  62. package/src/render.ts +17 -61
  63. package/src/style.ts +9 -64
  64. package/src/tokens.ts +4 -46
  65. package/src/transitions.ts +16 -72
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@motionscript/code",
3
- "version": "0.1.0-alpha.8",
3
+ "version": "0.1.0",
4
4
  "exports": {
5
5
  ".": "dist/browser/index.js"
6
6
  },
@@ -1,42 +1,15 @@
1
- /**
2
- * A range over a code document. Lines and columns are 1-indexed.
3
- *
4
- * `endLine`/`endCol` may be `Infinity` to mean "to the end of the line" or
5
- * "to the end of the document".
6
- */
1
+ /** Lines and columns are 1-indexed; `endLine`/`endCol` may be `Infinity` for the end of the line or document. */
7
2
  export interface CodeRange {
8
3
  startLine: number;
9
4
  startCol: number;
10
5
  endLine: number;
11
6
  endCol: number;
12
7
  }
13
- /**
14
- * Create a range that spans `length` characters starting at (line, col).
15
- * If `length` is omitted, the range extends to the end of the line.
16
- *
17
- * Example:
18
- * word(1, 3, 3) // line 1, column 3, spans 3 characters
19
- * word(1, 3) // line 1, column 3, to end of line
20
- */
8
+ /** `length` characters from (line, col); to the end of the line when omitted. */
21
9
  export declare function word(line: number, col: number, length?: number): CodeRange;
22
- /**
23
- * Create a range that covers entire lines from `from` to `to` (inclusive).
24
- * If `to` is omitted, only line `from` is covered.
25
- *
26
- * Example:
27
- * lines(1, 3) // lines 1 through 3
28
- * lines(2) // line 2 only
29
- */
10
+ /** Whole lines `from` to `to` inclusive; just `from` when `to` is omitted. */
30
11
  export declare function lines(from: number, to?: number): CodeRange;
31
- /**
32
- * Immutable, chainable, iterable builder over multiple ranges — mirrors
33
- * {@link FillChain}/`Fills` in `@motionscript/sdk`. Every method returns a
34
- * *new* chain with one more range appended, so the next range-kind method is
35
- * called directly rather than through a separate combinator:
36
- *
37
- * @example
38
- * CodeRanges.lines(2).word(5, 1, 3) // a 2-range selection, one expression
39
- */
12
+ /** Immutable chain of ranges: each method returns a new chain, as in `CodeRanges.lines(2).word(5, 1, 3)`. */
40
13
  export declare class CodeRangeChain {
41
14
  readonly list: CodeRange[];
42
15
  constructor(list?: CodeRange[]);
@@ -50,26 +23,13 @@ export declare class CodeRangeChain {
50
23
  */
51
24
  toJSON(): CodeRange[];
52
25
  }
53
- /**
54
- * Entry point for building multi-range selections fluently — an empty
55
- * {@link CodeRangeChain}, so `CodeRanges.lines(2)` *is* `new
56
- * CodeRangeChain().lines(2)`. `word`/`lines` stay directly importable and
57
- * usable standalone for a single range; reach for `CodeRanges` when a call
58
- * needs more than one.
59
- */
26
+ /** An empty {@link CodeRangeChain}, the start of a multi-range selection. */
60
27
  export declare const CodeRanges: CodeRangeChain;
61
- /**
62
- * Convert a CodeRange to absolute character offsets [start, end) in the joined
63
- * source text, given the per-line lengths of that source. Lines/columns are
64
- * clamped into the document so out-of-bounds inputs produce a valid range.
65
- */
28
+ /** Absolute [start, end) offsets in the joined source, clamped into the document. */
66
29
  export declare function rangeToCharOffsets(r: CodeRange, lineLengths: number[]): {
67
30
  start: number;
68
31
  end: number;
69
32
  };
70
- /**
71
- * Convert [start, end) character offsets in joined source to a CodeRange.
72
- * Lines/cols in the returned range are 1-indexed.
73
- */
33
+ /** The 1-indexed range for [start, end) offsets in the joined source. */
74
34
  export declare function charOffsetsToRange(start: number, end: number, lineLengths: number[]): CodeRange;
75
35
  //# sourceMappingURL=code-range.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"code-range.d.ts","sourceRoot":"","sources":["../src/code-range.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAO1E;AAED;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAO1D;AAID;;;;;;;;GAQG;AACH,qBAAa,cAAc;aACK,IAAI,EAAE,SAAS,EAAE;gBAAjB,IAAI,GAAE,SAAS,EAAO;IAElD,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,cAAc;IAIhD,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,cAAc;IAI/D,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,SAAS,CAAC;IAIzC;;;;OAIG;IACH,MAAM,IAAI,SAAS,EAAE;CAGxB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,gBAAuB,CAAC;AAE/C;;;;GAIG;AACH,wBAAgB,kBAAkB,CAC9B,CAAC,EAAE,SAAS,EACZ,WAAW,EAAE,MAAM,EAAE,GACtB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAkChC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAC9B,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,EAAE,GACtB,SAAS,CAoBX"}
1
+ {"version":3,"file":"code-range.d.ts","sourceRoot":"","sources":["../src/code-range.ts"],"names":[],"mappings":"AAAA,iHAAiH;AACjH,MAAM,WAAW,SAAS;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,iFAAiF;AACjF,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAO1E;AAED,8EAA8E;AAC9E,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAO1D;AAED,6GAA6G;AAC7G,qBAAa,cAAc;aACK,IAAI,EAAE,SAAS,EAAE;gBAAjB,IAAI,GAAE,SAAS,EAAO;IAElD,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,cAAc;IAIhD,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,cAAc;IAI/D,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,SAAS,CAAC;IAIzC;;;;OAIG;IACH,MAAM,IAAI,SAAS,EAAE;CAGxB;AAED,6EAA6E;AAC7E,eAAO,MAAM,UAAU,gBAAuB,CAAC;AAE/C,qFAAqF;AACrF,wBAAgB,kBAAkB,CAC9B,CAAC,EAAE,SAAS,EACZ,WAAW,EAAE,MAAM,EAAE,GACtB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAgChC;AAED,yEAAyE;AACzE,wBAAgB,kBAAkB,CAC9B,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,EAAE,GACtB,SAAS,CAoBX"}
@@ -1,11 +1,4 @@
1
- /**
2
- * Create a range that spans `length` characters starting at (line, col).
3
- * If `length` is omitted, the range extends to the end of the line.
4
- *
5
- * Example:
6
- * word(1, 3, 3) // line 1, column 3, spans 3 characters
7
- * word(1, 3) // line 1, column 3, to end of line
8
- */
1
+ /** `length` characters from (line, col); to the end of the line when omitted. */
9
2
  export function word(line, col, length) {
10
3
  return {
11
4
  startLine: line,
@@ -14,14 +7,7 @@ export function word(line, col, length) {
14
7
  endCol: length === undefined ? Infinity : col + length,
15
8
  };
16
9
  }
17
- /**
18
- * Create a range that covers entire lines from `from` to `to` (inclusive).
19
- * If `to` is omitted, only line `from` is covered.
20
- *
21
- * Example:
22
- * lines(1, 3) // lines 1 through 3
23
- * lines(2) // line 2 only
24
- */
10
+ /** Whole lines `from` to `to` inclusive; just `from` when `to` is omitted. */
25
11
  export function lines(from, to) {
26
12
  return {
27
13
  startLine: from,
@@ -30,15 +16,7 @@ export function lines(from, to) {
30
16
  endCol: Infinity,
31
17
  };
32
18
  }
33
- /**
34
- * Immutable, chainable, iterable builder over multiple ranges — mirrors
35
- * {@link FillChain}/`Fills` in `@motionscript/sdk`. Every method returns a
36
- * *new* chain with one more range appended, so the next range-kind method is
37
- * called directly rather than through a separate combinator:
38
- *
39
- * @example
40
- * CodeRanges.lines(2).word(5, 1, 3) // a 2-range selection, one expression
41
- */
19
+ /** Immutable chain of ranges: each method returns a new chain, as in `CodeRanges.lines(2).word(5, 1, 3)`. */
42
20
  export class CodeRangeChain {
43
21
  list;
44
22
  constructor(list = []) {
@@ -62,30 +40,19 @@ export class CodeRangeChain {
62
40
  return this.list;
63
41
  }
64
42
  }
65
- /**
66
- * Entry point for building multi-range selections fluently — an empty
67
- * {@link CodeRangeChain}, so `CodeRanges.lines(2)` *is* `new
68
- * CodeRangeChain().lines(2)`. `word`/`lines` stay directly importable and
69
- * usable standalone for a single range; reach for `CodeRanges` when a call
70
- * needs more than one.
71
- */
43
+ /** An empty {@link CodeRangeChain}, the start of a multi-range selection. */
72
44
  export const CodeRanges = new CodeRangeChain();
73
- /**
74
- * Convert a CodeRange to absolute character offsets [start, end) in the joined
75
- * source text, given the per-line lengths of that source. Lines/columns are
76
- * clamped into the document so out-of-bounds inputs produce a valid range.
77
- */
45
+ /** Absolute [start, end) offsets in the joined source, clamped into the document. */
78
46
  export function rangeToCharOffsets(r, lineLengths) {
79
47
  if (lineLengths.length === 0)
80
48
  return { start: 0, end: 0 };
81
- // Cumulative line starts in the joined string (lines joined with '\n').
82
49
  const lineStart = new Array(lineLengths.length);
83
50
  let acc = 0;
84
51
  for (let i = 0; i < lineLengths.length; i++) {
85
52
  lineStart[i] = acc;
86
53
  acc += lineLengths[i] + 1; // +1 for the joining newline
87
54
  }
88
- const docEnd = acc > 0 ? acc - 1 : 0; // strip trailing newline
55
+ const docEnd = acc > 0 ? acc - 1 : 0;
89
56
  const clampLine = (n) => Math.max(0, Math.min(lineLengths.length - 1, n - 1)); // to 0-indexed
90
57
  // A range read back from JSON holds `Infinity` as `null`; both mean "to the end".
91
58
  const endLine = r.endLine ?? Infinity;
@@ -94,8 +61,7 @@ export function rangeToCharOffsets(r, lineLengths) {
94
61
  const eLine = clampLine(endLine);
95
62
  const sColMax = lineLengths[sLine];
96
63
  const eColMax = lineLengths[eLine];
97
- // Columns are 1-indexed; clamp to [1, lineLength+1] so endCol can sit past
98
- // the last char (one-past-end).
64
+ // endCol may sit one past the last character.
99
65
  const sCol = Math.max(0, Math.min(sColMax, r.startCol - 1));
100
66
  const eCol = endCol === Infinity
101
67
  ? eColMax
@@ -104,10 +70,7 @@ export function rangeToCharOffsets(r, lineLengths) {
104
70
  const end = Math.min(docEnd, lineStart[eLine] + eCol);
105
71
  return { start: Math.min(start, end), end: Math.max(start, end) };
106
72
  }
107
- /**
108
- * Convert [start, end) character offsets in joined source to a CodeRange.
109
- * Lines/cols in the returned range are 1-indexed.
110
- */
73
+ /** The 1-indexed range for [start, end) offsets in the joined source. */
111
74
  export function charOffsetsToRange(start, end, lineLengths) {
112
75
  let off = 0;
113
76
  let startLine = 1, startCol = 1, endLine = 1, endCol = 1;
@@ -1 +1 @@
1
- {"version":3,"file":"code-range.js","sourceRoot":"","sources":["../src/code-range.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A range over a code document. Lines and columns are 1-indexed.\n *\n * `endLine`/`endCol` may be `Infinity` to mean \"to the end of the line\" or\n * \"to the end of the document\".\n */\nexport interface CodeRange {\n startLine: number;\n startCol: number;\n endLine: number;\n endCol: number;\n}\n\n/**\n * Create a range that spans `length` characters starting at (line, col).\n * If `length` is omitted, the range extends to the end of the line.\n *\n * Example:\n * word(1, 3, 3) // line 1, column 3, spans 3 characters\n * word(1, 3) // line 1, column 3, to end of line\n */\nexport function word(line: number, col: number, length?: number): CodeRange {\n return {\n startLine: line,\n startCol: col,\n endLine: line,\n endCol: length === undefined ? Infinity : col + length,\n };\n}\n\n/**\n * Create a range that covers entire lines from `from` to `to` (inclusive).\n * If `to` is omitted, only line `from` is covered.\n *\n * Example:\n * lines(1, 3) // lines 1 through 3\n * lines(2) // line 2 only\n */\nexport function lines(from: number, to?: number): CodeRange {\n return {\n startLine: from,\n startCol: 1,\n endLine: to ?? from,\n endCol: Infinity,\n };\n}\n\n\n\n/**\n * Immutable, chainable, iterable builder over multiple ranges — mirrors\n * {@link FillChain}/`Fills` in `@motionscript/sdk`. Every method returns a\n * *new* chain with one more range appended, so the next range-kind method is\n * called directly rather than through a separate combinator:\n *\n * @example\n * CodeRanges.lines(2).word(5, 1, 3) // a 2-range selection, one expression\n */\nexport class CodeRangeChain {\n constructor(public readonly list: CodeRange[] = []) { }\n\n lines(from: number, to?: number): CodeRangeChain {\n return new CodeRangeChain([...this.list, lines(from, to)]);\n }\n\n word(line: number, col: number, length?: number): CodeRangeChain {\n return new CodeRangeChain([...this.list, word(line, col, length)]);\n }\n\n *[Symbol.iterator](): Iterator<CodeRange> {\n yield* this.list;\n }\n\n /**\n * A chain is stored as its ranges. Without this it serialises as\n * `{ \"list\": [...] }`, which has no iterator once read back and so selects\n * nothing; a plain array of ranges reads back as the selection it was.\n */\n toJSON(): CodeRange[] {\n return this.list;\n }\n}\n\n/**\n * Entry point for building multi-range selections fluently — an empty\n * {@link CodeRangeChain}, so `CodeRanges.lines(2)` *is* `new\n * CodeRangeChain().lines(2)`. `word`/`lines` stay directly importable and\n * usable standalone for a single range; reach for `CodeRanges` when a call\n * needs more than one.\n */\nexport const CodeRanges = new CodeRangeChain();\n\n/**\n * Convert a CodeRange to absolute character offsets [start, end) in the joined\n * source text, given the per-line lengths of that source. Lines/columns are\n * clamped into the document so out-of-bounds inputs produce a valid range.\n */\nexport function rangeToCharOffsets(\n r: CodeRange,\n lineLengths: number[],\n): { start: number; end: number } {\n if (lineLengths.length === 0) return { start: 0, end: 0 };\n\n // Cumulative line starts in the joined string (lines joined with '\\n').\n const lineStart: number[] = new Array(lineLengths.length);\n let acc = 0;\n for (let i = 0; i < lineLengths.length; i++) {\n lineStart[i] = acc;\n acc += lineLengths[i] + 1; // +1 for the joining newline\n }\n const docEnd = acc > 0 ? acc - 1 : 0; // strip trailing newline\n\n const clampLine = (n: number) =>\n Math.max(0, Math.min(lineLengths.length - 1, n - 1)); // to 0-indexed\n\n // A range read back from JSON holds `Infinity` as `null`; both mean \"to the end\".\n const endLine = r.endLine ?? Infinity;\n const endCol = r.endCol ?? Infinity;\n\n const sLine = clampLine(r.startLine);\n const eLine = clampLine(endLine);\n const sColMax = lineLengths[sLine];\n const eColMax = lineLengths[eLine];\n\n // Columns are 1-indexed; clamp to [1, lineLength+1] so endCol can sit past\n // the last char (one-past-end).\n const sCol = Math.max(0, Math.min(sColMax, r.startCol - 1));\n const eCol = endCol === Infinity\n ? eColMax\n : Math.max(0, Math.min(eColMax, endCol - 1));\n\n const start = Math.min(docEnd, lineStart[sLine] + sCol);\n const end = Math.min(docEnd, lineStart[eLine] + eCol);\n return { start: Math.min(start, end), end: Math.max(start, end) };\n}\n\n/**\n * Convert [start, end) character offsets in joined source to a CodeRange.\n * Lines/cols in the returned range are 1-indexed.\n */\nexport function charOffsetsToRange(\n start: number,\n end: number,\n lineLengths: number[],\n): CodeRange {\n let off = 0;\n let startLine = 1, startCol = 1, endLine = 1, endCol = 1;\n let foundStart = false;\n for (let li = 0; li < lineLengths.length; li++) {\n const lineStart = off;\n const lineEnd = off + lineLengths[li];\n if (!foundStart && start >= lineStart && start <= lineEnd) {\n startLine = li + 1;\n startCol = (start - lineStart) + 1;\n foundStart = true;\n }\n if (end >= lineStart && end <= lineEnd) {\n endLine = li + 1;\n endCol = (end - lineStart) + 1;\n break;\n }\n off = lineEnd + 1;\n }\n return { startLine, startCol, endLine, endCol };\n}\n"]}
1
+ {"version":3,"file":"code-range.js","sourceRoot":"","sources":["../src/code-range.ts"],"names":[],"mappings":"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","sourcesContent":["/** Lines and columns are 1-indexed; `endLine`/`endCol` may be `Infinity` for the end of the line or document. */\nexport interface CodeRange {\n startLine: number;\n startCol: number;\n endLine: number;\n endCol: number;\n}\n\n/** `length` characters from (line, col); to the end of the line when omitted. */\nexport function word(line: number, col: number, length?: number): CodeRange {\n return {\n startLine: line,\n startCol: col,\n endLine: line,\n endCol: length === undefined ? Infinity : col + length,\n };\n}\n\n/** Whole lines `from` to `to` inclusive; just `from` when `to` is omitted. */\nexport function lines(from: number, to?: number): CodeRange {\n return {\n startLine: from,\n startCol: 1,\n endLine: to ?? from,\n endCol: Infinity,\n };\n}\n\n/** Immutable chain of ranges: each method returns a new chain, as in `CodeRanges.lines(2).word(5, 1, 3)`. */\nexport class CodeRangeChain {\n constructor(public readonly list: CodeRange[] = []) { }\n\n lines(from: number, to?: number): CodeRangeChain {\n return new CodeRangeChain([...this.list, lines(from, to)]);\n }\n\n word(line: number, col: number, length?: number): CodeRangeChain {\n return new CodeRangeChain([...this.list, word(line, col, length)]);\n }\n\n *[Symbol.iterator](): Iterator<CodeRange> {\n yield* this.list;\n }\n\n /**\n * A chain is stored as its ranges. Without this it serialises as\n * `{ \"list\": [...] }`, which has no iterator once read back and so selects\n * nothing; a plain array of ranges reads back as the selection it was.\n */\n toJSON(): CodeRange[] {\n return this.list;\n }\n}\n\n/** An empty {@link CodeRangeChain}, the start of a multi-range selection. */\nexport const CodeRanges = new CodeRangeChain();\n\n/** Absolute [start, end) offsets in the joined source, clamped into the document. */\nexport function rangeToCharOffsets(\n r: CodeRange,\n lineLengths: number[],\n): { start: number; end: number } {\n if (lineLengths.length === 0) return { start: 0, end: 0 };\n\n const lineStart: number[] = new Array(lineLengths.length);\n let acc = 0;\n for (let i = 0; i < lineLengths.length; i++) {\n lineStart[i] = acc;\n acc += lineLengths[i] + 1; // +1 for the joining newline\n }\n const docEnd = acc > 0 ? acc - 1 : 0;\n\n const clampLine = (n: number) =>\n Math.max(0, Math.min(lineLengths.length - 1, n - 1)); // to 0-indexed\n\n // A range read back from JSON holds `Infinity` as `null`; both mean \"to the end\".\n const endLine = r.endLine ?? Infinity;\n const endCol = r.endCol ?? Infinity;\n\n const sLine = clampLine(r.startLine);\n const eLine = clampLine(endLine);\n const sColMax = lineLengths[sLine];\n const eColMax = lineLengths[eLine];\n\n // endCol may sit one past the last character.\n const sCol = Math.max(0, Math.min(sColMax, r.startCol - 1));\n const eCol = endCol === Infinity\n ? eColMax\n : Math.max(0, Math.min(eColMax, endCol - 1));\n\n const start = Math.min(docEnd, lineStart[sLine] + sCol);\n const end = Math.min(docEnd, lineStart[eLine] + eCol);\n return { start: Math.min(start, end), end: Math.max(start, end) };\n}\n\n/** The 1-indexed range for [start, end) offsets in the joined source. */\nexport function charOffsetsToRange(\n start: number,\n end: number,\n lineLengths: number[],\n): CodeRange {\n let off = 0;\n let startLine = 1, startCol = 1, endLine = 1, endCol = 1;\n let foundStart = false;\n for (let li = 0; li < lineLengths.length; li++) {\n const lineStart = off;\n const lineEnd = off + lineLengths[li];\n if (!foundStart && start >= lineStart && start <= lineEnd) {\n startLine = li + 1;\n startCol = (start - lineStart) + 1;\n foundStart = true;\n }\n if (end >= lineStart && end <= lineEnd) {\n endLine = li + 1;\n endCol = (end - lineStart) + 1;\n break;\n }\n off = lineEnd + 1;\n }\n return { startLine, startCol, endLine, endCol };\n}\n"]}
package/dist/diff.d.ts CHANGED
@@ -1,56 +1,17 @@
1
1
  import type { IdLine } from "./tokens.js";
2
- /**
3
- * The result of diffing one listing structure against another: the *next*
4
- * structure, with token and line ids carried over from the previous one
5
- * wherever the content survived, plus the three sets a transition needs to know
6
- * which role each token plays.
7
- *
8
- * Identity is the whole product here. `const variable = 3` becoming
9
- * `const number = 3` should move `const` and `= 3` rather than dissolve and
10
- * rebuild them, and a token can only *move* if the frame after the edit still
11
- * knows it is the same token.
12
- */
13
- /**
14
- * How a `Code` node decides which token became which across an edit. Given
15
- * the old and new tokenized structures, return the carried-over structure
16
- * plus the added/removed/renamed-line bookkeeping a transition needs.
17
- * `diffCode` below is the default implementation (exported as
18
- * `defaultCodeDiff`) — pass a `diffStrategy` of this shape to `<Code>` to
19
- * replace it with your own.
20
- */
2
+ /** Decides which token became which across an edit; `diffCode` (exported as `defaultCodeDiff`) is the default. */
21
3
  export type CodeDiffStrategy = (from: IdLine[], to: IdLine[]) => CodeEdit;
4
+ /** The next structure with ids carried over wherever content survived, so a surviving token moves rather than dissolves and rebuilds. */
22
5
  export interface CodeEdit {
23
- /** The new structure. Ids are rewritten in place onto the tokens handed in. */
6
+ /** The new structure; ids are rewritten in place onto the tokens handed in. */
24
7
  lines: IdLine[];
25
- /** Ids present only in the old structure — these fade out. */
26
8
  removedIds: Set<number>;
27
- /** Ids present only in the new structure — these fade in. */
28
9
  addedIds: Set<number>;
29
- /** Ids of {@link lines} that did not exist before — these enter as a whole row. */
10
+ /** Lines that did not exist before; they enter as a whole row. */
30
11
  newLineIds: Set<number>;
31
12
  /** Previous colour of a surviving token whose highlighting changed, for the cross-fade. */
32
13
  fromColorById: Map<number, string | undefined>;
33
14
  }
34
- /**
35
- * The most line pairs one run of changed lines is scored against each other, and
36
- * the most across a whole edit.
37
- *
38
- * Scoring every pair is quadratic: with 50-character lines it took 31 ms at 200
39
- * lines and 741 ms at 1,000, paid again for each edit command when it is built.
40
- * So the lines are first paired where they cannot be in doubt (see
41
- * {@link alignLines}), and only a run left between two such anchors is scored.
42
- * A run past the first limit, or what is left of the second, is not compared: its
43
- * lines leave and enter as whole rows. That is the budget, and an edit that stays
44
- * inside it is diffed exactly as before.
45
- */
46
- export declare const LINE_ALIGN_CELLS = 40000;
47
- export declare const EDIT_ALIGN_CELLS = 160000;
48
- /**
49
- * Carry `from`'s identities onto `to`, and report what changed.
50
- *
51
- * `to` is freshly tokenized and owns ids nobody has seen yet, so rewriting them
52
- * in place is safe and is what makes the transition cheap: after this, the two
53
- * structures share an id for every token that survived the edit.
54
- */
15
+ /** Carries `from`'s ids onto `to`; `to` is freshly tokenized, so rewriting its ids in place is safe. */
55
16
  export declare function diffCode(from: IdLine[], to: IdLine[]): CodeEdit;
56
17
  //# sourceMappingURL=diff.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAW,MAAM,UAAU,CAAC;AAEhD;;;;;;;;;;GAUG;AACH;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,QAAQ,CAAC;AAE1E,MAAM,WAAW,QAAQ;IACrB,+EAA+E;IAC/E,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,8DAA8D;IAC9D,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACxB,6DAA6D;IAC7D,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB,mFAAmF;IACnF,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACxB,2FAA2F;IAC3F,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAClD;AAYD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,gBAAgB,QAAS,CAAC;AACvC,eAAO,MAAM,gBAAgB,SAAU,CAAC;AA0OxC;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,QAAQ,CAkD/D"}
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAW,MAAM,UAAU,CAAC;AAEhD,kHAAkH;AAClH,MAAM,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,QAAQ,CAAC;AAE1E,yIAAyI;AACzI,MAAM,WAAW,QAAQ;IACrB,+EAA+E;IAC/E,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACxB,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB,kEAAkE;IAClE,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACxB,2FAA2F;IAC3F,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAClD;AA0ND,wGAAwG;AACxG,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,QAAQ,CAkD/D"}
package/dist/diff.js CHANGED
@@ -1,27 +1,13 @@
1
- /**
2
- * How similar two lines must be before they are treated as *one line that was
3
- * edited* rather than as one line deleted and another inserted.
4
- *
5
- * Below this, a row's tokens have so little in common that carrying ids across
6
- * would animate glyphs sliding between unrelated words. Above it, the edit reads
7
- * the way it was made.
8
- */
1
+ /** Below this similarity two lines are one deleted and one inserted, not one edited: carrying ids across would slide glyphs between unrelated words. */
9
2
  const LINE_MATCH_FLOOR = 0.45;
10
3
  /**
11
- * The most line pairs one run of changed lines is scored against each other, and
12
- * the most across a whole edit.
13
- *
14
- * Scoring every pair is quadratic: with 50-character lines it took 31 ms at 200
15
- * lines and 741 ms at 1,000, paid again for each edit command when it is built.
16
- * So the lines are first paired where they cannot be in doubt (see
17
- * {@link alignLines}), and only a run left between two such anchors is scored.
18
- * A run past the first limit, or what is left of the second, is not compared: its
19
- * lines leave and enter as whole rows. That is the budget, and an edit that stays
20
- * inside it is diffed exactly as before.
4
+ * Most line pairs scored in one run of changed lines, and across a whole edit.
5
+ * Scoring every pair is quadratic (741 ms at 1,000 lines), so only a run between
6
+ * two anchors (see {@link alignLines}) is scored; past the budget its lines leave
7
+ * and enter as whole rows.
21
8
  */
22
- export const LINE_ALIGN_CELLS = 40_000;
23
- export const EDIT_ALIGN_CELLS = 160_000;
24
- /** Weight a token carries when judging similarity: its visible characters. */
9
+ const LINE_ALIGN_CELLS = 40_000;
10
+ const EDIT_ALIGN_CELLS = 160_000;
25
11
  function tokenWeight(tok) {
26
12
  return tok.content.trim().length;
27
13
  }
@@ -32,12 +18,9 @@ function lineWeight(line) {
32
18
  return sum;
33
19
  }
34
20
  /**
35
- * Dice coefficient over the two lines' token multisets, weighted by visible
36
- * characters so `variable` counts for far more than a run of spaces.
37
- *
38
- * Two blank lines are identical (1); a blank line against a non-blank one shares
39
- * nothing (0), which keeps the blank rows a reformat introduces from anchoring
40
- * themselves onto real code.
21
+ * Dice coefficient over the lines' token multisets, weighted by visible characters.
22
+ * Two blank lines are identical (1) but a blank against a non-blank shares nothing
23
+ * (0), so blank rows a reformat introduces never anchor onto real code.
41
24
  */
42
25
  function similarity(a, b) {
43
26
  const wa = lineWeight(a);
@@ -66,18 +49,11 @@ function similarity(a, b) {
66
49
  return (2 * common) / (wa + wb);
67
50
  }
68
51
  /**
69
- * Align two sequences by maximising total `score`, skipping is free.
70
- *
71
- * A plain LCS would only ever pair *identical* elements, which is the wrong tool
72
- * twice over: two lines that differ by one word are the same line, and two
73
- * tokens that differ only in colour are the same token. Scoring the pairing and
74
- * letting anything that scores ≤ 0 fall out expresses that directly, and because
75
- * skips cost nothing the alignment stays in order.
76
- *
77
- * Returns the matched index pairs, in order.
52
+ * Matched index pairs, in order, maximising total `score`; a pair scoring <= 0 is
53
+ * skipped. An LCS would pair only identical elements, but two lines that differ by
54
+ * one word are the same line.
78
55
  */
79
56
  function align(aLength, bLength, score) {
80
- // dp[i][j] = best score aligning a[0..i) with b[0..j).
81
57
  const width = bLength + 1;
82
58
  const dp = new Float64Array((aLength + 1) * width);
83
59
  const pairScore = new Float64Array(aLength * bLength);
@@ -116,20 +92,12 @@ function align(aLength, bLength, score) {
116
92
  pairs.reverse();
117
93
  return pairs;
118
94
  }
119
- /**
120
- * Match the tokens of one line against another's.
121
- *
122
- * Scored by visible characters rather than token count, so an alignment that
123
- * keeps `items.reduce` together beats one that keeps four more spaces. A token
124
- * pairs only when its content is unchanged — a changed word is a different word,
125
- * and should be seen to be replaced.
126
- */
95
+ /** Scored by visible characters, so keeping `items.reduce` beats keeping four spaces; a changed word is a different token. */
127
96
  function alignTokens(from, to) {
128
97
  return align(from.length, to.length, (i, j) => {
129
98
  if (from[i].content !== to[j].content)
130
99
  return 0;
131
- // Whitespace still pairs (it holds indentation together), just weakly
132
- // enough that it never outranks real content.
100
+ // Whitespace pairs weakly: it holds indentation together but never outranks content.
133
101
  return tokenWeight(to[j]) || 0.25;
134
102
  });
135
103
  }
@@ -141,7 +109,7 @@ function sameTokens(a, b) {
141
109
  return false;
142
110
  return true;
143
111
  }
144
- /** A line's text, token boundaries included, for telling identical lines apart from similar ones. */
112
+ /** Text with token boundaries, so identical lines tell apart from similar ones. */
145
113
  function signature(line) {
146
114
  let out = "";
147
115
  for (const tok of line.tokens)
@@ -149,14 +117,10 @@ function signature(line) {
149
117
  return out;
150
118
  }
151
119
  /**
152
- * Pair the lines of two listings, in order.
153
- *
154
- * Lines that are the same at the start and at the end are paired outright. In
155
- * what is left, a line that occurs exactly once on each side is an anchor, and
156
- * the longest run of anchors that keeps their order splits the rest into runs of
157
- * changed lines, each scored against itself within the budget (see
158
- * {@link LINE_ALIGN_CELLS}). A one-line edit to a long listing therefore never
159
- * builds a table bigger than the lines around it.
120
+ * Pairs lines in order: identical head and tail outright, then the longest ordered
121
+ * run of lines occurring once on each side as anchors, with each run between
122
+ * anchors scored within the budget. A one-line edit to a long listing therefore
123
+ * never builds a table bigger than the lines around it.
160
124
  */
161
125
  function alignLines(from, to) {
162
126
  const fromSig = from.map(signature);
@@ -194,11 +158,7 @@ function alignLines(from, to) {
194
158
  pairs.push([from.length - k, to.length - k]);
195
159
  return pairs;
196
160
  }
197
- /**
198
- * The lines that occur once in `from[fa, fb)` and once in `to[ta, tb)`, reduced to
199
- * the longest subsequence that is increasing on both sides (patience sorting).
200
- * Blank lines are never anchors: they say nothing about where they belong.
201
- */
161
+ /** Lines occurring once on each side, reduced to the longest subsequence increasing on both (patience sorting); blanks never anchor. */
202
162
  function anchorLines(fromSig, toSig, fa, fb, ta, tb) {
203
163
  const fromAt = new Map();
204
164
  const seen = new Set();
@@ -220,7 +180,6 @@ function anchorLines(fromSig, toSig, fa, fb, ta, tb) {
220
180
  toAt.set(sig, j);
221
181
  seenTo.add(sig);
222
182
  }
223
- // In `to` order, each candidate carries its `from` position.
224
183
  const candidates = [];
225
184
  for (let j = ta; j < tb; j++) {
226
185
  const i = fromAt.get(toSig[j]);
@@ -249,13 +208,7 @@ function anchorLines(fromSig, toSig, fa, fb, ta, tb) {
249
208
  chain.push(candidates[c]);
250
209
  return chain.reverse();
251
210
  }
252
- /**
253
- * Carry `from`'s identities onto `to`, and report what changed.
254
- *
255
- * `to` is freshly tokenized and owns ids nobody has seen yet, so rewriting them
256
- * in place is safe and is what makes the transition cheap: after this, the two
257
- * structures share an id for every token that survived the edit.
258
- */
211
+ /** Carries `from`'s ids onto `to`; `to` is freshly tokenized, so rewriting its ids in place is safe. */
259
212
  export function diffCode(from, to) {
260
213
  const removedIds = new Set();
261
214
  const addedIds = new Set();
package/dist/diff.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"diff.js","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IdLine, IdToken } from \"./tokens\";\n\n/**\n * The result of diffing one listing structure against another: the *next*\n * structure, with token and line ids carried over from the previous one\n * wherever the content survived, plus the three sets a transition needs to know\n * which role each token plays.\n *\n * Identity is the whole product here. `const variable = 3` becoming\n * `const number = 3` should move `const` and `= 3` rather than dissolve and\n * rebuild them, and a token can only *move* if the frame after the edit still\n * knows it is the same token.\n */\n/**\n * How a `Code` node decides which token became which across an edit. Given\n * the old and new tokenized structures, return the carried-over structure\n * plus the added/removed/renamed-line bookkeeping a transition needs.\n * `diffCode` below is the default implementation (exported as\n * `defaultCodeDiff`) — pass a `diffStrategy` of this shape to `<Code>` to\n * replace it with your own.\n */\nexport type CodeDiffStrategy = (from: IdLine[], to: IdLine[]) => CodeEdit;\n\nexport interface CodeEdit {\n /** The new structure. Ids are rewritten in place onto the tokens handed in. */\n lines: IdLine[];\n /** Ids present only in the old structure — these fade out. */\n removedIds: Set<number>;\n /** Ids present only in the new structure — these fade in. */\n addedIds: Set<number>;\n /** Ids of {@link lines} that did not exist before — these enter as a whole row. */\n newLineIds: Set<number>;\n /** Previous colour of a surviving token whose highlighting changed, for the cross-fade. */\n fromColorById: Map<number, string | undefined>;\n}\n\n/**\n * How similar two lines must be before they are treated as *one line that was\n * edited* rather than as one line deleted and another inserted.\n *\n * Below this, a row's tokens have so little in common that carrying ids across\n * would animate glyphs sliding between unrelated words. Above it, the edit reads\n * the way it was made.\n */\nconst LINE_MATCH_FLOOR = 0.45;\n\n/**\n * The most line pairs one run of changed lines is scored against each other, and\n * the most across a whole edit.\n *\n * Scoring every pair is quadratic: with 50-character lines it took 31 ms at 200\n * lines and 741 ms at 1,000, paid again for each edit command when it is built.\n * So the lines are first paired where they cannot be in doubt (see\n * {@link alignLines}), and only a run left between two such anchors is scored.\n * A run past the first limit, or what is left of the second, is not compared: its\n * lines leave and enter as whole rows. That is the budget, and an edit that stays\n * inside it is diffed exactly as before.\n */\nexport const LINE_ALIGN_CELLS = 40_000;\nexport const EDIT_ALIGN_CELLS = 160_000;\n\n/** Weight a token carries when judging similarity: its visible characters. */\nfunction tokenWeight(tok: IdToken): number {\n return tok.content.trim().length;\n}\n\nfunction lineWeight(line: IdLine): number {\n let sum = 0;\n for (const tok of line.tokens) sum += tokenWeight(tok);\n return sum;\n}\n\n/**\n * Dice coefficient over the two lines' token multisets, weighted by visible\n * characters so `variable` counts for far more than a run of spaces.\n *\n * Two blank lines are identical (1); a blank line against a non-blank one shares\n * nothing (0), which keeps the blank rows a reformat introduces from anchoring\n * themselves onto real code.\n */\nfunction similarity(a: IdLine, b: IdLine): number {\n const wa = lineWeight(a);\n const wb = lineWeight(b);\n if (wa === 0 && wb === 0) return 1;\n if (wa === 0 || wb === 0) return 0;\n\n const bag = new Map<string, number>();\n for (const tok of a.tokens) {\n if (tokenWeight(tok) === 0) continue;\n bag.set(tok.content, (bag.get(tok.content) ?? 0) + 1);\n }\n let common = 0;\n for (const tok of b.tokens) {\n const w = tokenWeight(tok);\n if (w === 0) continue;\n const left = bag.get(tok.content) ?? 0;\n if (left > 0) {\n bag.set(tok.content, left - 1);\n common += w;\n }\n }\n return (2 * common) / (wa + wb);\n}\n\n/**\n * Align two sequences by maximising total `score`, skipping is free.\n *\n * A plain LCS would only ever pair *identical* elements, which is the wrong tool\n * twice over: two lines that differ by one word are the same line, and two\n * tokens that differ only in colour are the same token. Scoring the pairing and\n * letting anything that scores ≤ 0 fall out expresses that directly, and because\n * skips cost nothing the alignment stays in order.\n *\n * Returns the matched index pairs, in order.\n */\nfunction align(\n aLength: number,\n bLength: number,\n score: (i: number, j: number) => number,\n): Array<[number, number]> {\n // dp[i][j] = best score aligning a[0..i) with b[0..j).\n const width = bLength + 1;\n const dp = new Float64Array((aLength + 1) * width);\n const pairScore = new Float64Array(aLength * bLength);\n\n for (let i = 1; i <= aLength; i++) {\n for (let j = 1; j <= bLength; j++) {\n const s = score(i - 1, j - 1);\n pairScore[(i - 1) * bLength + (j - 1)] = s;\n const skipA = dp[(i - 1) * width + j];\n const skipB = dp[i * width + (j - 1)];\n let best = skipA > skipB ? skipA : skipB;\n if (s > 0) {\n const paired = dp[(i - 1) * width + (j - 1)] + s;\n if (paired > best) best = paired;\n }\n dp[i * width + j] = best;\n }\n }\n\n const pairs: Array<[number, number]> = [];\n let i = aLength;\n let j = bLength;\n while (i > 0 && j > 0) {\n const s = pairScore[(i - 1) * bLength + (j - 1)];\n if (s > 0 && dp[i * width + j] === dp[(i - 1) * width + (j - 1)] + s) {\n pairs.push([i - 1, j - 1]);\n i--; j--;\n } else if (dp[(i - 1) * width + j] >= dp[i * width + (j - 1)]) {\n i--;\n } else {\n j--;\n }\n }\n pairs.reverse();\n return pairs;\n}\n\n/**\n * Match the tokens of one line against another's.\n *\n * Scored by visible characters rather than token count, so an alignment that\n * keeps `items.reduce` together beats one that keeps four more spaces. A token\n * pairs only when its content is unchanged — a changed word is a different word,\n * and should be seen to be replaced.\n */\nfunction alignTokens(from: IdToken[], to: IdToken[]): Array<[number, number]> {\n return align(from.length, to.length, (i, j) => {\n if (from[i].content !== to[j].content) return 0;\n // Whitespace still pairs (it holds indentation together), just weakly\n // enough that it never outranks real content.\n return tokenWeight(to[j]) || 0.25;\n });\n}\n\nfunction sameTokens(a: IdLine, b: IdLine): boolean {\n if (a.tokens.length !== b.tokens.length) return false;\n for (let k = 0; k < a.tokens.length; k++) if (a.tokens[k].content !== b.tokens[k].content) return false;\n return true;\n}\n\n/** A line's text, token boundaries included, for telling identical lines apart from similar ones. */\nfunction signature(line: IdLine): string {\n let out = \"\";\n for (const tok of line.tokens) out += tok.content + \"\\u0001\";\n return out;\n}\n\n/**\n * Pair the lines of two listings, in order.\n *\n * Lines that are the same at the start and at the end are paired outright. In\n * what is left, a line that occurs exactly once on each side is an anchor, and\n * the longest run of anchors that keeps their order splits the rest into runs of\n * changed lines, each scored against itself within the budget (see\n * {@link LINE_ALIGN_CELLS}). A one-line edit to a long listing therefore never\n * builds a table bigger than the lines around it.\n */\nfunction alignLines(from: IdLine[], to: IdLine[]): Array<[number, number]> {\n const fromSig = from.map(signature);\n const toSig = to.map(signature);\n const pairs: Array<[number, number]> = [];\n\n let head = 0;\n while (head < from.length && head < to.length && fromSig[head] === toSig[head]) {\n pairs.push([head, head]);\n head++;\n }\n let tail = 0;\n while (\n tail < from.length - head && tail < to.length - head\n && fromSig[from.length - 1 - tail] === toSig[to.length - 1 - tail]\n ) tail++;\n\n const anchors = anchorLines(fromSig, toSig, head, from.length - tail, head, to.length - tail);\n let budget = EDIT_ALIGN_CELLS;\n let fi = head;\n let ti = head;\n for (const [af, at] of [...anchors, [from.length - tail, to.length - tail] as [number, number]]) {\n const rows = af - fi;\n const cols = at - ti;\n const cells = rows * cols;\n if (cells > 0 && cells <= LINE_ALIGN_CELLS && cells <= budget) {\n budget -= cells;\n for (const [i, j] of align(rows, cols, (a, b) => similarity(from[fi + a], to[ti + b]) - LINE_MATCH_FLOOR)) {\n pairs.push([fi + i, ti + j]);\n }\n }\n if (af < from.length - tail) pairs.push([af, at]);\n fi = af + 1;\n ti = at + 1;\n }\n for (let k = tail; k > 0; k--) pairs.push([from.length - k, to.length - k]);\n return pairs;\n}\n\n/**\n * The lines that occur once in `from[fa, fb)` and once in `to[ta, tb)`, reduced to\n * the longest subsequence that is increasing on both sides (patience sorting).\n * Blank lines are never anchors: they say nothing about where they belong.\n */\nfunction anchorLines(\n fromSig: string[],\n toSig: string[],\n fa: number,\n fb: number,\n ta: number,\n tb: number,\n): Array<[number, number]> {\n const fromAt = new Map<string, number>();\n const seen = new Set<string>();\n for (let i = fa; i < fb; i++) {\n const sig = fromSig[i];\n if (seen.has(sig)) fromAt.delete(sig);\n else fromAt.set(sig, i);\n seen.add(sig);\n }\n const toAt = new Map<string, number>();\n const seenTo = new Set<string>();\n for (let j = ta; j < tb; j++) {\n const sig = toSig[j];\n if (seenTo.has(sig)) toAt.delete(sig);\n else toAt.set(sig, j);\n seenTo.add(sig);\n }\n\n // In `to` order, each candidate carries its `from` position.\n const candidates: Array<[number, number]> = [];\n for (let j = ta; j < tb; j++) {\n const i = fromAt.get(toSig[j]);\n if (i !== undefined && toAt.get(toSig[j]) === j && toSig[j].replaceAll(\"\\u0001\", \"\").trim() !== \"\") {\n candidates.push([i, j]);\n }\n }\n\n const tails: number[] = [];\n const previous: number[] = new Array(candidates.length).fill(-1);\n for (let c = 0; c < candidates.length; c++) {\n let lo = 0;\n let hi = tails.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (candidates[tails[mid]][0] < candidates[c][0]) lo = mid + 1;\n else hi = mid;\n }\n if (lo > 0) previous[c] = tails[lo - 1];\n tails[lo] = c;\n }\n const chain: Array<[number, number]> = [];\n for (let c = tails.length > 0 ? tails[tails.length - 1] : -1; c >= 0; c = previous[c]) chain.push(candidates[c]);\n return chain.reverse();\n}\n\n/**\n * Carry `from`'s identities onto `to`, and report what changed.\n *\n * `to` is freshly tokenized and owns ids nobody has seen yet, so rewriting them\n * in place is safe and is what makes the transition cheap: after this, the two\n * structures share an id for every token that survived the edit.\n */\nexport function diffCode(from: IdLine[], to: IdLine[]): CodeEdit {\n const removedIds = new Set<number>();\n const addedIds = new Set<number>();\n const newLineIds = new Set<number>();\n const fromColorById = new Map<number, string | undefined>();\n\n const linePairs = alignLines(from, to);\n\n const pairedTo = new Set<number>();\n const pairedFrom = new Set<number>();\n\n for (const [fi, ti] of linePairs) {\n pairedFrom.add(fi);\n pairedTo.add(ti);\n const fromLine = from[fi];\n const toLine = to[ti];\n toLine.id = fromLine.id;\n\n const matched = sameTokens(fromLine, toLine)\n ? fromLine.tokens.map((_, k): [number, number] => [k, k])\n : alignTokens(fromLine.tokens, toLine.tokens);\n const keptFrom = new Set<number>();\n const keptTo = new Set<number>();\n for (const [a, b] of matched) {\n keptFrom.add(a);\n keptTo.add(b);\n const oldTok = fromLine.tokens[a];\n const newTok = toLine.tokens[b];\n newTok.id = oldTok.id;\n if (oldTok.color !== newTok.color) fromColorById.set(oldTok.id, oldTok.color);\n }\n for (let a = 0; a < fromLine.tokens.length; a++) {\n if (!keptFrom.has(a)) removedIds.add(fromLine.tokens[a].id);\n }\n for (let b = 0; b < toLine.tokens.length; b++) {\n if (!keptTo.has(b)) addedIds.add(toLine.tokens[b].id);\n }\n }\n\n for (let i = 0; i < from.length; i++) {\n if (pairedFrom.has(i)) continue;\n for (const tok of from[i].tokens) removedIds.add(tok.id);\n }\n for (let j = 0; j < to.length; j++) {\n if (pairedTo.has(j)) continue;\n newLineIds.add(to[j].id);\n for (const tok of to[j].tokens) addedIds.add(tok.id);\n }\n\n return { lines: to, removedIds, addedIds, newLineIds, fromColorById };\n}\n"]}
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IdLine, IdToken } from \"./tokens\";\n\n/** Decides which token became which across an edit; `diffCode` (exported as `defaultCodeDiff`) is the default. */\nexport type CodeDiffStrategy = (from: IdLine[], to: IdLine[]) => CodeEdit;\n\n/** The next structure with ids carried over wherever content survived, so a surviving token moves rather than dissolves and rebuilds. */\nexport interface CodeEdit {\n /** The new structure; ids are rewritten in place onto the tokens handed in. */\n lines: IdLine[];\n removedIds: Set<number>;\n addedIds: Set<number>;\n /** Lines that did not exist before; they enter as a whole row. */\n newLineIds: Set<number>;\n /** Previous colour of a surviving token whose highlighting changed, for the cross-fade. */\n fromColorById: Map<number, string | undefined>;\n}\n\n/** Below this similarity two lines are one deleted and one inserted, not one edited: carrying ids across would slide glyphs between unrelated words. */\nconst LINE_MATCH_FLOOR = 0.45;\n\n/**\n * Most line pairs scored in one run of changed lines, and across a whole edit.\n * Scoring every pair is quadratic (741 ms at 1,000 lines), so only a run between\n * two anchors (see {@link alignLines}) is scored; past the budget its lines leave\n * and enter as whole rows.\n */\nconst LINE_ALIGN_CELLS = 40_000;\nconst EDIT_ALIGN_CELLS = 160_000;\n\nfunction tokenWeight(tok: IdToken): number {\n return tok.content.trim().length;\n}\n\nfunction lineWeight(line: IdLine): number {\n let sum = 0;\n for (const tok of line.tokens) sum += tokenWeight(tok);\n return sum;\n}\n\n/**\n * Dice coefficient over the lines' token multisets, weighted by visible characters.\n * Two blank lines are identical (1) but a blank against a non-blank shares nothing\n * (0), so blank rows a reformat introduces never anchor onto real code.\n */\nfunction similarity(a: IdLine, b: IdLine): number {\n const wa = lineWeight(a);\n const wb = lineWeight(b);\n if (wa === 0 && wb === 0) return 1;\n if (wa === 0 || wb === 0) return 0;\n\n const bag = new Map<string, number>();\n for (const tok of a.tokens) {\n if (tokenWeight(tok) === 0) continue;\n bag.set(tok.content, (bag.get(tok.content) ?? 0) + 1);\n }\n let common = 0;\n for (const tok of b.tokens) {\n const w = tokenWeight(tok);\n if (w === 0) continue;\n const left = bag.get(tok.content) ?? 0;\n if (left > 0) {\n bag.set(tok.content, left - 1);\n common += w;\n }\n }\n return (2 * common) / (wa + wb);\n}\n\n/**\n * Matched index pairs, in order, maximising total `score`; a pair scoring <= 0 is\n * skipped. An LCS would pair only identical elements, but two lines that differ by\n * one word are the same line.\n */\nfunction align(\n aLength: number,\n bLength: number,\n score: (i: number, j: number) => number,\n): Array<[number, number]> {\n const width = bLength + 1;\n const dp = new Float64Array((aLength + 1) * width);\n const pairScore = new Float64Array(aLength * bLength);\n\n for (let i = 1; i <= aLength; i++) {\n for (let j = 1; j <= bLength; j++) {\n const s = score(i - 1, j - 1);\n pairScore[(i - 1) * bLength + (j - 1)] = s;\n const skipA = dp[(i - 1) * width + j];\n const skipB = dp[i * width + (j - 1)];\n let best = skipA > skipB ? skipA : skipB;\n if (s > 0) {\n const paired = dp[(i - 1) * width + (j - 1)] + s;\n if (paired > best) best = paired;\n }\n dp[i * width + j] = best;\n }\n }\n\n const pairs: Array<[number, number]> = [];\n let i = aLength;\n let j = bLength;\n while (i > 0 && j > 0) {\n const s = pairScore[(i - 1) * bLength + (j - 1)];\n if (s > 0 && dp[i * width + j] === dp[(i - 1) * width + (j - 1)] + s) {\n pairs.push([i - 1, j - 1]);\n i--; j--;\n } else if (dp[(i - 1) * width + j] >= dp[i * width + (j - 1)]) {\n i--;\n } else {\n j--;\n }\n }\n pairs.reverse();\n return pairs;\n}\n\n/** Scored by visible characters, so keeping `items.reduce` beats keeping four spaces; a changed word is a different token. */\nfunction alignTokens(from: IdToken[], to: IdToken[]): Array<[number, number]> {\n return align(from.length, to.length, (i, j) => {\n if (from[i].content !== to[j].content) return 0;\n // Whitespace pairs weakly: it holds indentation together but never outranks content.\n return tokenWeight(to[j]) || 0.25;\n });\n}\n\nfunction sameTokens(a: IdLine, b: IdLine): boolean {\n if (a.tokens.length !== b.tokens.length) return false;\n for (let k = 0; k < a.tokens.length; k++) if (a.tokens[k].content !== b.tokens[k].content) return false;\n return true;\n}\n\n/** Text with token boundaries, so identical lines tell apart from similar ones. */\nfunction signature(line: IdLine): string {\n let out = \"\";\n for (const tok of line.tokens) out += tok.content + \"\\u0001\";\n return out;\n}\n\n/**\n * Pairs lines in order: identical head and tail outright, then the longest ordered\n * run of lines occurring once on each side as anchors, with each run between\n * anchors scored within the budget. A one-line edit to a long listing therefore\n * never builds a table bigger than the lines around it.\n */\nfunction alignLines(from: IdLine[], to: IdLine[]): Array<[number, number]> {\n const fromSig = from.map(signature);\n const toSig = to.map(signature);\n const pairs: Array<[number, number]> = [];\n\n let head = 0;\n while (head < from.length && head < to.length && fromSig[head] === toSig[head]) {\n pairs.push([head, head]);\n head++;\n }\n let tail = 0;\n while (\n tail < from.length - head && tail < to.length - head\n && fromSig[from.length - 1 - tail] === toSig[to.length - 1 - tail]\n ) tail++;\n\n const anchors = anchorLines(fromSig, toSig, head, from.length - tail, head, to.length - tail);\n let budget = EDIT_ALIGN_CELLS;\n let fi = head;\n let ti = head;\n for (const [af, at] of [...anchors, [from.length - tail, to.length - tail] as [number, number]]) {\n const rows = af - fi;\n const cols = at - ti;\n const cells = rows * cols;\n if (cells > 0 && cells <= LINE_ALIGN_CELLS && cells <= budget) {\n budget -= cells;\n for (const [i, j] of align(rows, cols, (a, b) => similarity(from[fi + a], to[ti + b]) - LINE_MATCH_FLOOR)) {\n pairs.push([fi + i, ti + j]);\n }\n }\n if (af < from.length - tail) pairs.push([af, at]);\n fi = af + 1;\n ti = at + 1;\n }\n for (let k = tail; k > 0; k--) pairs.push([from.length - k, to.length - k]);\n return pairs;\n}\n\n/** Lines occurring once on each side, reduced to the longest subsequence increasing on both (patience sorting); blanks never anchor. */\nfunction anchorLines(\n fromSig: string[],\n toSig: string[],\n fa: number,\n fb: number,\n ta: number,\n tb: number,\n): Array<[number, number]> {\n const fromAt = new Map<string, number>();\n const seen = new Set<string>();\n for (let i = fa; i < fb; i++) {\n const sig = fromSig[i];\n if (seen.has(sig)) fromAt.delete(sig);\n else fromAt.set(sig, i);\n seen.add(sig);\n }\n const toAt = new Map<string, number>();\n const seenTo = new Set<string>();\n for (let j = ta; j < tb; j++) {\n const sig = toSig[j];\n if (seenTo.has(sig)) toAt.delete(sig);\n else toAt.set(sig, j);\n seenTo.add(sig);\n }\n\n const candidates: Array<[number, number]> = [];\n for (let j = ta; j < tb; j++) {\n const i = fromAt.get(toSig[j]);\n if (i !== undefined && toAt.get(toSig[j]) === j && toSig[j].replaceAll(\"\\u0001\", \"\").trim() !== \"\") {\n candidates.push([i, j]);\n }\n }\n\n const tails: number[] = [];\n const previous: number[] = new Array(candidates.length).fill(-1);\n for (let c = 0; c < candidates.length; c++) {\n let lo = 0;\n let hi = tails.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (candidates[tails[mid]][0] < candidates[c][0]) lo = mid + 1;\n else hi = mid;\n }\n if (lo > 0) previous[c] = tails[lo - 1];\n tails[lo] = c;\n }\n const chain: Array<[number, number]> = [];\n for (let c = tails.length > 0 ? tails[tails.length - 1] : -1; c >= 0; c = previous[c]) chain.push(candidates[c]);\n return chain.reverse();\n}\n\n/** Carries `from`'s ids onto `to`; `to` is freshly tokenized, so rewriting its ids in place is safe. */\nexport function diffCode(from: IdLine[], to: IdLine[]): CodeEdit {\n const removedIds = new Set<number>();\n const addedIds = new Set<number>();\n const newLineIds = new Set<number>();\n const fromColorById = new Map<number, string | undefined>();\n\n const linePairs = alignLines(from, to);\n\n const pairedTo = new Set<number>();\n const pairedFrom = new Set<number>();\n\n for (const [fi, ti] of linePairs) {\n pairedFrom.add(fi);\n pairedTo.add(ti);\n const fromLine = from[fi];\n const toLine = to[ti];\n toLine.id = fromLine.id;\n\n const matched = sameTokens(fromLine, toLine)\n ? fromLine.tokens.map((_, k): [number, number] => [k, k])\n : alignTokens(fromLine.tokens, toLine.tokens);\n const keptFrom = new Set<number>();\n const keptTo = new Set<number>();\n for (const [a, b] of matched) {\n keptFrom.add(a);\n keptTo.add(b);\n const oldTok = fromLine.tokens[a];\n const newTok = toLine.tokens[b];\n newTok.id = oldTok.id;\n if (oldTok.color !== newTok.color) fromColorById.set(oldTok.id, oldTok.color);\n }\n for (let a = 0; a < fromLine.tokens.length; a++) {\n if (!keptFrom.has(a)) removedIds.add(fromLine.tokens[a].id);\n }\n for (let b = 0; b < toLine.tokens.length; b++) {\n if (!keptTo.has(b)) addedIds.add(toLine.tokens[b].id);\n }\n }\n\n for (let i = 0; i < from.length; i++) {\n if (pairedFrom.has(i)) continue;\n for (const tok of from[i].tokens) removedIds.add(tok.id);\n }\n for (let j = 0; j < to.length; j++) {\n if (pairedTo.has(j)) continue;\n newLineIds.add(to[j].id);\n for (const tok of to[j].tokens) addedIds.add(tok.id);\n }\n\n return { lines: to, removedIds, addedIds, newLineIds, fromColorById };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAOA,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,QAAQ,IAAI,eAAe,EAAE,MAAM,QAAQ,CAAC;AACrD,YAAY,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACzJ,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACjD,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,gBAAgB,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpJ,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC3F,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC/G,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAGA,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,QAAQ,IAAI,eAAe,EAAE,MAAM,QAAQ,CAAC;AACrD,YAAY,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACzJ,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACjD,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,gBAAgB,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpJ,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC3F,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC/G,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC"}
package/dist/engine.js CHANGED
@@ -1,10 +1,6 @@
1
- // The Code "engine": syntax highlighting, tokenizing, layout, diffing, and
2
- // transition/phase scheduling — kept separate from node.ts so a copy of the node
3
- // can take just its declaration and import this behind
4
- // `@motionscript/code` instead. What gets copied is whatever this
5
- // package's registry.json declares, which for this component is node.ts;
6
- // src/tests/registry.test.ts checks that anything it
7
- // reaches for is either copied alongside it or re-exported from here.
1
+ // Everything node.ts imports besides its own declaration, so a copy of the node can take
2
+ // just node.ts and import this from `@motionscript/code`. registry.test.ts checks that
3
+ // whatever node.ts reaches for is copied alongside it or re-exported from here.
8
4
  export * from './transitions.js';
9
5
  export * from './layout.js';
10
6
  export { drawCode } from './render.js';
@@ -1 +1 @@
1
- {"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,iFAAiF;AACjF,uDAAuD;AACvD,kEAAkE;AAClE,yEAAyE;AACzE,qDAAqD;AACrD,sEAAsE;AACtE,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,OAAO,EAAE,QAAQ,IAAI,eAAe,EAAE,MAAM,QAAQ,CAAC;AAErD,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACzJ,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAEjD,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,gBAAgB,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEpJ,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC","sourcesContent":["// The Code \"engine\": syntax highlighting, tokenizing, layout, diffing, and\n// transition/phase scheduling — kept separate from node.ts so a copy of the node\n// can take just its declaration and import this behind\n// `@motionscript/code` instead. What gets copied is whatever this\n// package's registry.json declares, which for this component is node.ts;\n// src/tests/registry.test.ts checks that anything it\n// reaches for is either copied alongside it or re-exported from here.\nexport * from './transitions';\nexport * from './layout';\nexport { drawCode } from './render';\nexport type { CodeCanvas, DrawCodeState } from './render';\nexport { diffCode as defaultCodeDiff } from './diff';\nexport type { CodeDiffStrategy, CodeEdit } from './diff';\nexport { loadCodeLanguage, initSyntaxHighlighter, ensureHighlighter, registerCodeTheme, resolveTheme, canHighlight, normalizeSource } from './highlight';\nexport { tokenizeCodeToIdLines } from './tokens';\nexport type { IdLine, IdToken } from './tokens';\nexport { DefaultHighlightStyle, GithubDarkStyle, GithubLightStyle, VscodeDarkStyle, VscodeLightStyle, BUILTIN_THEMES, compileStyle } from './style';\nexport type { CodeHighlightStyle, CodeStyleRule, CodeTheme, CodeThemeName } from './style';\nexport { TokenAdvanceCache } from './measure-cache';\nexport { word, lines, rangeToCharOffsets, charOffsetsToRange, CodeRanges, CodeRangeChain } from './code-range';\nexport type { CodeRange } from './code-range';\n"]}
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,uFAAuF;AACvF,gFAAgF;AAChF,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,OAAO,EAAE,QAAQ,IAAI,eAAe,EAAE,MAAM,QAAQ,CAAC;AAErD,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACzJ,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAEjD,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,gBAAgB,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEpJ,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC","sourcesContent":["// Everything node.ts imports besides its own declaration, so a copy of the node can take\n// just node.ts and import this from `@motionscript/code`. registry.test.ts checks that\n// whatever node.ts reaches for is copied alongside it or re-exported from here.\nexport * from './transitions';\nexport * from './layout';\nexport { drawCode } from './render';\nexport type { CodeCanvas, DrawCodeState } from './render';\nexport { diffCode as defaultCodeDiff } from './diff';\nexport type { CodeDiffStrategy, CodeEdit } from './diff';\nexport { loadCodeLanguage, initSyntaxHighlighter, ensureHighlighter, registerCodeTheme, resolveTheme, canHighlight, normalizeSource } from './highlight';\nexport { tokenizeCodeToIdLines } from './tokens';\nexport type { IdLine, IdToken } from './tokens';\nexport { DefaultHighlightStyle, GithubDarkStyle, GithubLightStyle, VscodeDarkStyle, VscodeLightStyle, BUILTIN_THEMES, compileStyle } from './style';\nexport type { CodeHighlightStyle, CodeStyleRule, CodeTheme, CodeThemeName } from './style';\nexport { TokenAdvanceCache } from './measure-cache';\nexport { word, lines, rangeToCharOffsets, charOffsetsToRange, CodeRanges, CodeRangeChain } from './code-range';\nexport type { CodeRange } from './code-range';\n"]}