| 5 | const newlineRe = /\r\n|\r|\n/; |
| 6 | |
| 7 | export function tokenize(code: string, lang: string) { |
| 8 | const grammar = Prism.languages[lang]; |
| 9 | if (!grammar) { |
| 10 | throw new MissingGrammarError(lang); |
| 11 | } |
| 12 | |
| 13 | const prismTokens = Prism.tokenize(code, Prism.languages[lang]); |
| 14 | const nestedTokens = tokenizeStrings(prismTokens); |
| 15 | const tokens = flattenTokens(nestedTokens); |
| 16 | |
| 17 | let currentLine: FlatToken[] = []; |
| 18 | let currentTokenLine: string[] = []; |
| 19 | let currentTypeLine: string[] = []; |
| 20 | |
| 21 | const lines = [currentLine]; |
| 22 | const tokenLines = [currentTokenLine]; |
| 23 | const typeLines = [currentTypeLine]; |
| 24 | |
| 25 | tokens.forEach(token => { |
| 26 | const contentLines = token.content.split(newlineRe); |
| 27 | |
| 28 | const firstContent = contentLines.shift(); |
| 29 | if (firstContent !== undefined && firstContent !== "") { |
| 30 | currentLine.push({ type: token.type, content: firstContent }); |
| 31 | currentTokenLine.push(firstContent); |
| 32 | currentTypeLine.push(token.type); |
| 33 | } |
| 34 | contentLines.forEach(content => { |
| 35 | currentLine = []; |
| 36 | currentTokenLine = []; |
| 37 | currentTypeLine = []; |
| 38 | lines.push(currentLine); |
| 39 | tokenLines.push(currentTokenLine); |
| 40 | typeLines.push(currentTypeLine); |
| 41 | if (content !== "") { |
| 42 | currentLine.push({ type: token.type, content }); |
| 43 | currentTokenLine.push(content); |
| 44 | currentTypeLine.push(token.type); |
| 45 | } |
| 46 | }); |
| 47 | }); |
| 48 | return { |
| 49 | tokens: tokenLines, |
| 50 | types: typeLines |
| 51 | }; |
| 52 | } |
| 53 | |
| 54 | type NestedToken = { |
| 55 | type: string; |