Skip to content

Commit e99aaad

Browse files
authoredSep 16, 2023
fix(build): handle importing code snippets not having an extension (#2978)
1 parent f409e20 commit e99aaad

File tree

2 files changed

+74
-21
lines changed

2 files changed

+74
-21
lines changed
 

‎__tests__/unit/node/markdown/plugins/snippet.test.ts

+43-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,40 @@
1-
import { dedent } from 'node/markdown/plugins/snippet'
1+
import { dedent, rawPathToToken } from 'node/markdown/plugins/snippet'
2+
3+
const removeEmptyKeys = <T extends Record<string, unknown>>(obj: T) => {
4+
return Object.fromEntries(
5+
Object.entries(obj).filter(([, value]) => value !== '')
6+
) as T
7+
}
8+
9+
/* prettier-ignore */
10+
const rawPathTokenMap: [string, Partial<{ filepath: string, extension: string, title: string, region: string, lines: string, lang: string }>][] = [
11+
['/path/to/file.extension', { filepath: '/path/to/file.extension', extension: 'extension', title: 'file.extension' }],
12+
['./path/to/file.extension', { filepath: './path/to/file.extension', extension: 'extension', title: 'file.extension' }],
13+
['/path to/file.extension', { filepath: '/path to/file.extension', extension: 'extension', title: 'file.extension' }],
14+
['./path to/file.extension', { filepath: './path to/file.extension', extension: 'extension', title: 'file.extension' }],
15+
['/path.to/file.extension', { filepath: '/path.to/file.extension', extension: 'extension', title: 'file.extension' }],
16+
['./path.to/file.extension', { filepath: './path.to/file.extension', extension: 'extension', title: 'file.extension' }],
17+
['/path .to/file.extension', { filepath: '/path .to/file.extension', extension: 'extension', title: 'file.extension' }],
18+
['./path .to/file.extension', { filepath: './path .to/file.extension', extension: 'extension', title: 'file.extension' }],
19+
['/path/to/file', { filepath: '/path/to/file', title: 'file' }],
20+
['./path/to/file', { filepath: './path/to/file', title: 'file' }],
21+
['/path to/file', { filepath: '/path to/file', title: 'file' }],
22+
['./path to/file', { filepath: './path to/file', title: 'file' }],
23+
['/path.to/file', { filepath: '/path.to/file', title: 'file' }],
24+
['./path.to/file', { filepath: './path.to/file', title: 'file' }],
25+
['/path .to/file', { filepath: '/path .to/file', title: 'file' }],
26+
['./path .to/file', { filepath: './path .to/file', title: 'file' }],
27+
['/path/to/file.extension#region', { filepath: '/path/to/file.extension', extension: 'extension', title: 'file.extension', region: '#region' }],
28+
['./path/to/file.extension {c#}', { filepath: './path/to/file.extension', extension: 'extension', title: 'file.extension', lang: 'c#' }],
29+
['/path to/file.extension {1,2,4-6}', { filepath: '/path to/file.extension', extension: 'extension', title: 'file.extension', lines: '1,2,4-6' }],
30+
['/path to/file.extension {1,2,4-6 c#}', { filepath: '/path to/file.extension', extension: 'extension', title: 'file.extension', lines: '1,2,4-6', lang: 'c#' }],
31+
['/path.to/file.extension [title]', { filepath: '/path.to/file.extension', extension: 'extension', title: 'title' }],
32+
['./path.to/file.extension#region {c#}', { filepath: './path.to/file.extension', extension: 'extension', title: 'file.extension', region: '#region', lang: 'c#' }],
33+
['/path/to/file#region {1,2,4-6}', { filepath: '/path/to/file', title: 'file', region: '#region', lines: '1,2,4-6' }],
34+
['./path/to/file#region {1,2,4-6 c#}', { filepath: './path/to/file', title: 'file', region: '#region', lines: '1,2,4-6', lang: 'c#' }],
35+
['/path to/file {1,2,4-6 c#} [title]', { filepath: '/path to/file', title: 'title', lines: '1,2,4-6', lang: 'c#' }],
36+
['./path to/file#region {1,2,4-6 c#} [title]', { filepath: './path to/file', title: 'title', region: '#region', lines: '1,2,4-6', lang: 'c#' }],
37+
]
238

339
describe('node/markdown/plugins/snippet', () => {
440
describe('dedent', () => {
@@ -57,4 +93,10 @@ describe('node/markdown/plugins/snippet', () => {
5793
`)
5894
})
5995
})
96+
97+
test('rawPathToToken', () => {
98+
rawPathTokenMap.forEach(([rawPath, token]) => {
99+
expect(removeEmptyKeys(rawPathToToken(rawPath))).toEqual(token)
100+
})
101+
})
60102
})

‎src/node/markdown/plugins/snippet.ts

+31-20
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,35 @@ import type { RuleBlock } from 'markdown-it/lib/parser_block'
44
import path from 'path'
55
import type { MarkdownEnv } from '../../shared'
66

7+
/**
8+
* raw path format: "/path/to/file.extension#region {meta} [title]"
9+
* where #region, {meta} and [title] are optional
10+
* meta can be like '1,2,4-6 lang', 'lang' or '1,2,4-6'
11+
* lang can contain special characters like C++, C#, F#, etc.
12+
* path can be relative to the current file or absolute
13+
* file extension is optional
14+
* path can contain spaces and dots
15+
*
16+
* captures: ['/path/to/file.extension', 'extension', '#region', '{meta}', '[title]']
17+
*/
18+
export const rawPathRegexp =
19+
/^(.+?(?:(?:\.([a-z0-9]+))?))(?:(#[\w-]+))?(?: ?(?:{(\d+(?:[,-]\d+)*)? ?(\S+)?}))? ?(?:\[(.+)\])?$/
20+
21+
export function rawPathToToken(rawPath: string) {
22+
const [
23+
filepath = '',
24+
extension = '',
25+
region = '',
26+
lines = '',
27+
lang = '',
28+
rawTitle = ''
29+
] = (rawPathRegexp.exec(rawPath) || []).slice(1)
30+
31+
const title = rawTitle || filepath.split('/').pop() || ''
32+
33+
return { filepath, extension, region, lines, lang, title }
34+
}
35+
736
export function dedent(text: string): string {
837
const lines = text.split('\n')
938

@@ -91,32 +120,14 @@ export const snippetPlugin = (md: MarkdownIt, srcDir: string) => {
91120
const start = pos + 3
92121
const end = state.skipSpacesBack(max, pos)
93122

94-
/**
95-
* raw path format: "/path/to/file.extension#region {meta}"
96-
* where #region and {meta} are optional
97-
* and meta can be like '1,2,4-6 lang', 'lang' or '1,2,4-6'
98-
*
99-
* captures: ['/path/to/file.extension', 'extension', '#region', '{meta}', '[title]']
100-
*/
101-
const rawPathRegexp =
102-
/^(.+(?:\.([a-z0-9]+)))(?:(#[\w-]+))?(?: ?(?:{(\d+(?:[,-]\d+)*)? ?(\S+)?}))? ?(?:\[(.+)\])?$/
103-
104123
const rawPath = state.src
105124
.slice(start, end)
106125
.trim()
107126
.replace(/^@/, srcDir)
108127
.trim()
109128

110-
const [
111-
filepath = '',
112-
extension = '',
113-
region = '',
114-
lines = '',
115-
lang = '',
116-
rawTitle = ''
117-
] = (rawPathRegexp.exec(rawPath) || []).slice(1)
118-
119-
const title = rawTitle || filepath.split('/').pop() || ''
129+
const { filepath, extension, region, lines, lang, title } =
130+
rawPathToToken(rawPath)
120131

121132
state.line = startLine + 1
122133

0 commit comments

Comments
 (0)
Please sign in to comment.