Skip to content
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: 1 addition & 1 deletion packages/cli/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export async function run(

const codes = await Promise.all(files.map(async (path) => {
const { content, ext } = await readSource(path)
const lang = (options.lang || ext).toLowerCase()
const lang = (options.lang || ext || 'text').toLowerCase()
if (options.format === 'html') {
const { codeToHtml } = await import('shiki')
return await codeToHtml(content, {
Expand Down
27 changes: 27 additions & 0 deletions packages/cli/test/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,4 +174,31 @@ describe('run', () => {
expect(output).toContain('javascript')
expect(output).toContain('python')
})
it('local file without extension falls back to plaintext', async () => {
const noExtFile = path.join(testDir, 'Makefile')
await fs.writeFile(noExtFile, 'all:\n\techo Hello')

const output: string[] = []
// should not throw; without the fix, lang='' caused shiki to error
await run(['node', 'shiki', noExtFile], msg => output.push(msg))

expect(output.length).toBe(1)
expect(output[0]).toContain('all')
})

it('remote URL without file extension falls back to plaintext', async () => {
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
ok: true,
text: () => Promise.resolve('FROM node:18'),
}))

const output: string[] = []
// URL has no extension → ext='', lang must fall back to 'text'
await run(['node', 'shiki', 'https://raw.githubusercontent.com/user/repo/main/Dockerfile'], msg => output.push(msg))

expect(output.length).toBe(1)
expect(output[0]).toContain('FROM')

vi.unstubAllGlobals()
})
})