tree-sitter-ts-highlight-svelte 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -0
- package/dist/components/Highlight.svelte +78 -0
- package/dist/components/Highlight.svelte.d.ts +26 -0
- package/dist/components/Highlight.svelte.d.ts.map +1 -0
- package/dist/components/HighlightDiff.svelte +210 -0
- package/dist/components/HighlightDiff.svelte.d.ts +26 -0
- package/dist/components/HighlightDiff.svelte.d.ts.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/lib/highlight.d.ts +29 -0
- package/dist/lib/highlight.d.ts.map +1 -0
- package/dist/lib/highlight.js +29 -0
- package/dist/lib/svelte-renderer.d.ts +43 -0
- package/dist/lib/svelte-renderer.d.ts.map +1 -0
- package/dist/lib/svelte-renderer.js +109 -0
- package/dist/test/highlight.test.d.ts +2 -0
- package/dist/test/highlight.test.d.ts.map +1 -0
- package/dist/test/highlight.test.js +63 -0
- package/dist/test/svelte-renderer.test.d.ts +2 -0
- package/dist/test/svelte-renderer.test.d.ts.map +1 -0
- package/dist/test/svelte-renderer.test.js +94 -0
- package/package.json +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# tree-sitter-ts-highlight-svelte
|
|
2
|
+
|
|
3
|
+
Native Svelte components and utilities for `tree-sitter-ts-highlight`.
|
|
4
|
+
Use this package when you want syntax-highlighted code/diffs rendered as native Svelte nodes.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install tree-sitter-ts-highlight-svelte tree-sitter-ts-highlight tree-sitter-ts
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Import a theme once in your app entry:
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import "tree-sitter-ts-highlight/themes/github-dark.css";
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Quick start
|
|
19
|
+
|
|
20
|
+
```svelte
|
|
21
|
+
<script lang="ts">
|
|
22
|
+
import { Highlight, HighlightDiff } from "tree-sitter-ts-highlight-svelte";
|
|
23
|
+
|
|
24
|
+
const oldCode = `const n = 1;`;
|
|
25
|
+
const newCode = `const n = 2;`;
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<Highlight
|
|
29
|
+
code={`const total: number = 42;`}
|
|
30
|
+
language="typescript"
|
|
31
|
+
options={{ lineNumbers: true }}
|
|
32
|
+
/>
|
|
33
|
+
|
|
34
|
+
<HighlightDiff
|
|
35
|
+
oldCode={oldCode}
|
|
36
|
+
newCode={newCode}
|
|
37
|
+
language="typescript"
|
|
38
|
+
options={{ view: "side-by-side" }}
|
|
39
|
+
/>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Exports
|
|
43
|
+
|
|
44
|
+
### Components
|
|
45
|
+
|
|
46
|
+
- `Highlight`
|
|
47
|
+
- Props: `code`, `language`, `options?`, `preClassName?`, `codeClassName?`
|
|
48
|
+
- Renders highlighted code inside `<pre><code>`.
|
|
49
|
+
- `HighlightDiff`
|
|
50
|
+
- Props: `oldCode`, `newCode`, `language`, `options?`, `containerClassName?`
|
|
51
|
+
- Renders inline or side-by-side diffs.
|
|
52
|
+
|
|
53
|
+
### Utilities
|
|
54
|
+
|
|
55
|
+
- `getHighlightedHtml({ code, language, options? })`
|
|
56
|
+
- `getHighlightedDiffHtml({ oldCode, newCode, language, options? })`
|
|
57
|
+
- `createHighlightedHtmlStore({ code, language, options? })`
|
|
58
|
+
- `createHighlightedDiffHtmlStore({ oldCode, newCode, language, options? })`
|
|
59
|
+
|
|
60
|
+
All exports from `tree-sitter-ts-highlight` are also re-exported.
|
|
61
|
+
Type exports from `tree-sitter-ts-highlight` and `Token` from `tree-sitter-ts` are re-exported for TypeScript consumers.
|
|
62
|
+
|
|
63
|
+
## Notes
|
|
64
|
+
|
|
65
|
+
- `language` is passed through to `tree-sitter-ts-highlight`.
|
|
66
|
+
- `Highlight` always renders with `wrapInPre: false` internally to avoid nested `<pre>`.
|
|
67
|
+
- For additional live demos and theme previews, use the upstream project page:
|
|
68
|
+
<https://github.com/hieutran512/tree-sitter-ts-highlight>
|
|
69
|
+
|
|
70
|
+
## Package scripts
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npm run build
|
|
74
|
+
npm run typecheck
|
|
75
|
+
npm test
|
|
76
|
+
```
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { HighlightOptions } from "tree-sitter-ts-highlight";
|
|
3
|
+
import {
|
|
4
|
+
createHighlightRenderable,
|
|
5
|
+
styleObjectToCssText,
|
|
6
|
+
type RenderToken,
|
|
7
|
+
} from "../lib/svelte-renderer";
|
|
8
|
+
|
|
9
|
+
interface HighlightProps {
|
|
10
|
+
code: string;
|
|
11
|
+
language: string;
|
|
12
|
+
options?: Omit<HighlightOptions, "wrapInPre" | "language">;
|
|
13
|
+
preClassName?: string;
|
|
14
|
+
codeClassName?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export let code: HighlightProps["code"];
|
|
18
|
+
export let language: HighlightProps["language"];
|
|
19
|
+
export let options: HighlightProps["options"] = undefined;
|
|
20
|
+
export let preClassName: HighlightProps["preClassName"] = "";
|
|
21
|
+
export let codeClassName: HighlightProps["codeClassName"] = "";
|
|
22
|
+
|
|
23
|
+
$: renderable = createHighlightRenderable(code, language, options);
|
|
24
|
+
$: preStyle = styleObjectToCssText(renderable.preStyle);
|
|
25
|
+
$: mergedPreClass = ["hlts", `hlts-lang-${language}`, preClassName]
|
|
26
|
+
.filter(Boolean)
|
|
27
|
+
.join(" ");
|
|
28
|
+
$: mergedCodeClass = [codeClassName].filter(Boolean).join(" ");
|
|
29
|
+
|
|
30
|
+
function tokenStyle(token: RenderToken): string {
|
|
31
|
+
return token.style ? styleObjectToCssText(token.style) : "";
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<pre class={mergedPreClass} style={preStyle}>
|
|
36
|
+
<code class={mergedCodeClass}>
|
|
37
|
+
{#if renderable.lineNumbers}
|
|
38
|
+
<table class="hlts-table">
|
|
39
|
+
<tbody>
|
|
40
|
+
{#each renderable.lines as line}
|
|
41
|
+
<tr
|
|
42
|
+
data-line={renderable.dataLineAttributes
|
|
43
|
+
? line.lineNumber
|
|
44
|
+
: undefined}>
|
|
45
|
+
<td class="hlts-line-number">{line.lineNumber}</td>
|
|
46
|
+
<td class="hlts-line-content">
|
|
47
|
+
{#each line.tokens as token}
|
|
48
|
+
{#if token.wrap}
|
|
49
|
+
<span
|
|
50
|
+
class={token.className}
|
|
51
|
+
style={tokenStyle(token)}
|
|
52
|
+
{...token.dataAttrs}
|
|
53
|
+
>{token.value}</span
|
|
54
|
+
>
|
|
55
|
+
{:else}
|
|
56
|
+
{token.value}
|
|
57
|
+
{/if}
|
|
58
|
+
{/each}
|
|
59
|
+
</td>
|
|
60
|
+
</tr>
|
|
61
|
+
{/each}
|
|
62
|
+
</tbody>
|
|
63
|
+
</table>
|
|
64
|
+
{:else}
|
|
65
|
+
{#each renderable.tokens as token}
|
|
66
|
+
{#if token.wrap}
|
|
67
|
+
<span
|
|
68
|
+
class={token.className}
|
|
69
|
+
style={tokenStyle(token)}
|
|
70
|
+
{...token.dataAttrs}>{token.value}</span
|
|
71
|
+
>
|
|
72
|
+
{:else}
|
|
73
|
+
{token.value}
|
|
74
|
+
{/if}
|
|
75
|
+
{/each}
|
|
76
|
+
{/if}
|
|
77
|
+
</code>
|
|
78
|
+
</pre>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { HighlightOptions } from "tree-sitter-ts-highlight";
|
|
2
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
3
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
+
$$bindings?: Bindings;
|
|
5
|
+
} & Exports;
|
|
6
|
+
(internal: unknown, props: Props & {
|
|
7
|
+
$$events?: Events;
|
|
8
|
+
$$slots?: Slots;
|
|
9
|
+
}): Exports & {
|
|
10
|
+
$set?: any;
|
|
11
|
+
$on?: any;
|
|
12
|
+
};
|
|
13
|
+
z_$$bindings?: Bindings;
|
|
14
|
+
}
|
|
15
|
+
declare const Highlight: $$__sveltets_2_IsomorphicComponent<{
|
|
16
|
+
code: string;
|
|
17
|
+
language: string;
|
|
18
|
+
options?: Omit<HighlightOptions, "wrapInPre" | "language"> | undefined;
|
|
19
|
+
preClassName?: string | undefined;
|
|
20
|
+
codeClassName?: string | undefined;
|
|
21
|
+
}, {
|
|
22
|
+
[evt: string]: CustomEvent<any>;
|
|
23
|
+
}, {}, {}, string>;
|
|
24
|
+
type Highlight = InstanceType<typeof Highlight>;
|
|
25
|
+
export default Highlight;
|
|
26
|
+
//# sourceMappingURL=Highlight.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Highlight.svelte.d.ts","sourceRoot":"","sources":["../../src/components/Highlight.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AA0EjE,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAKD,QAAA,MAAM,SAAS;;;;;;;;kBAA+E,CAAC;AAC7E,KAAK,SAAS,GAAG,YAAY,CAAC,OAAO,SAAS,CAAC,CAAC;AAClD,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { DiffOptions } from "tree-sitter-ts-highlight";
|
|
3
|
+
import {
|
|
4
|
+
createDiffRenderable,
|
|
5
|
+
styleObjectToCssText,
|
|
6
|
+
type RenderToken,
|
|
7
|
+
} from "../lib/svelte-renderer";
|
|
8
|
+
|
|
9
|
+
interface HighlightDiffProps {
|
|
10
|
+
oldCode: string;
|
|
11
|
+
newCode: string;
|
|
12
|
+
language: string;
|
|
13
|
+
options?: DiffOptions;
|
|
14
|
+
containerClassName?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export let oldCode: HighlightDiffProps["oldCode"];
|
|
18
|
+
export let newCode: HighlightDiffProps["newCode"];
|
|
19
|
+
export let language: HighlightDiffProps["language"];
|
|
20
|
+
export let options: HighlightDiffProps["options"] = undefined;
|
|
21
|
+
export let containerClassName: HighlightDiffProps["containerClassName"] =
|
|
22
|
+
"";
|
|
23
|
+
|
|
24
|
+
$: renderable = createDiffRenderable(oldCode, newCode, language, options);
|
|
25
|
+
|
|
26
|
+
function tokenStyle(token: RenderToken): string {
|
|
27
|
+
return token.style ? styleObjectToCssText(token.style) : "";
|
|
28
|
+
}
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<div class={containerClassName}>
|
|
32
|
+
{#if renderable.view === "inline"}
|
|
33
|
+
<table
|
|
34
|
+
class={`${renderable.classPrefix}diff ${renderable.classPrefix}diff-inline`}
|
|
35
|
+
>
|
|
36
|
+
<tbody>
|
|
37
|
+
{#each renderable.rows as row}
|
|
38
|
+
{#if row.changeType === "context"}
|
|
39
|
+
<tr
|
|
40
|
+
class={`${renderable.classPrefix}diff-row ${renderable.classPrefix}diff-context`}
|
|
41
|
+
>
|
|
42
|
+
<td class={`${renderable.classPrefix}diff-gutter`}
|
|
43
|
+
>{row.newLineNumber ?? ""}</td
|
|
44
|
+
>
|
|
45
|
+
<td class={`${renderable.classPrefix}diff-sign`}>
|
|
46
|
+
</td>
|
|
47
|
+
<td class={`${renderable.classPrefix}diff-content`}>
|
|
48
|
+
{#if row.newTokens.length > 0}
|
|
49
|
+
{#each row.newTokens as token}
|
|
50
|
+
{#if token.wrap}
|
|
51
|
+
<span
|
|
52
|
+
class={token.className}
|
|
53
|
+
style={tokenStyle(token)}
|
|
54
|
+
{...token.dataAttrs}
|
|
55
|
+
>{token.value}</span
|
|
56
|
+
>
|
|
57
|
+
{:else}
|
|
58
|
+
{token.value}
|
|
59
|
+
{/if}
|
|
60
|
+
{/each}
|
|
61
|
+
{:else}
|
|
62
|
+
{row.newText}
|
|
63
|
+
{/if}
|
|
64
|
+
</td>
|
|
65
|
+
</tr>
|
|
66
|
+
{:else}
|
|
67
|
+
{#if row.oldLineNumber !== null}
|
|
68
|
+
<tr
|
|
69
|
+
class={`${renderable.classPrefix}diff-row ${renderable.classPrefix}diff-removed`}
|
|
70
|
+
>
|
|
71
|
+
<td
|
|
72
|
+
class={`${renderable.classPrefix}diff-gutter`}
|
|
73
|
+
>{row.oldLineNumber}</td
|
|
74
|
+
>
|
|
75
|
+
<td class={`${renderable.classPrefix}diff-sign`}
|
|
76
|
+
>-</td
|
|
77
|
+
>
|
|
78
|
+
<td
|
|
79
|
+
class={`${renderable.classPrefix}diff-content`}
|
|
80
|
+
>
|
|
81
|
+
{#if row.oldTokens.length > 0}
|
|
82
|
+
{#each row.oldTokens as token}
|
|
83
|
+
{#if token.wrap}
|
|
84
|
+
<span
|
|
85
|
+
class={token.className}
|
|
86
|
+
style={tokenStyle(token)}
|
|
87
|
+
{...token.dataAttrs}
|
|
88
|
+
>{token.value}</span
|
|
89
|
+
>
|
|
90
|
+
{:else}
|
|
91
|
+
{token.value}
|
|
92
|
+
{/if}
|
|
93
|
+
{/each}
|
|
94
|
+
{:else}
|
|
95
|
+
{row.oldText}
|
|
96
|
+
{/if}
|
|
97
|
+
</td>
|
|
98
|
+
</tr>
|
|
99
|
+
{/if}
|
|
100
|
+
{#if row.newLineNumber !== null}
|
|
101
|
+
<tr
|
|
102
|
+
class={`${renderable.classPrefix}diff-row ${renderable.classPrefix}diff-added`}
|
|
103
|
+
>
|
|
104
|
+
<td
|
|
105
|
+
class={`${renderable.classPrefix}diff-gutter`}
|
|
106
|
+
>{row.newLineNumber}</td
|
|
107
|
+
>
|
|
108
|
+
<td class={`${renderable.classPrefix}diff-sign`}
|
|
109
|
+
>+</td
|
|
110
|
+
>
|
|
111
|
+
<td
|
|
112
|
+
class={`${renderable.classPrefix}diff-content`}
|
|
113
|
+
>
|
|
114
|
+
{#if row.newTokens.length > 0}
|
|
115
|
+
{#each row.newTokens as token}
|
|
116
|
+
{#if token.wrap}
|
|
117
|
+
<span
|
|
118
|
+
class={token.className}
|
|
119
|
+
style={tokenStyle(token)}
|
|
120
|
+
{...token.dataAttrs}
|
|
121
|
+
>{token.value}</span
|
|
122
|
+
>
|
|
123
|
+
{:else}
|
|
124
|
+
{token.value}
|
|
125
|
+
{/if}
|
|
126
|
+
{/each}
|
|
127
|
+
{:else}
|
|
128
|
+
{row.newText}
|
|
129
|
+
{/if}
|
|
130
|
+
</td>
|
|
131
|
+
</tr>
|
|
132
|
+
{/if}
|
|
133
|
+
{/if}
|
|
134
|
+
{/each}
|
|
135
|
+
</tbody>
|
|
136
|
+
</table>
|
|
137
|
+
{:else}
|
|
138
|
+
<table
|
|
139
|
+
class={`${renderable.classPrefix}diff ${renderable.classPrefix}diff-side-by-side`}
|
|
140
|
+
>
|
|
141
|
+
<tbody>
|
|
142
|
+
{#if renderable.showHeader}
|
|
143
|
+
<tr class={`${renderable.classPrefix}diff-header`}>
|
|
144
|
+
<th
|
|
145
|
+
class={`${renderable.classPrefix}diff-label`}
|
|
146
|
+
colspan="2">{renderable.oldLabel}</th
|
|
147
|
+
>
|
|
148
|
+
<th
|
|
149
|
+
class={`${renderable.classPrefix}diff-label`}
|
|
150
|
+
colspan="2">{renderable.newLabel}</th
|
|
151
|
+
>
|
|
152
|
+
</tr>
|
|
153
|
+
{/if}
|
|
154
|
+
|
|
155
|
+
{#each renderable.rows as row}
|
|
156
|
+
<tr
|
|
157
|
+
class={`${renderable.classPrefix}diff-row ${renderable.classPrefix}diff-${row.changeType}`}
|
|
158
|
+
>
|
|
159
|
+
<td class={`${renderable.classPrefix}diff-gutter`}
|
|
160
|
+
>{row.oldLineNumber ?? ""}</td
|
|
161
|
+
>
|
|
162
|
+
<td class={`${renderable.classPrefix}diff-content`}>
|
|
163
|
+
{#if row.oldLineNumber !== null}
|
|
164
|
+
{#if row.oldTokens.length > 0}
|
|
165
|
+
{#each row.oldTokens as token}
|
|
166
|
+
{#if token.wrap}
|
|
167
|
+
<span
|
|
168
|
+
class={token.className}
|
|
169
|
+
style={tokenStyle(token)}
|
|
170
|
+
{...token.dataAttrs}
|
|
171
|
+
>{token.value}</span
|
|
172
|
+
>
|
|
173
|
+
{:else}
|
|
174
|
+
{token.value}
|
|
175
|
+
{/if}
|
|
176
|
+
{/each}
|
|
177
|
+
{:else}
|
|
178
|
+
{row.oldText}
|
|
179
|
+
{/if}
|
|
180
|
+
{/if}
|
|
181
|
+
</td>
|
|
182
|
+
<td class={`${renderable.classPrefix}diff-gutter`}
|
|
183
|
+
>{row.newLineNumber ?? ""}</td
|
|
184
|
+
>
|
|
185
|
+
<td class={`${renderable.classPrefix}diff-content`}>
|
|
186
|
+
{#if row.newLineNumber !== null}
|
|
187
|
+
{#if row.newTokens.length > 0}
|
|
188
|
+
{#each row.newTokens as token}
|
|
189
|
+
{#if token.wrap}
|
|
190
|
+
<span
|
|
191
|
+
class={token.className}
|
|
192
|
+
style={tokenStyle(token)}
|
|
193
|
+
{...token.dataAttrs}
|
|
194
|
+
>{token.value}</span
|
|
195
|
+
>
|
|
196
|
+
{:else}
|
|
197
|
+
{token.value}
|
|
198
|
+
{/if}
|
|
199
|
+
{/each}
|
|
200
|
+
{:else}
|
|
201
|
+
{row.newText}
|
|
202
|
+
{/if}
|
|
203
|
+
{/if}
|
|
204
|
+
</td>
|
|
205
|
+
</tr>
|
|
206
|
+
{/each}
|
|
207
|
+
</tbody>
|
|
208
|
+
</table>
|
|
209
|
+
{/if}
|
|
210
|
+
</div>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { DiffOptions } from "tree-sitter-ts-highlight";
|
|
2
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
3
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
+
$$bindings?: Bindings;
|
|
5
|
+
} & Exports;
|
|
6
|
+
(internal: unknown, props: Props & {
|
|
7
|
+
$$events?: Events;
|
|
8
|
+
$$slots?: Slots;
|
|
9
|
+
}): Exports & {
|
|
10
|
+
$set?: any;
|
|
11
|
+
$on?: any;
|
|
12
|
+
};
|
|
13
|
+
z_$$bindings?: Bindings;
|
|
14
|
+
}
|
|
15
|
+
declare const HighlightDiff: $$__sveltets_2_IsomorphicComponent<{
|
|
16
|
+
oldCode: string;
|
|
17
|
+
newCode: string;
|
|
18
|
+
language: string;
|
|
19
|
+
options?: DiffOptions | undefined;
|
|
20
|
+
containerClassName?: string | undefined;
|
|
21
|
+
}, {
|
|
22
|
+
[evt: string]: CustomEvent<any>;
|
|
23
|
+
}, {}, {}, string>;
|
|
24
|
+
type HighlightDiff = InstanceType<typeof HighlightDiff>;
|
|
25
|
+
export default HighlightDiff;
|
|
26
|
+
//# sourceMappingURL=HighlightDiff.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HighlightDiff.svelte.d.ts","sourceRoot":"","sources":["../../src/components/HighlightDiff.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAyJ5D,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAKD,QAAA,MAAM,aAAa;;;;;;;;kBAA+E,CAAC;AACjF,KAAK,aAAa,GAAG,YAAY,CAAC,OAAO,aAAa,CAAC,CAAC;AAC1D,eAAe,aAAa,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { default as Highlight } from "./components/Highlight.svelte";
|
|
2
|
+
export { default as HighlightDiff } from "./components/HighlightDiff.svelte";
|
|
3
|
+
export { getHighlightedHtml, getHighlightedDiffHtml, createHighlightedHtmlStore, createHighlightedDiffHtmlStore, } from "./lib/highlight";
|
|
4
|
+
export type { GetHighlightedHtmlParams, GetHighlightedDiffHtmlParams, HighlightedHtmlStoreParams, HighlightedDiffHtmlStoreParams, } from "./lib/highlight";
|
|
5
|
+
export type { HighlightRenderable, DiffRenderable, DiffRenderableRow, RenderToken, } from "./lib/svelte-renderer";
|
|
6
|
+
export { createHighlightRenderable, createDiffRenderable, cssTextToStyleObject, } from "./lib/svelte-renderer";
|
|
7
|
+
export type { Token } from "tree-sitter-ts";
|
|
8
|
+
export type * from "tree-sitter-ts-highlight";
|
|
9
|
+
export * from "tree-sitter-ts-highlight";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAE7E,OAAO,EACH,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC1B,8BAA8B,GACjC,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACR,wBAAwB,EACxB,4BAA4B,EAC5B,0BAA0B,EAC1B,8BAA8B,GACjC,MAAM,iBAAiB,CAAC;AAEzB,YAAY,EACR,mBAAmB,EACnB,cAAc,EACd,iBAAiB,EACjB,WAAW,GACd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACH,yBAAyB,EACzB,oBAAoB,EACpB,oBAAoB,GACvB,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAC5C,mBAAmB,0BAA0B,CAAC;AAC9C,cAAc,0BAA0B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { default as Highlight } from "./components/Highlight.svelte";
|
|
2
|
+
export { default as HighlightDiff } from "./components/HighlightDiff.svelte";
|
|
3
|
+
export { getHighlightedHtml, getHighlightedDiffHtml, createHighlightedHtmlStore, createHighlightedDiffHtmlStore, } from "./lib/highlight";
|
|
4
|
+
export { createHighlightRenderable, createDiffRenderable, cssTextToStyleObject, } from "./lib/svelte-renderer";
|
|
5
|
+
export * from "tree-sitter-ts-highlight";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { DiffOptions, HighlightOptions } from "tree-sitter-ts-highlight";
|
|
2
|
+
import { type Readable } from "svelte/store";
|
|
3
|
+
export interface GetHighlightedHtmlParams {
|
|
4
|
+
code: string;
|
|
5
|
+
language: string;
|
|
6
|
+
options?: Omit<HighlightOptions, "wrapInPre" | "language">;
|
|
7
|
+
}
|
|
8
|
+
export declare function getHighlightedHtml({ code, language, options, }: GetHighlightedHtmlParams): string;
|
|
9
|
+
export interface GetHighlightedDiffHtmlParams {
|
|
10
|
+
oldCode: string;
|
|
11
|
+
newCode: string;
|
|
12
|
+
language: string;
|
|
13
|
+
options?: DiffOptions;
|
|
14
|
+
}
|
|
15
|
+
export declare function getHighlightedDiffHtml({ oldCode, newCode, language, options, }: GetHighlightedDiffHtmlParams): string;
|
|
16
|
+
export interface HighlightedHtmlStoreParams {
|
|
17
|
+
code: Readable<string>;
|
|
18
|
+
language: Readable<string>;
|
|
19
|
+
options?: Readable<Omit<HighlightOptions, "wrapInPre" | "language"> | undefined>;
|
|
20
|
+
}
|
|
21
|
+
export declare function createHighlightedHtmlStore({ code, language, options, }: HighlightedHtmlStoreParams): Readable<string>;
|
|
22
|
+
export interface HighlightedDiffHtmlStoreParams {
|
|
23
|
+
oldCode: Readable<string>;
|
|
24
|
+
newCode: Readable<string>;
|
|
25
|
+
language: Readable<string>;
|
|
26
|
+
options?: Readable<DiffOptions | undefined>;
|
|
27
|
+
}
|
|
28
|
+
export declare function createHighlightedDiffHtmlStore({ oldCode, newCode, language, options, }: HighlightedDiffHtmlStoreParams): Readable<string>;
|
|
29
|
+
//# sourceMappingURL=highlight.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"highlight.d.ts","sourceRoot":"","sources":["../../src/lib/highlight.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC9E,OAAO,EAAW,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAEtD,MAAM,WAAW,wBAAwB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,WAAW,GAAG,UAAU,CAAC,CAAC;CAC9D;AAED,wBAAgB,kBAAkB,CAAC,EAC/B,IAAI,EACJ,QAAQ,EACR,OAAO,GACV,EAAE,wBAAwB,GAAG,MAAM,CAMnC;AAED,MAAM,WAAW,4BAA4B;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,WAAW,CAAC;CACzB;AAED,wBAAgB,sBAAsB,CAAC,EACnC,OAAO,EACP,OAAO,EACP,QAAQ,EACR,OAAO,GACV,EAAE,4BAA4B,GAAG,MAAM,CAEvC;AAED,MAAM,WAAW,0BAA0B;IACvC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACvB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC3B,OAAO,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,gBAAgB,EAAE,WAAW,GAAG,UAAU,CAAC,GAAG,SAAS,CAAC,CAAC;CACpF;AAED,wBAAgB,0BAA0B,CAAC,EACvC,IAAI,EACJ,QAAQ,EACR,OAAO,GACV,EAAE,0BAA0B,GAAG,QAAQ,CAAC,MAAM,CAAC,CAU/C;AAED,MAAM,WAAW,8BAA8B;IAC3C,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC1B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC1B,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC3B,OAAO,CAAC,EAAE,QAAQ,CAAC,WAAW,GAAG,SAAS,CAAC,CAAC;CAC/C;AAED,wBAAgB,8BAA8B,CAAC,EAC3C,OAAO,EACP,OAAO,EACP,QAAQ,EACR,OAAO,GACV,EAAE,8BAA8B,GAAG,QAAQ,CAAC,MAAM,CAAC,CAiBnD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { highlight, highlightDiff } from "tree-sitter-ts-highlight";
|
|
2
|
+
import { derived } from "svelte/store";
|
|
3
|
+
export function getHighlightedHtml({ code, language, options, }) {
|
|
4
|
+
return highlight(code, language, {
|
|
5
|
+
...options,
|
|
6
|
+
wrapInPre: false,
|
|
7
|
+
language,
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
export function getHighlightedDiffHtml({ oldCode, newCode, language, options, }) {
|
|
11
|
+
return highlightDiff(oldCode, newCode, language, options);
|
|
12
|
+
}
|
|
13
|
+
export function createHighlightedHtmlStore({ code, language, options, }) {
|
|
14
|
+
if (!options) {
|
|
15
|
+
return derived([code, language], ([$code, $language]) => getHighlightedHtml({ code: $code, language: $language }));
|
|
16
|
+
}
|
|
17
|
+
return derived([code, language, options], ([$code, $language, $options]) => getHighlightedHtml({ code: $code, language: $language, options: $options }));
|
|
18
|
+
}
|
|
19
|
+
export function createHighlightedDiffHtmlStore({ oldCode, newCode, language, options, }) {
|
|
20
|
+
if (!options) {
|
|
21
|
+
return derived([oldCode, newCode, language], ([$oldCode, $newCode, $language]) => getHighlightedDiffHtml({ oldCode: $oldCode, newCode: $newCode, language: $language }));
|
|
22
|
+
}
|
|
23
|
+
return derived([oldCode, newCode, language, options], ([$oldCode, $newCode, $language, $options]) => getHighlightedDiffHtml({
|
|
24
|
+
oldCode: $oldCode,
|
|
25
|
+
newCode: $newCode,
|
|
26
|
+
language: $language,
|
|
27
|
+
options: $options,
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { DiffChangeType, DiffOptions, HighlightOptions } from "tree-sitter-ts-highlight";
|
|
2
|
+
import { type Token } from "tree-sitter-ts";
|
|
3
|
+
export interface RenderToken {
|
|
4
|
+
value: string;
|
|
5
|
+
category: Token["category"];
|
|
6
|
+
className?: string;
|
|
7
|
+
style?: Record<string, string>;
|
|
8
|
+
dataAttrs?: Record<string, string>;
|
|
9
|
+
wrap: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface HighlightRenderableLine {
|
|
12
|
+
lineNumber: number;
|
|
13
|
+
tokens: RenderToken[];
|
|
14
|
+
}
|
|
15
|
+
export interface HighlightRenderable {
|
|
16
|
+
lineNumbers: boolean;
|
|
17
|
+
dataLineAttributes: boolean;
|
|
18
|
+
lines: HighlightRenderableLine[];
|
|
19
|
+
tokens: RenderToken[];
|
|
20
|
+
preStyle: Record<string, string>;
|
|
21
|
+
}
|
|
22
|
+
export interface DiffRenderableRow {
|
|
23
|
+
changeType: DiffChangeType;
|
|
24
|
+
oldLineNumber: number | null;
|
|
25
|
+
newLineNumber: number | null;
|
|
26
|
+
oldText: string;
|
|
27
|
+
newText: string;
|
|
28
|
+
oldTokens: RenderToken[];
|
|
29
|
+
newTokens: RenderToken[];
|
|
30
|
+
}
|
|
31
|
+
export interface DiffRenderable {
|
|
32
|
+
view: "side-by-side" | "inline";
|
|
33
|
+
showHeader: boolean;
|
|
34
|
+
oldLabel: string;
|
|
35
|
+
newLabel: string;
|
|
36
|
+
rows: DiffRenderableRow[];
|
|
37
|
+
classPrefix: string;
|
|
38
|
+
}
|
|
39
|
+
export declare function createHighlightRenderable(code: string, language: string, options?: Omit<HighlightOptions, "wrapInPre" | "language">): HighlightRenderable;
|
|
40
|
+
export declare function createDiffRenderable(oldCode: string, newCode: string, language: string, options?: DiffOptions): DiffRenderable;
|
|
41
|
+
export declare function cssTextToStyleObject(cssText: string): Record<string, string>;
|
|
42
|
+
export declare function styleObjectToCssText(style: Record<string, string>): string;
|
|
43
|
+
//# sourceMappingURL=svelte-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"svelte-renderer.d.ts","sourceRoot":"","sources":["../../src/lib/svelte-renderer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAER,cAAc,EACd,WAAW,EAEX,gBAAgB,EAEnB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAY,KAAK,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEtD,MAAM,WAAW,WAAW;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,IAAI,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,uBAAuB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,WAAW,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IAChC,WAAW,EAAE,OAAO,CAAC;IACrB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,KAAK,EAAE,uBAAuB,EAAE,CAAC;IACjC,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,iBAAiB;IAC9B,UAAU,EAAE,cAAc,CAAC;IAC3B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,WAAW,EAAE,CAAC;IACzB,SAAS,EAAE,WAAW,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC3B,IAAI,EAAE,cAAc,GAAG,QAAQ,CAAC;IAChC,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,iBAAiB,EAAE,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,yBAAyB,CACrC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,IAAI,CAAC,gBAAgB,EAAE,WAAW,GAAG,UAAU,CAAM,GAC/D,mBAAmB,CAsBrB;AAED,wBAAgB,oBAAoB,CAChC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,WAAgB,GAC1B,cAAc,CAgBhB;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAwB5E;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAI1E"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { applyDecorations, createDiffModelWithTokens, enhanceSemantics, groupTokensByLine } from "tree-sitter-ts-highlight";
|
|
2
|
+
import { tokenize } from "tree-sitter-ts";
|
|
3
|
+
export function createHighlightRenderable(code, language, options = {}) {
|
|
4
|
+
const rawTokens = tokenize(code, language);
|
|
5
|
+
const tokens = options.semanticHighlighting ? enhanceSemantics(rawTokens) : rawTokens;
|
|
6
|
+
const classPrefix = options.classPrefix ?? "hlts-";
|
|
7
|
+
const groups = groupTokensByLine(tokens);
|
|
8
|
+
const startLine = options.startLine ?? 1;
|
|
9
|
+
const lines = groups.map((group) => ({
|
|
10
|
+
lineNumber: group.lineNumber - groups[0].lineNumber + startLine,
|
|
11
|
+
tokens: toRenderTokens(group.tokens, classPrefix, options.theme, options.decorations),
|
|
12
|
+
}));
|
|
13
|
+
return {
|
|
14
|
+
lineNumbers: options.lineNumbers ?? false,
|
|
15
|
+
dataLineAttributes: options.dataLineAttributes ?? true,
|
|
16
|
+
lines,
|
|
17
|
+
tokens: toRenderTokens(tokens, classPrefix, options.theme, options.decorations),
|
|
18
|
+
preStyle: {
|
|
19
|
+
...(options.theme?.background ? { background: options.theme.background } : {}),
|
|
20
|
+
...(options.theme?.foreground ? { color: options.theme.foreground } : {}),
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function createDiffRenderable(oldCode, newCode, language, options = {}) {
|
|
25
|
+
const diff = createDiffModelWithTokens(oldCode, newCode, language, options);
|
|
26
|
+
const classPrefix = options.classPrefix ?? "hlts-";
|
|
27
|
+
const rows = diff.model.rows.map((row) => toDiffRow(row, diff.oldLineTokens, diff.newLineTokens, classPrefix, options.theme, options.decorations));
|
|
28
|
+
return {
|
|
29
|
+
view: options.view ?? "side-by-side",
|
|
30
|
+
showHeader: options.showHeader ?? true,
|
|
31
|
+
oldLabel: diff.model.oldLabel,
|
|
32
|
+
newLabel: diff.model.newLabel,
|
|
33
|
+
rows,
|
|
34
|
+
classPrefix,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function cssTextToStyleObject(cssText) {
|
|
38
|
+
const style = {};
|
|
39
|
+
for (const declaration of cssText.split(";")) {
|
|
40
|
+
const trimmed = declaration.trim();
|
|
41
|
+
if (!trimmed) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const separatorIndex = trimmed.indexOf(":");
|
|
45
|
+
if (separatorIndex === -1) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const property = trimmed.slice(0, separatorIndex).trim();
|
|
49
|
+
const value = trimmed.slice(separatorIndex + 1).trim();
|
|
50
|
+
if (!property || !value) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
style[property] = value;
|
|
54
|
+
}
|
|
55
|
+
return style;
|
|
56
|
+
}
|
|
57
|
+
export function styleObjectToCssText(style) {
|
|
58
|
+
return Object.entries(style)
|
|
59
|
+
.map(([key, value]) => `${key}: ${value}`)
|
|
60
|
+
.join("; ");
|
|
61
|
+
}
|
|
62
|
+
function toRenderTokens(tokens, classPrefix, theme, decorations) {
|
|
63
|
+
const decorated = decorations && decorations.length > 0
|
|
64
|
+
? applyDecorations(tokens, decorations)
|
|
65
|
+
: tokens.map((token) => ({
|
|
66
|
+
token,
|
|
67
|
+
extraClasses: [],
|
|
68
|
+
extraAttrs: {},
|
|
69
|
+
extraStyle: undefined,
|
|
70
|
+
}));
|
|
71
|
+
return decorated.map(({ token, extraClasses, extraAttrs, extraStyle }) => {
|
|
72
|
+
const wrap = token.category !== "whitespace" && token.category !== "newline";
|
|
73
|
+
if (theme) {
|
|
74
|
+
const baseStyle = theme.styles[token.category] ?? "";
|
|
75
|
+
const style = cssTextToStyleObject([baseStyle, extraStyle].filter(Boolean).join(";"));
|
|
76
|
+
return {
|
|
77
|
+
value: token.value,
|
|
78
|
+
category: token.category,
|
|
79
|
+
style,
|
|
80
|
+
dataAttrs: extraAttrs,
|
|
81
|
+
wrap,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
value: token.value,
|
|
86
|
+
category: token.category,
|
|
87
|
+
className: [classPrefix + token.category, ...extraClasses].join(" "),
|
|
88
|
+
dataAttrs: extraAttrs,
|
|
89
|
+
wrap,
|
|
90
|
+
};
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
function toDiffRow(row, oldTokenMap, newTokenMap, classPrefix, theme, decorations) {
|
|
94
|
+
const oldTokens = row.oldLineNumber === null
|
|
95
|
+
? []
|
|
96
|
+
: toRenderTokens(oldTokenMap.get(row.oldLineNumber) ?? [], classPrefix, theme, decorations);
|
|
97
|
+
const newTokens = row.newLineNumber === null
|
|
98
|
+
? []
|
|
99
|
+
: toRenderTokens(newTokenMap.get(row.newLineNumber) ?? [], classPrefix, theme, decorations);
|
|
100
|
+
return {
|
|
101
|
+
changeType: row.changeType,
|
|
102
|
+
oldLineNumber: row.oldLineNumber,
|
|
103
|
+
newLineNumber: row.newLineNumber,
|
|
104
|
+
oldText: row.oldText,
|
|
105
|
+
newText: row.newText,
|
|
106
|
+
oldTokens,
|
|
107
|
+
newTokens,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"highlight.test.d.ts","sourceRoot":"","sources":["../../src/test/highlight.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { get, writable } from "svelte/store";
|
|
2
|
+
import { createHighlightedDiffHtmlStore, createHighlightedHtmlStore, getHighlightedDiffHtml, getHighlightedHtml, } from "../lib/highlight";
|
|
3
|
+
const highlightMock = jest.fn();
|
|
4
|
+
const highlightDiffMock = jest.fn();
|
|
5
|
+
jest.mock("tree-sitter-ts-highlight", () => ({
|
|
6
|
+
highlight: (...args) => highlightMock(...args),
|
|
7
|
+
highlightDiff: (...args) => highlightDiffMock(...args),
|
|
8
|
+
}));
|
|
9
|
+
describe("highlight utilities", () => {
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
highlightMock.mockReset();
|
|
12
|
+
highlightDiffMock.mockReset();
|
|
13
|
+
});
|
|
14
|
+
test("getHighlightedHtml forwards args and enforces wrapInPre=false", () => {
|
|
15
|
+
highlightMock.mockReturnValue("<span>ok</span>");
|
|
16
|
+
const html = getHighlightedHtml({
|
|
17
|
+
code: "const n = 1;",
|
|
18
|
+
language: "typescript",
|
|
19
|
+
options: { lineNumbers: true },
|
|
20
|
+
});
|
|
21
|
+
expect(html).toBe("<span>ok</span>");
|
|
22
|
+
expect(highlightMock).toHaveBeenCalledWith("const n = 1;", "typescript", {
|
|
23
|
+
lineNumbers: true,
|
|
24
|
+
wrapInPre: false,
|
|
25
|
+
language: "typescript",
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
test("getHighlightedDiffHtml forwards args", () => {
|
|
29
|
+
highlightDiffMock.mockReturnValue("<div>diff</div>");
|
|
30
|
+
const html = getHighlightedDiffHtml({
|
|
31
|
+
oldCode: "a",
|
|
32
|
+
newCode: "b",
|
|
33
|
+
language: "typescript",
|
|
34
|
+
options: { view: "inline" },
|
|
35
|
+
});
|
|
36
|
+
expect(html).toBe("<div>diff</div>");
|
|
37
|
+
expect(highlightDiffMock).toHaveBeenCalledWith("a", "b", "typescript", { view: "inline" });
|
|
38
|
+
});
|
|
39
|
+
test("createHighlightedHtmlStore reacts to code/language changes", () => {
|
|
40
|
+
highlightMock.mockImplementation((code, language) => `${language}:${code}`);
|
|
41
|
+
const code = writable("const n = 1;");
|
|
42
|
+
const language = writable("typescript");
|
|
43
|
+
const store = createHighlightedHtmlStore({ code, language });
|
|
44
|
+
expect(get(store)).toBe("typescript:const n = 1;");
|
|
45
|
+
code.set("const n = 2;");
|
|
46
|
+
expect(get(store)).toBe("typescript:const n = 2;");
|
|
47
|
+
language.set("javascript");
|
|
48
|
+
expect(get(store)).toBe("javascript:const n = 2;");
|
|
49
|
+
});
|
|
50
|
+
test("createHighlightedDiffHtmlStore reacts with optional options store", () => {
|
|
51
|
+
highlightDiffMock.mockImplementation((oldCode, newCode, language, options) => `${language}:${oldCode}->${newCode}:${options?.view ?? "side-by-side"}`);
|
|
52
|
+
const oldCode = writable("a");
|
|
53
|
+
const newCode = writable("b");
|
|
54
|
+
const language = writable("typescript");
|
|
55
|
+
const options = writable({ view: "inline" });
|
|
56
|
+
const store = createHighlightedDiffHtmlStore({ oldCode, newCode, language, options });
|
|
57
|
+
expect(get(store)).toBe("typescript:a->b:inline");
|
|
58
|
+
newCode.set("c");
|
|
59
|
+
expect(get(store)).toBe("typescript:a->c:inline");
|
|
60
|
+
options.set(undefined);
|
|
61
|
+
expect(get(store)).toBe("typescript:a->c:side-by-side");
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"svelte-renderer.test.d.ts","sourceRoot":"","sources":["../../src/test/svelte-renderer.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { createDiffRenderable, createHighlightRenderable, cssTextToStyleObject, styleObjectToCssText, } from "../lib/svelte-renderer";
|
|
2
|
+
const tokenizeMock = jest.fn();
|
|
3
|
+
const enhanceSemanticsMock = jest.fn();
|
|
4
|
+
const groupTokensByLineMock = jest.fn();
|
|
5
|
+
const applyDecorationsMock = jest.fn();
|
|
6
|
+
const createDiffModelWithTokensMock = jest.fn();
|
|
7
|
+
jest.mock("tree-sitter-ts", () => ({
|
|
8
|
+
tokenize: (...args) => tokenizeMock(...args),
|
|
9
|
+
}));
|
|
10
|
+
jest.mock("tree-sitter-ts-highlight", () => ({
|
|
11
|
+
applyDecorations: (...args) => applyDecorationsMock(...args),
|
|
12
|
+
enhanceSemantics: (...args) => enhanceSemanticsMock(...args),
|
|
13
|
+
groupTokensByLine: (...args) => groupTokensByLineMock(...args),
|
|
14
|
+
createDiffModelWithTokens: (...args) => createDiffModelWithTokensMock(...args),
|
|
15
|
+
}));
|
|
16
|
+
describe("svelte renderer utilities", () => {
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
tokenizeMock.mockReset();
|
|
19
|
+
enhanceSemanticsMock.mockReset();
|
|
20
|
+
groupTokensByLineMock.mockReset();
|
|
21
|
+
applyDecorationsMock.mockReset();
|
|
22
|
+
createDiffModelWithTokensMock.mockReset();
|
|
23
|
+
});
|
|
24
|
+
test("cssTextToStyleObject parses valid declarations", () => {
|
|
25
|
+
expect(cssTextToStyleObject("color: red; background: #000; invalid; :missing; opacity: 0.8"))
|
|
26
|
+
.toEqual({ color: "red", background: "#000", opacity: "0.8" });
|
|
27
|
+
});
|
|
28
|
+
test("styleObjectToCssText serializes style object", () => {
|
|
29
|
+
expect(styleObjectToCssText({ color: "red", background: "#000" })).toBe("color: red; background: #000");
|
|
30
|
+
});
|
|
31
|
+
test("createHighlightRenderable supports semantic highlighting and themes", () => {
|
|
32
|
+
const rawTokens = [
|
|
33
|
+
{ value: "const", category: "keyword" },
|
|
34
|
+
{ value: " ", category: "whitespace" },
|
|
35
|
+
];
|
|
36
|
+
const semanticTokens = [{ value: "const", category: "keyword" }];
|
|
37
|
+
tokenizeMock.mockReturnValue(rawTokens);
|
|
38
|
+
enhanceSemanticsMock.mockReturnValue(semanticTokens);
|
|
39
|
+
groupTokensByLineMock.mockReturnValue([
|
|
40
|
+
{ lineNumber: 3, tokens: semanticTokens },
|
|
41
|
+
{ lineNumber: 4, tokens: semanticTokens },
|
|
42
|
+
]);
|
|
43
|
+
applyDecorationsMock.mockImplementation((tokens) => tokens.map((token) => ({
|
|
44
|
+
token,
|
|
45
|
+
extraClasses: ["extra"],
|
|
46
|
+
extraAttrs: { "data-test": "1" },
|
|
47
|
+
extraStyle: "font-weight: 700",
|
|
48
|
+
})));
|
|
49
|
+
const renderable = createHighlightRenderable("const a = 1;", "typescript", {
|
|
50
|
+
semanticHighlighting: true,
|
|
51
|
+
startLine: 10,
|
|
52
|
+
decorations: [{ line: 1 }],
|
|
53
|
+
theme: {
|
|
54
|
+
name: "test-theme",
|
|
55
|
+
background: "#111",
|
|
56
|
+
foreground: "#eee",
|
|
57
|
+
styles: { keyword: "color: #f00" },
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
expect(tokenizeMock).toHaveBeenCalledWith("const a = 1;", "typescript");
|
|
61
|
+
expect(enhanceSemanticsMock).toHaveBeenCalledWith(rawTokens);
|
|
62
|
+
expect(renderable.lines[0].lineNumber).toBe(10);
|
|
63
|
+
expect(renderable.lines[1].lineNumber).toBe(11);
|
|
64
|
+
expect(renderable.tokens[0].style).toEqual({ color: "#f00", "font-weight": "700" });
|
|
65
|
+
expect(renderable.tokens[0].dataAttrs).toEqual({ "data-test": "1" });
|
|
66
|
+
expect(renderable.preStyle).toEqual({ background: "#111", color: "#eee" });
|
|
67
|
+
});
|
|
68
|
+
test("createDiffRenderable builds rows and applies defaults", () => {
|
|
69
|
+
createDiffModelWithTokensMock.mockReturnValue({
|
|
70
|
+
model: {
|
|
71
|
+
oldLabel: "Old",
|
|
72
|
+
newLabel: "New",
|
|
73
|
+
rows: [
|
|
74
|
+
{
|
|
75
|
+
changeType: "modified",
|
|
76
|
+
oldLineNumber: 1,
|
|
77
|
+
newLineNumber: 2,
|
|
78
|
+
oldText: "a",
|
|
79
|
+
newText: "b",
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
oldLineTokens: new Map([[1, [{ value: "a", category: "identifier" }]]]),
|
|
84
|
+
newLineTokens: new Map([[2, [{ value: "b", category: "identifier" }]]]),
|
|
85
|
+
});
|
|
86
|
+
const diff = createDiffRenderable("a", "b", "typescript", {});
|
|
87
|
+
expect(createDiffModelWithTokensMock).toHaveBeenCalledWith("a", "b", "typescript", {});
|
|
88
|
+
expect(diff.view).toBe("side-by-side");
|
|
89
|
+
expect(diff.showHeader).toBe(true);
|
|
90
|
+
expect(diff.classPrefix).toBe("hlts-");
|
|
91
|
+
expect(diff.rows).toHaveLength(1);
|
|
92
|
+
expect(diff.rows[0].oldTokens[0].className).toBe("hlts-identifier");
|
|
93
|
+
});
|
|
94
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tree-sitter-ts-highlight-svelte",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Native Svelte wrapper components for tree-sitter-ts-highlight.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"svelte": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"svelte": "./dist/index.js",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "svelte-package --input src --output dist",
|
|
22
|
+
"prepack": "npm run build",
|
|
23
|
+
"typecheck": "svelte-check --tsconfig ./tsconfig.json",
|
|
24
|
+
"test": "jest",
|
|
25
|
+
"test:watch": "jest --watch"
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"svelte": "^5.0.0",
|
|
29
|
+
"tree-sitter-ts": "^0.1.2",
|
|
30
|
+
"tree-sitter-ts-highlight": "^0.1.2"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@sveltejs/package": "^2.3.7",
|
|
34
|
+
"@swc/core": "^1.15.11",
|
|
35
|
+
"@swc/jest": "^0.2.39",
|
|
36
|
+
"@types/jest": "^30.0.0",
|
|
37
|
+
"jest": "^30.2.0",
|
|
38
|
+
"svelte": "^5.38.10",
|
|
39
|
+
"svelte-check": "^4.3.1",
|
|
40
|
+
"typescript": "^5.4.0"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public",
|
|
44
|
+
"provenance": false
|
|
45
|
+
},
|
|
46
|
+
"keywords": [
|
|
47
|
+
"svelte",
|
|
48
|
+
"tree-sitter",
|
|
49
|
+
"syntax-highlighting",
|
|
50
|
+
"typescript",
|
|
51
|
+
"code-highlighting"
|
|
52
|
+
],
|
|
53
|
+
"repository": {
|
|
54
|
+
"type": "git",
|
|
55
|
+
"url": "https://github.com/hieutran512/tree-sitter-ts-highlight-svelte"
|
|
56
|
+
},
|
|
57
|
+
"license": "MIT",
|
|
58
|
+
"engines": {
|
|
59
|
+
"node": ">=18.0.0"
|
|
60
|
+
}
|
|
61
|
+
}
|