diff --git a/components/prism-typescript.js b/components/prism-typescript.js index 54c45bf610..f15345bd4e 100644 --- a/components/prism-typescript.js +++ b/components/prism-typescript.js @@ -1,7 +1,42 @@ -Prism.languages.typescript = Prism.languages.extend('javascript', { - // From JavaScript Prism keyword list and TypeScript language spec: https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#221-reserved-words - 'keyword': /\b(?:abstract|as|async|await|break|case|catch|class|const|constructor|continue|debugger|declare|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|is|keyof|let|module|namespace|new|null|of|package|private|protected|public|readonly|return|require|set|static|super|switch|this|throw|try|type|typeof|undefined|var|void|while|with|yield)\b/, - 'builtin': /\b(?:string|Function|any|number|boolean|Array|symbol|console|Promise|unknown|never)\b/, -}); +(function (Prism) { -Prism.languages.ts = Prism.languages.typescript; + Prism.languages.typescript = Prism.languages.extend('javascript', { + 'class-name': { + pattern: /(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/, + lookbehind: true, + greedy: true, + inside: null // see below + }, + // From JavaScript Prism keyword list and TypeScript language spec: https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#221-reserved-words + 'keyword': /\b(?:abstract|as|asserts|async|await|break|case|catch|class|const|constructor|continue|debugger|declare|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|is|keyof|let|module|namespace|new|null|of|package|private|protected|public|readonly|return|require|set|static|super|switch|this|throw|try|type|typeof|undefined|var|void|while|with|yield)\b/, + 'builtin': /\b(?:string|Function|any|number|boolean|Array|symbol|console|Promise|unknown|never)\b/, + }); + + // doesn't work with TS because TS is too complex + delete Prism.languages.typescript['parameter']; + + // a version of typescript specifically for highlighting types + var typeInside = Prism.languages.extend('typescript', {}); + delete typeInside['class-name']; + + Prism.languages.typescript['class-name'].inside = typeInside; + + Prism.languages.insertBefore('typescript', 'function', { + 'generic-function': { + // e.g. foo( ... + pattern: /#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/, + greedy: true, + inside: { + 'function': /^#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*/, + 'generic': { + pattern: /<[\s\S]+/, // everything after the first < + alias: 'class-name', + inside: typeInside + } + } + } + }); + + Prism.languages.ts = Prism.languages.typescript; + +}(Prism)); diff --git a/components/prism-typescript.min.js b/components/prism-typescript.min.js index 2390f69400..18512141ed 100644 --- a/components/prism-typescript.min.js +++ b/components/prism-typescript.min.js @@ -1 +1 @@ -Prism.languages.typescript=Prism.languages.extend("javascript",{keyword:/\b(?:abstract|as|async|await|break|case|catch|class|const|constructor|continue|debugger|declare|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|is|keyof|let|module|namespace|new|null|of|package|private|protected|public|readonly|return|require|set|static|super|switch|this|throw|try|type|typeof|undefined|var|void|while|with|yield)\b/,builtin:/\b(?:string|Function|any|number|boolean|Array|symbol|console|Promise|unknown|never)\b/}),Prism.languages.ts=Prism.languages.typescript; \ No newline at end of file +!function(e){e.languages.typescript=e.languages.extend("javascript",{"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},keyword:/\b(?:abstract|as|asserts|async|await|break|case|catch|class|const|constructor|continue|debugger|declare|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|is|keyof|let|module|namespace|new|null|of|package|private|protected|public|readonly|return|require|set|static|super|switch|this|throw|try|type|typeof|undefined|var|void|while|with|yield)\b/,builtin:/\b(?:string|Function|any|number|boolean|Array|symbol|console|Promise|unknown|never)\b/}),delete e.languages.typescript.parameter;var n=e.languages.extend("typescript",{});delete n["class-name"],e.languages.typescript["class-name"].inside=n,e.languages.insertBefore("typescript","function",{"generic-function":{pattern:/#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:n}}}}),e.languages.ts=e.languages.typescript}(Prism); \ No newline at end of file diff --git a/tests/languages/typescript/class-name_feature.test b/tests/languages/typescript/class-name_feature.test new file mode 100644 index 0000000000..0a712617cf --- /dev/null +++ b/tests/languages/typescript/class-name_feature.test @@ -0,0 +1,125 @@ +interface Dictionary { + [key: string]: T; +} + +interface Foo extends Dictionary {} + +class Bar extends Baz implements FooBar {} + +type Record = { + [P in K]: T; +} +type Diff = T extends U ? never : T; + +---------------------------------------------------- + +[ + ["keyword", "interface"], + ["class-name", [ + "Dictionary", + ["operator", "<"], + ["constant", "T"], + ["operator", ">"] + ]], + ["punctuation", "{"], + ["punctuation", "["], + "key", + ["operator", ":"], + ["builtin", "string"], + ["punctuation", "]"], + ["operator", ":"], + ["constant", "T"], + ["punctuation", ";"], + ["punctuation", "}"], + + ["keyword", "interface"], + ["class-name", [ + "Foo" + ]], + ["keyword", "extends"], + ["class-name", [ + "Dictionary", + ["operator", "<"], + ["builtin", "number"], + ["operator", ">"] + ]], + ["punctuation", "{"], + ["punctuation", "}"], + + ["keyword", "class"], + ["class-name", [ + "Bar", + ["operator", "<"], + ["constant", "T"], + ["operator", ">"] + ]], + ["keyword", "extends"], + ["class-name", [ + "Baz", + ["operator", "<"], + ["constant", "T"], + ["operator", ">"] + ]], + ["keyword", "implements"], + ["class-name", [ + "FooBar", + ["operator", "<"], + ["builtin", "number"], + ["punctuation", ","], + ["constant", "T"], + ["operator", "|"], + ["keyword", "null"], + ["operator", ">"] + ]], + ["punctuation", "{"], + ["punctuation", "}"], + + ["keyword", "type"], + ["class-name", [ + "Record", + ["operator", "<"], + ["constant", "K"], + ["keyword", "extends"], + ["keyword", "keyof"], + ["builtin", "any"], + ["punctuation", ","], + ["constant", "T"], + ["operator", ">"] + ]], + ["operator", "="], + ["punctuation", "{"], + ["punctuation", "["], + ["constant", "P"], + ["keyword", "in"], + ["constant", "K"], + ["punctuation", "]"], + ["operator", ":"], + ["constant", "T"], + ["punctuation", ";"], + ["punctuation", "}"], + + ["keyword", "type"], + ["class-name", [ + "Diff", + ["operator", "<"], + ["constant", "T"], + ["punctuation", ","], + ["constant", "U"], + ["operator", ">"] + ]], + ["operator", "="], + ["constant", "T"], + ["keyword", "extends"], + ["class-name", [ + ["constant", "U"] + ]], + ["operator", "?"], + ["builtin", "never"], + ["operator", ":"], + ["constant", "T"], + ["punctuation", ";"] +] + +---------------------------------------------------- + +Checks for class, interface, and other type names. diff --git a/tests/languages/typescript/function_feature.test b/tests/languages/typescript/function_feature.test new file mode 100644 index 0000000000..3b0fd70417 --- /dev/null +++ b/tests/languages/typescript/function_feature.test @@ -0,0 +1,91 @@ +function getProperty(o: T, propertyName: K): T[K] { } + +declare function f(x: T): T extends true ? string : number; + +function assert(condition: any, msg?: string): asserts condition { } + +---------------------------------------------------- + +[ + ["keyword", "function"], + ["generic-function", [ + ["function", "getProperty"], + ["generic", [ + ["operator", "<"], + ["constant", "T"], + ["punctuation", ","], + ["constant", "K"], + ["keyword", "extends"], + ["keyword", "keyof"], + ["constant", "T"], + ["operator", ">"] + ]] + ]], + ["punctuation", "("], + "o", + ["operator", ":"], + ["constant", "T"], + ["punctuation", ","], + " propertyName", + ["operator", ":"], + ["constant", "K"], + ["punctuation", ")"], + ["operator", ":"], + ["constant", "T"], + ["punctuation", "["], + ["constant", "K"], + ["punctuation", "]"], + ["punctuation", "{"], + ["punctuation", "}"], + + ["keyword", "declare"], + ["keyword", "function"], + ["generic-function", [ + ["function", "f"], + ["generic", [ + ["operator", "<"], + ["constant", "T"], + ["keyword", "extends"], + ["builtin", "boolean"], + ["operator", ">"] + ]] + ]], + ["punctuation", "("], + "x", + ["operator", ":"], + ["constant", "T"], + ["punctuation", ")"], + ["operator", ":"], + ["constant", "T"], + ["keyword", "extends"], + ["class-name", [ + ["boolean", "true"] + ]], + ["operator", "?"], + ["builtin", "string"], + ["operator", ":"], + ["builtin", "number"], + ["punctuation", ";"], + + ["keyword", "function"], + ["function", "assert"], + ["punctuation", "("], + "condition", + ["operator", ":"], + ["builtin", "any"], + ["punctuation", ","], + " msg", + ["operator", "?"], + ["operator", ":"], + ["builtin", "string"], + ["punctuation", ")"], + ["operator", ":"], + ["keyword", "asserts"], + " condition ", + ["punctuation", "{"], + ["punctuation", "}"] +] + +---------------------------------------------------- + +Checks for functions. diff --git a/tests/languages/typescript/keyword_feature.test b/tests/languages/typescript/keyword_feature.test index 9e19b365a4..f877e094e3 100644 --- a/tests/languages/typescript/keyword_feature.test +++ b/tests/languages/typescript/keyword_feature.test @@ -1,5 +1,6 @@ abstract as +asserts async await break @@ -51,8 +52,9 @@ switch this throw try -type +type; typeof +undefined var void while @@ -64,6 +66,7 @@ yield [ ["keyword", "abstract"], ["keyword", "as"], + ["keyword", "asserts"], ["keyword", "async"], ["keyword", "await"], ["keyword", "break"], @@ -115,8 +118,9 @@ yield ["keyword", "this"], ["keyword", "throw"], ["keyword", "try"], - ["keyword", "type"], + ["keyword", "type"], ["punctuation", ";"], ["keyword", "typeof"], + ["keyword", "undefined"], ["keyword", "var"], ["keyword", "void"], ["keyword", "while"], @@ -126,4 +130,4 @@ yield ---------------------------------------------------- -Checks for keywords. \ No newline at end of file +Checks for keywords.