-
Notifications
You must be signed in to change notification settings - Fork 55
/
Copy pathswift.js
80 lines (72 loc) · 2.89 KB
/
swift.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
/**
* This source file is part of the Swift.org open source project
*
* Copyright (c) 2021 Apple Inc. and the Swift project authors
* Licensed under Apache License v2.0 with Runtime Library Exception
*
* See https://swift.org/LICENSE.txt for license information
* See https://swift.org/CONTRIBUTORS.txt for Swift project authors
*/
import swift from 'highlight.js/lib/languages/swift';
export default function swiftOverride(hljs) {
const language = swift(hljs);
// Temporarily patch the Swift language syntax to recognize `distributed` as
// a keyword until the next version of highlight.js (v11.6) is released, which
// will have built-in support for this [1]
//
// [1]: https://github.com/highlightjs/highlight.js/pull/3523
language.keywords.keyword = [
...language.keywords.keyword,
'distributed',
];
const isClassMode = ({ beginKeywords = '' }) => beginKeywords
.split(' ')
.includes('class');
const classModeIndex = language.contains.findIndex(isClassMode);
if (classModeIndex >= 0) {
const {
beginKeywords, // purposefully strip this out
...classMode
} = language.contains[classModeIndex];
// Update the existing "class" mode by replacing the `beginKeywords` with
// a `begin` regular expression, which is careful not to mistakenly
// recognize class function declarations as class declarations
language.contains[classModeIndex] = {
...classMode,
begin: /\b(struct|protocol|extension|enum|actor|class\b(?!.*\bfunc))\b/,
};
}
// Checks if a given language sub-mode matches the "ESCAPED_NEWLINE" from the
// built-in Swift parser from hljs
const isEscapedNewlineMode = (mode) => {
const { className, match } = mode;
if (className !== 'subst' || !match) {
return false;
}
const matchStr = match.toString();
return matchStr.startsWith('\\') && matchStr.endsWith('[\\t ]*(?:[\\r\\n]|\\r\\n)');
};
// replace the "ESCAPED_NEWLINE" sub-mode in the multiline string literal mode
// variants so that it doesn't include the actual newline characters in the
// span token that it generates, because this causes issues with our
// line-number + multi-line string literal logic when the span for the
// backslash token is split across multiple lines
const strIndex = language.contains.findIndex(({ className }) => className === 'string');
language.contains[strIndex] = {
...language.contains[strIndex],
variants: language.contains[strIndex].variants.map(variant => ({
...variant,
contains: variant.contains.map(mode => (isEscapedNewlineMode(mode) ? ({
className: 'subst',
begin: /\\#{0,3}/,
end: /[\t ]*(?:[\r\n]|\r\n)/,
// same match as the original one but with an explicit start/end match so
// that the end one can be excluded from the resulting span
excludeEnd: true,
}) : (
mode
))),
})),
};
return language;
}