Skip to content

feat: support langalias #68

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ jobs:

- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10.4.0

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
Expand Down
8 changes: 1 addition & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,5 @@
"changesets-changelog-clean": "^1.3.0",
"typescript": "^5.8.2"
},
"packageManager": "pnpm@10.4.0",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got some errors trying to install this version with checksums so updated it

"pnpm": {
"onlyBuiltDependencies": [
"@biomejs/biome",
"esbuild"
]
}
Comment on lines -28 to -33
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these options can now live in pnpm-workspace in case you're wondering where they went 😅

"packageManager": "pnpm@10.12.1"
}
5 changes: 1 addition & 4 deletions package/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,7 @@
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"dist",
"src/lib/styles.css"
],
"files": ["dist", "src/lib/styles.css"],
"exports": {
".": {
"types": "./dist/index.d.ts",
Expand Down
25 changes: 25 additions & 0 deletions package/src/__tests__/hook.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,19 @@ interface TestComponentProps {
theme: Theme;
transformers?: ShikiTransformer[];
tabindex?: string;
langAlias?: Record<string, string>;
}

const TestComponent = ({
code,
language,
theme,
transformers,
langAlias,
}: TestComponentProps) => {
const highlighted = useShikiHighlighter(code, language, theme, {
transformers,
langAlias,
});
return <div data-testid="highlighted">{highlighted}</div>;
};
Expand Down Expand Up @@ -132,4 +135,26 @@ describe('useShikiHighlighter Hook', () => {
expect(container).toMatchSnapshot();
});
});

test('applies highlighting on aliased language', async () => {
const code = 'package main';
const { getByTestId } = renderComponent({
code,
language: 'golang',
langAlias: {
golang: 'go',
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn’t go recognized as an alias for golang by default?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually it looks like go is the primary identifier for golang in shiki - https://shiki.style/languages. Does golang work as an identifier for go? I don't think it would judging by go.json in shiki-textmate-themes-grammars repo, but can't test at the moment

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our usecase for this was that LLMs sometimes output \``golang` headers for codeblocks and those weren't getting formatted. The alias here just makes it so golang gets passed to the go language spec

},
});

await waitFor(() => {
const container = getByTestId('highlighted');
const preElement = container.querySelector('pre');
const spanElement = preElement?.querySelector(
'code>span>span'
) as HTMLSpanElement | null;

expect(spanElement).toBeInTheDocument();
expect(spanElement).toHaveStyle('color: #D73A49');
});
});
});
9 changes: 7 additions & 2 deletions package/src/lib/hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,13 @@ export const useShikiHighlighter = (
const [stableOpts, optsRev] = useStableOptions(options);

const { languageId, langsToLoad } = useMemo(
() => resolveLanguage(stableLang, stableOpts.customLanguages),
[stableLang, stableOpts.customLanguages]
() =>
resolveLanguage(
stableLang,
stableOpts.customLanguages as never,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why cast as never?

stableOpts.langAlias
),
[stableLang, stableOpts.customLanguages, stableOpts.langAlias]
);

const { isMultiTheme, themeId, multiTheme, singleTheme, themesToLoad } =
Expand Down
17 changes: 15 additions & 2 deletions package/src/lib/resolvers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import type { Language, Theme, Themes } from './types';
import type { ThemeRegistrationAny } from 'shiki/core';
import type {
BundledHighlighterOptions,
ThemeRegistrationAny,
} from 'shiki/core';
import type { LanguageRegistration } from './extended-types';

/**
Expand All @@ -22,7 +25,8 @@ type LanguageResult = {
*/
export const resolveLanguage = (
lang: Language,
customLanguages?: LanguageRegistration | LanguageRegistration[]
customLanguages?: LanguageRegistration | LanguageRegistration[],
langAliases?: Record<string, string>
): LanguageResult => {
const normalizedCustomLangs = customLanguages
? Array.isArray(customLanguages)
Expand Down Expand Up @@ -71,6 +75,15 @@ export const resolveLanguage = (
};
}

// Check if language is aliased
if (langAliases && langAliases[lang]) {
return {
languageId: langAliases[lang],
displayLanguageId: lang,
langsToLoad: langAliases[lang],
};
}

// For any other string, pass it through,
// fallback is handled in highlighter factories
return {
Expand Down
4 changes: 3 additions & 1 deletion package/src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
CodeToHastOptions,
Highlighter,
HighlighterCore,
BundledHighlighterOptions,
} from 'shiki';

import type { ReactNode } from 'react';
Expand Down Expand Up @@ -123,7 +124,8 @@ interface HighlighterOptions
CodeOptionsMultipleThemes<BundledTheme>,
'defaultColor' | 'cssVariablePrefix'
>,
Omit<CodeToHastOptions, 'lang' | 'theme' | 'themes'> {}
Omit<CodeToHastOptions, 'lang' | 'theme' | 'themes'>,
Pick<BundledHighlighterOptions<string, string>, 'langAlias'> {}

/**
* State for the throttling logic
Expand Down
5 changes: 4 additions & 1 deletion pnpm-workspace.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
packages:
- package
- playground
- playground
onlyBuiltDependencies:
- "@biomejs/biome"
- esbuild