-
Notifications
You must be signed in to change notification settings - Fork 3.6k
/
Copy pathtypescript.js
145 lines (129 loc) · 3.67 KB
/
typescript.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
Language: TypeScript
Author: Panu Horsmalahti <[email protected]>
Contributors: Ike Ku <[email protected]>
Description: TypeScript is a strict superset of JavaScript
Website: https://www.typescriptlang.org
Category: common, scripting
*/
import * as ECMAScript from "./lib/ecmascript.js";
import javascript from "./javascript.js";
/** @type LanguageFn */
export default function(hljs) {
const regex = hljs.regex;
const tsLanguage = javascript(hljs);
const IDENT_RE = ECMAScript.IDENT_RE;
const TYPES = [
"any",
"void",
"number",
"boolean",
"string",
"object",
"never",
"symbol",
"bigint",
"unknown"
];
const NAMESPACE = {
begin: [
/namespace/,
/\s+/,
hljs.IDENT_RE
],
beginScope: {
1: "keyword",
3: "title.class"
}
};
const INTERFACE = {
beginKeywords: 'interface',
end: /\{/,
excludeEnd: true,
keywords: {
keyword: 'interface extends',
built_in: TYPES
},
contains: [ tsLanguage.exports.CLASS_REFERENCE ]
};
const USE_STRICT = {
className: 'meta',
relevance: 10,
begin: /^\s*['"]use strict['"]/
};
const TS_SPECIFIC_KEYWORDS = [
"type",
// "namespace",
"interface",
"public",
"private",
"protected",
"implements",
"declare",
"abstract",
"readonly",
"enum",
"override",
"satisfies"
];
/*
namespace is a TS keyword but it's fine to use it as a variable name too.
const message = 'foo';
const namespace = 'bar';
*/
const KEYWORDS = {
$pattern: ECMAScript.IDENT_RE,
keyword: ECMAScript.KEYWORDS.concat(TS_SPECIFIC_KEYWORDS),
literal: ECMAScript.LITERALS,
built_in: ECMAScript.BUILT_INS.concat(TYPES),
"variable.language": ECMAScript.BUILT_IN_VARIABLES
};
const DECORATOR = {
className: 'meta',
begin: '@' + IDENT_RE,
};
const swapMode = (mode, label, replacement) => {
const indx = mode.contains.findIndex(m => m.label === label);
if (indx === -1) { throw new Error("can not find mode to replace"); }
mode.contains.splice(indx, 1, replacement);
};
// this should update anywhere keywords is used since
// it will be the same actual JS object
Object.assign(tsLanguage.keywords, KEYWORDS);
tsLanguage.exports.PARAMS_CONTAINS.push(DECORATOR);
// highlight the function params
const ATTRIBUTE_HIGHLIGHT = tsLanguage.contains.find(c => c.scope === "attr");
// take default attr rule and extend it to support optionals
const OPTIONAL_KEY_OR_ARGUMENT = Object.assign({},
ATTRIBUTE_HIGHLIGHT,
{ match: regex.concat(IDENT_RE, regex.lookahead(/\s*\?:/)) }
);
tsLanguage.exports.PARAMS_CONTAINS.push([
tsLanguage.exports.CLASS_REFERENCE, // class reference for highlighting the params types
ATTRIBUTE_HIGHLIGHT, // highlight the params key
OPTIONAL_KEY_OR_ARGUMENT, // Added for optional property assignment highlighting
]);
// Add the optional property assignment highlighting for objects or classes
tsLanguage.contains = tsLanguage.contains.concat([
DECORATOR,
NAMESPACE,
INTERFACE,
OPTIONAL_KEY_OR_ARGUMENT, // Added for optional property assignment highlighting
]);
// TS gets a simpler shebang rule than JS
swapMode(tsLanguage, "shebang", hljs.SHEBANG());
// JS use strict rule purposely excludes `asm` which makes no sense
swapMode(tsLanguage, "use_strict", USE_STRICT);
const functionDeclaration = tsLanguage.contains.find(m => m.label === "func.def");
functionDeclaration.relevance = 0; // () => {} is more typical in TypeScript
Object.assign(tsLanguage, {
name: 'TypeScript',
aliases: [
'ts',
'tsx',
'mts',
'cts'
]
});
return tsLanguage;
}