Skip to content

Commit 7ff687c

Browse files
feat: support langAlias option (#68)
support `langAlias` option also updates and improves tests --------- Co-authored-by: Bassim Shahidy <122117267+AVGVSTVS96@users.noreply.github.com>
1 parent 08e5833 commit 7ff687c

File tree

15 files changed

+207
-463
lines changed

15 files changed

+207
-463
lines changed

.changeset/yellow-fishes-march.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"react-shiki": patch
3+
---
4+
5+
feat: support langAlias option

.github/workflows/build.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ jobs:
1414

1515
- name: Install pnpm
1616
uses: pnpm/action-setup@v4
17-
with:
18-
version: 10.4.0
1917

2018
- name: Setup Node.js ${{ matrix.node-version }}
2119
uses: actions/setup-node@v4

package.json

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,5 @@
2424
"changesets-changelog-clean": "^1.3.0",
2525
"typescript": "^5.8.2"
2626
},
27-
"packageManager": "pnpm@10.4.0",
28-
"pnpm": {
29-
"onlyBuiltDependencies": [
30-
"@biomejs/biome",
31-
"esbuild"
32-
]
33-
}
27+
"packageManager": "pnpm@10.12.1"
3428
}

package/README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ See [Shiki - RegExp Engines](https://shiki.style/guide/regex-engines) for more i
157157
| `theme` | `string \| object` | `'github-dark'` | Single or multi-theme configuration, built-in or custom textmate theme object |
158158
| `delay` | `number` | `0` | Delay between highlights (in milliseconds) |
159159
| `customLanguages` | `array` | `[]` | Array of custom languages to preload |
160+
| `langAlias` | `object` | `{}` | Map of language aliases |
160161
| `showLineNumbers` | `boolean` | `false` | Display line numbers alongside code |
161162
| `startingLineNumber` | `number` | `1` | Starting line number when line numbers are enabled |
162163
| `transformers` | `array` | `[]` | Custom Shiki transformers for modifying the highlighting output |
@@ -273,6 +274,26 @@ const highlightedCode = useShikiHighlighter(code, "typescript", "github-dark", {
273274
});
274275
```
275276

277+
### Language Aliases
278+
279+
You can define custom aliases for languages using the `langAlias` option. This is useful when you want to use alternative names for languages:
280+
281+
```tsx
282+
// Component
283+
<ShikiHighlighter
284+
language="indents"
285+
theme="github-dark"
286+
langAlias={{ indents: "python" }}
287+
>
288+
{code.trim()}
289+
</ShikiHighlighter>
290+
291+
// Hook
292+
const highlightedCode = useShikiHighlighter(code, "indents", "github-dark", {
293+
langAlias: { indents: "python" },
294+
});
295+
```
296+
276297
### Custom Transformers
277298

278299
```tsx

package/package.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,7 @@
2626
"type": "module",
2727
"main": "./dist/index.js",
2828
"types": "./dist/index.d.ts",
29-
"files": [
30-
"dist",
31-
"src/lib/styles.css"
32-
],
29+
"files": ["dist", "src/lib/styles.css"],
3330
"exports": {
3431
".": {
3532
"types": "./dist/index.d.ts",

package/src/__tests__/__snapshots__/component.test.tsx.snap

Lines changed: 0 additions & 16 deletions
This file was deleted.

package/src/__tests__/__snapshots__/hook.test.tsx.snap

Lines changed: 0 additions & 7 deletions
This file was deleted.

package/src/__tests__/component.test.tsx

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -102,28 +102,6 @@ describe('ShikiHighlighter Component', () => {
102102
});
103103
});
104104

105-
test('matches snapshot for complex language input', async () => {
106-
const complexCode = `
107-
function greet(name) {
108-
console.log('Hello, ' + name);
109-
}
110-
greet('World');
111-
`.trim();
112-
113-
const { container } = render(
114-
<ShikiHighlighter language="javascript" theme="github-light">
115-
{complexCode}
116-
</ShikiHighlighter>
117-
);
118-
119-
await waitFor(() => {
120-
const outerContainer = container.querySelector(
121-
'[data-testid="shiki-container"]'
122-
);
123-
expect(outerContainer).toMatchSnapshot();
124-
});
125-
});
126-
127105
test('applies custom transformers and custom styling props', async () => {
128106
const customCode = 'console.log("Custom transformer test");';
129107
// Transformer that adds a custom attribute to the <pre> tag.

package/src/__tests__/hook.test.tsx

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,19 @@ interface TestComponentProps {
1010
theme: Theme;
1111
transformers?: ShikiTransformer[];
1212
tabindex?: string;
13+
langAlias?: Record<string, string>;
1314
}
1415

1516
const TestComponent = ({
1617
code,
1718
language,
1819
theme,
1920
transformers,
21+
langAlias,
2022
}: TestComponentProps) => {
2123
const highlighted = useShikiHighlighter(code, language, theme, {
2224
transformers,
25+
langAlias,
2326
});
2427
return <div data-testid="highlighted">{highlighted}</div>;
2528
};
@@ -36,37 +39,22 @@ describe('useShikiHighlighter Hook', () => {
3639
return render(<TestComponent {...defaultProps} />);
3740
};
3841

39-
test('renders pre element with correct theme classes', async () => {
42+
test('renders correct DOM structure', async () => {
4043
const { getByTestId } = renderComponent();
4144
await waitFor(() => {
4245
const container = getByTestId('highlighted');
46+
47+
// Check pre element with theme classes
4348
const preElement = container.querySelector(
4449
'pre.shiki.github-light'
4550
);
4651
expect(preElement).toBeInTheDocument();
47-
});
48-
});
4952

50-
test('renders code element inside pre element', async () => {
51-
const { getByTestId } = renderComponent();
52-
await waitFor(() => {
53-
const container = getByTestId('highlighted');
54-
const preElement = container.querySelector(
55-
'pre.shiki.github-light'
56-
);
53+
// Check code element inside pre
5754
const codeElement = preElement?.querySelector('code');
5855
expect(codeElement).toBeInTheDocument();
59-
});
60-
});
6156

62-
test('renders line spans inside code element', async () => {
63-
const { getByTestId } = renderComponent();
64-
await waitFor(() => {
65-
const container = getByTestId('highlighted');
66-
const preElement = container.querySelector(
67-
'pre.shiki.github-light'
68-
);
69-
const codeElement = preElement?.querySelector('code');
57+
// Check line spans inside code
7058
const lineSpan = codeElement?.querySelector('span.line');
7159
expect(lineSpan).toBeInTheDocument();
7260
});
@@ -124,12 +112,47 @@ describe('useShikiHighlighter Hook', () => {
124112
});
125113
});
126114

127-
test('matches snapshot for hook rendered output for known language', async () => {
128-
const code = '<div>Hello World</div>';
129-
const { getByTestId } = renderComponent({ code });
115+
test('applies highlighting on aliased language', async () => {
116+
const code = 'package main';
117+
const { getByTestId } = renderComponent({
118+
code,
119+
language: 'golang',
120+
langAlias: {
121+
golang: 'go',
122+
},
123+
});
124+
125+
await waitFor(() => {
126+
const container = getByTestId('highlighted');
127+
const preElement = container.querySelector('pre');
128+
const spanElement = preElement?.querySelector(
129+
'code>span>span'
130+
) as HTMLSpanElement | null;
131+
132+
expect(spanElement).toBeInTheDocument();
133+
expect(spanElement).toHaveStyle('color: #D73A49');
134+
});
135+
});
136+
137+
test('handles multiple language aliases', async () => {
138+
const code = 'def hello():\n print("world")';
139+
const { getByTestId } = renderComponent({
140+
code,
141+
language: 'indents',
142+
langAlias: {
143+
indents: 'python',
144+
},
145+
});
146+
130147
await waitFor(() => {
131148
const container = getByTestId('highlighted');
132-
expect(container).toMatchSnapshot();
149+
const preElement = container.querySelector('pre');
150+
const defKeyword = Array.from(
151+
preElement?.querySelectorAll('span') || []
152+
).find((span) => span.textContent === 'def');
153+
154+
expect(defKeyword).toBeInTheDocument();
155+
expect(defKeyword).toHaveStyle('color: #D73A49');
133156
});
134157
});
135158
});
Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, expect, it } from 'vitest';
2-
import { render } from '@testing-library/react';
2+
import { render, waitFor } from '@testing-library/react';
33
import { ShikiHighlighter } from '../index';
44

55
describe('Line Numbers', () => {
@@ -14,14 +14,14 @@ describe('Line Numbers', () => {
1414
</ShikiHighlighter>
1515
);
1616

17-
// Wait for highlighting to complete
18-
await new Promise((resolve) => setTimeout(resolve, 100));
17+
await waitFor(() => {
18+
const containerElement =
19+
container.querySelector('#shiki-container');
20+
expect(containerElement).not.toHaveClass('has-line-numbers');
1921

20-
const container_element = container.querySelector('#shiki-container');
21-
expect(container_element).not.toHaveClass('has-line-numbers');
22-
23-
const lineElements = container.querySelectorAll('.line-numbers');
24-
expect(lineElements).toHaveLength(0);
22+
const lineElements = container.querySelectorAll('.line-numbers');
23+
expect(lineElements).toHaveLength(0);
24+
});
2525
});
2626

2727
it('should show line numbers when enabled', async () => {
@@ -35,14 +35,13 @@ describe('Line Numbers', () => {
3535
</ShikiHighlighter>
3636
);
3737

38-
// Wait for highlighting to complete
39-
await new Promise((resolve) => setTimeout(resolve, 100));
40-
41-
const codeElement = container.querySelector('code');
42-
expect(codeElement).toHaveClass('has-line-numbers');
38+
await waitFor(() => {
39+
const codeElement = container.querySelector('code');
40+
expect(codeElement).toHaveClass('has-line-numbers');
4341

44-
const lineElements = container.querySelectorAll('.line-numbers');
45-
expect(lineElements.length).toBeGreaterThan(0);
42+
const lineElements = container.querySelectorAll('.line-numbers');
43+
expect(lineElements.length).toBeGreaterThan(0);
44+
});
4645
});
4746

4847
it('should set custom starting line number', async () => {
@@ -57,17 +56,16 @@ describe('Line Numbers', () => {
5756
</ShikiHighlighter>
5857
);
5958

60-
// Wait for highlighting to complete
61-
await new Promise((resolve) => setTimeout(resolve, 100));
62-
63-
// Check which elements have the style attribute
64-
const elementsWithStyle = container.querySelectorAll(
65-
'[style*="--line-start"]'
66-
);
67-
expect(elementsWithStyle.length).toBeGreaterThan(0);
68-
expect(elementsWithStyle[0]?.getAttribute('style')).toContain(
69-
'--line-start: 42'
70-
);
59+
await waitFor(() => {
60+
// Check which elements have the style attribute
61+
const elementsWithStyle = container.querySelectorAll(
62+
'[style*="--line-start"]'
63+
);
64+
expect(elementsWithStyle.length).toBeGreaterThan(0);
65+
expect(elementsWithStyle[0]?.getAttribute('style')).toContain(
66+
'--line-start: 42'
67+
);
68+
});
7169
});
7270

7371
it('should not set line-start CSS variable when starting from 1', async () => {
@@ -82,12 +80,11 @@ describe('Line Numbers', () => {
8280
</ShikiHighlighter>
8381
);
8482

85-
// Wait for highlighting to complete
86-
await new Promise((resolve) => setTimeout(resolve, 100));
87-
88-
const elementsWithStyle = container.querySelectorAll(
89-
'[style*="--line-start"]'
90-
);
91-
expect(elementsWithStyle.length).toBe(0);
83+
await waitFor(() => {
84+
const elementsWithStyle = container.querySelectorAll(
85+
'[style*="--line-start"]'
86+
);
87+
expect(elementsWithStyle.length).toBe(0);
88+
});
9289
});
9390
});

0 commit comments

Comments
 (0)