skir 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/casing.d.ts +1 -4
- package/dist/casing.d.ts.map +1 -1
- package/dist/casing.js +0 -29
- package/dist/casing.js.map +1 -1
- package/dist/casing.test.js +2 -13
- package/dist/casing.test.js.map +1 -1
- package/dist/command_line_parser.d.ts +3 -3
- package/dist/command_line_parser.d.ts.map +1 -1
- package/dist/command_line_parser.js +35 -38
- package/dist/command_line_parser.js.map +1 -1
- package/dist/command_line_parser.test.js +73 -78
- package/dist/command_line_parser.test.js.map +1 -1
- package/dist/compatibility_checker.d.ts +9 -3
- package/dist/compatibility_checker.d.ts.map +1 -1
- package/dist/compatibility_checker.js +17 -4
- package/dist/compatibility_checker.js.map +1 -1
- package/dist/compatibility_checker.test.js +55 -1
- package/dist/compatibility_checker.test.js.map +1 -1
- package/dist/compiler.js +34 -17
- package/dist/compiler.js.map +1 -1
- package/dist/config.d.ts +5 -35
- package/dist/config.d.ts.map +1 -1
- package/dist/definition_finder.d.ts +1 -1
- package/dist/definition_finder.d.ts.map +1 -1
- package/dist/doc_comment_parser.d.ts +3 -0
- package/dist/doc_comment_parser.d.ts.map +1 -0
- package/dist/doc_comment_parser.js +219 -0
- package/dist/doc_comment_parser.js.map +1 -0
- package/dist/doc_comment_parser.test.d.ts +2 -0
- package/dist/doc_comment_parser.test.d.ts.map +1 -0
- package/dist/doc_comment_parser.test.js +494 -0
- package/dist/doc_comment_parser.test.js.map +1 -0
- package/dist/error_renderer.d.ts +1 -1
- package/dist/error_renderer.d.ts.map +1 -1
- package/dist/error_renderer.js +84 -65
- package/dist/error_renderer.js.map +1 -1
- package/dist/formatter.d.ts +15 -2
- package/dist/formatter.d.ts.map +1 -1
- package/dist/formatter.js +191 -234
- package/dist/formatter.js.map +1 -1
- package/dist/formatter.test.js +322 -88
- package/dist/formatter.test.js.map +1 -1
- package/dist/index.d.ts +1 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -4
- package/dist/index.js.map +1 -1
- package/dist/language_server.js +1 -1
- package/dist/language_server.js.map +1 -1
- package/dist/literals.d.ts +1 -2
- package/dist/literals.d.ts.map +1 -1
- package/dist/literals.js +1 -12
- package/dist/literals.js.map +1 -1
- package/dist/literals.test.js +1 -4
- package/dist/literals.test.js.map +1 -1
- package/dist/module_set.d.ts +3 -7
- package/dist/module_set.d.ts.map +1 -1
- package/dist/module_set.js +205 -51
- package/dist/module_set.js.map +1 -1
- package/dist/module_set.test.js +595 -28
- package/dist/module_set.test.js.map +1 -1
- package/dist/parser.d.ts +3 -4
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +185 -92
- package/dist/parser.js.map +1 -1
- package/dist/parser.test.js +243 -15
- package/dist/parser.test.js.map +1 -1
- package/dist/project_initializer.d.ts +2 -0
- package/dist/project_initializer.d.ts.map +1 -0
- package/dist/project_initializer.js +30 -0
- package/dist/project_initializer.js.map +1 -0
- package/dist/snapshotter.d.ts +3 -0
- package/dist/snapshotter.d.ts.map +1 -1
- package/dist/snapshotter.js +43 -6
- package/dist/snapshotter.js.map +1 -1
- package/dist/tokenizer.d.ts +8 -2
- package/dist/tokenizer.d.ts.map +1 -1
- package/dist/tokenizer.js +26 -20
- package/dist/tokenizer.js.map +1 -1
- package/dist/tokenizer.test.js +285 -269
- package/dist/tokenizer.test.js.map +1 -1
- package/package.json +7 -5
- package/src/casing.ts +1 -36
- package/src/command_line_parser.ts +42 -48
- package/src/compatibility_checker.ts +29 -7
- package/src/compiler.ts +35 -18
- package/src/definition_finder.ts +1 -1
- package/src/doc_comment_parser.ts +246 -0
- package/src/error_renderer.ts +90 -66
- package/src/formatter.ts +249 -238
- package/src/index.ts +0 -6
- package/src/language_server.ts +8 -8
- package/src/literals.ts +5 -14
- package/src/module_set.ts +259 -79
- package/src/parser.ts +213 -98
- package/src/project_initializer.ts +39 -0
- package/src/snapshotter.ts +46 -5
- package/src/tokenizer.ts +47 -25
- package/dist/encoding.d.ts +0 -2
- package/dist/encoding.d.ts.map +0 -1
- package/dist/encoding.js +0 -38
- package/dist/encoding.js.map +0 -1
- package/dist/encoding.test.d.ts +0 -2
- package/dist/encoding.test.d.ts.map +0 -1
- package/dist/encoding.test.js +0 -23
- package/dist/encoding.test.js.map +0 -1
- package/dist/index.test.d.ts +0 -2
- package/dist/index.test.d.ts.map +0 -1
- package/dist/index.test.js +0 -14
- package/dist/index.test.js.map +0 -1
- package/dist/types.d.ts +0 -375
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- package/src/encoding.ts +0 -32
- package/src/types.ts +0 -518
package/src/formatter.ts
CHANGED
|
@@ -1,274 +1,285 @@
|
|
|
1
|
-
import type { Token } from "
|
|
1
|
+
import type { Token } from "skir-internal";
|
|
2
|
+
import { ModuleTokens } from "./tokenizer.js";
|
|
2
3
|
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
export interface FormattedModule {
|
|
5
|
+
readonly newSourceCode: string;
|
|
6
|
+
/// For VSCode extension: text edits to convert the original source code into
|
|
7
|
+
// the formatted source code.
|
|
8
|
+
readonly textEdits: readonly TextEdit[];
|
|
9
|
+
}
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
) {
|
|
15
|
-
// Preserve comments before line break.
|
|
16
|
-
sink.write(" " + iterator.next().text);
|
|
17
|
-
}
|
|
18
|
-
};
|
|
11
|
+
export interface TextEdit {
|
|
12
|
+
readonly oldStart: number;
|
|
13
|
+
readonly oldEnd: number;
|
|
14
|
+
readonly newText: string;
|
|
15
|
+
}
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (next.line.lineNumber >= current.line.lineNumber + 2) {
|
|
27
|
-
// Preserve double line breaks.
|
|
28
|
-
sink.write("\n");
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
if (!lastLineOnlyHasWhitespaces) {
|
|
32
|
-
sink.write("\n" + " ".repeat(indentDepth));
|
|
33
|
-
}
|
|
34
|
-
};
|
|
17
|
+
/**
|
|
18
|
+
* Formats the given module and returns the new source code.
|
|
19
|
+
* Preserves token ordering.
|
|
20
|
+
*/
|
|
21
|
+
export function formatModule(moduleTokens: ModuleTokens): FormattedModule {
|
|
22
|
+
const tokens = moduleTokens.tokensWithComments;
|
|
35
23
|
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
24
|
+
const context: Context = {
|
|
25
|
+
context: null,
|
|
26
|
+
indentStack: [{ indent: "" }],
|
|
39
27
|
};
|
|
40
28
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
29
|
+
let newSourceCode = "";
|
|
30
|
+
const textEdits: TextEdit[] = [];
|
|
31
|
+
|
|
32
|
+
const appendToken: (t: Token) => void = (t: Token) => {
|
|
33
|
+
const newToken = normalizeToken(t.text);
|
|
34
|
+
if (newToken !== t.text) {
|
|
35
|
+
textEdits.push({
|
|
36
|
+
oldStart: t.position,
|
|
37
|
+
oldEnd: t.position + t.text.length,
|
|
38
|
+
newText: newToken,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
newSourceCode += newToken;
|
|
44
42
|
};
|
|
43
|
+
appendToken(tokens[0]!);
|
|
45
44
|
|
|
46
|
-
|
|
47
|
-
const token =
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
case ":": {
|
|
57
|
-
sink.write(token.text + " ");
|
|
58
|
-
break;
|
|
59
|
-
}
|
|
60
|
-
case "from": {
|
|
61
|
-
sink.write(" from ");
|
|
62
|
-
break;
|
|
63
|
-
}
|
|
64
|
-
case "removed": {
|
|
65
|
-
if (iterator.hasNext() && iterator.peek().text === ";") {
|
|
66
|
-
sink.write("removed");
|
|
67
|
-
} else {
|
|
68
|
-
sink.write("removed ");
|
|
69
|
-
}
|
|
70
|
-
break;
|
|
71
|
-
}
|
|
72
|
-
case "{": {
|
|
73
|
-
if (iterator.hasNext() && iterator.peek().text === "}") {
|
|
74
|
-
sink.write(inValue ? "{}" : " {}");
|
|
75
|
-
iterator.next();
|
|
76
|
-
if (!inValue) {
|
|
77
|
-
breakLine();
|
|
78
|
-
}
|
|
79
|
-
} else {
|
|
80
|
-
sink.write(inValue ? "{" : " {");
|
|
81
|
-
breakLineAndIndent();
|
|
82
|
-
}
|
|
83
|
-
break;
|
|
84
|
-
}
|
|
85
|
-
case "{|": {
|
|
86
|
-
if (iterator.hasNext() && iterator.peek().text === "|}") {
|
|
87
|
-
sink.write(inValue ? "{||}" : " {||}");
|
|
88
|
-
iterator.next();
|
|
89
|
-
if (!inValue) {
|
|
90
|
-
breakLine();
|
|
91
|
-
}
|
|
92
|
-
} else {
|
|
93
|
-
sink.write(inValue ? "{|" : " {|");
|
|
94
|
-
breakLineAndIndent();
|
|
95
|
-
}
|
|
96
|
-
break;
|
|
97
|
-
}
|
|
98
|
-
case "}": {
|
|
99
|
-
if (inValue) {
|
|
100
|
-
sink.maybeWriteTrailingComma();
|
|
101
|
-
breakLine();
|
|
102
|
-
}
|
|
103
|
-
unindent();
|
|
104
|
-
sink.write("}");
|
|
105
|
-
if (!inValue) {
|
|
106
|
-
breakLine();
|
|
107
|
-
}
|
|
108
|
-
break;
|
|
109
|
-
}
|
|
110
|
-
case "|}": {
|
|
111
|
-
if (inValue) {
|
|
112
|
-
sink.maybeWriteTrailingComma();
|
|
113
|
-
breakLine();
|
|
114
|
-
}
|
|
115
|
-
unindent();
|
|
116
|
-
sink.write("|}");
|
|
117
|
-
if (!inValue) {
|
|
118
|
-
breakLine();
|
|
119
|
-
}
|
|
120
|
-
break;
|
|
121
|
-
}
|
|
122
|
-
case "[": {
|
|
123
|
-
if (iterator.hasNext() && iterator.peek().text === "]") {
|
|
124
|
-
sink.write("[]");
|
|
125
|
-
iterator.next();
|
|
126
|
-
} else {
|
|
127
|
-
sink.write("[");
|
|
128
|
-
if (inValue) {
|
|
129
|
-
breakLineAndIndent();
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
break;
|
|
133
|
-
}
|
|
134
|
-
case "]": {
|
|
135
|
-
if (inValue) {
|
|
136
|
-
sink.maybeWriteTrailingComma();
|
|
137
|
-
breakLine();
|
|
138
|
-
unindent();
|
|
139
|
-
}
|
|
140
|
-
sink.write("]");
|
|
141
|
-
break;
|
|
142
|
-
}
|
|
143
|
-
case ";": {
|
|
144
|
-
sink.write(";");
|
|
145
|
-
inValue = false;
|
|
146
|
-
breakLine();
|
|
147
|
-
break;
|
|
148
|
-
}
|
|
149
|
-
case "=": {
|
|
150
|
-
inValue = true;
|
|
151
|
-
sink.write(" = ");
|
|
152
|
-
break;
|
|
153
|
-
}
|
|
154
|
-
case ",": {
|
|
155
|
-
if (inValue) {
|
|
156
|
-
sink.write(",");
|
|
157
|
-
breakLine();
|
|
158
|
-
} else {
|
|
159
|
-
sink.write(", ");
|
|
160
|
-
}
|
|
45
|
+
for (let i = 1; i < tokens.length; i++) {
|
|
46
|
+
const token = tokens[i - 1]!;
|
|
47
|
+
const next = tokens[i]!;
|
|
48
|
+
|
|
49
|
+
// Find the next non-comment token
|
|
50
|
+
let nextNonComment = next;
|
|
51
|
+
for (let j = i; j < tokens.length; j++) {
|
|
52
|
+
const token = tokens[j]!;
|
|
53
|
+
if (!isComment(token)) {
|
|
54
|
+
nextNonComment = token;
|
|
161
55
|
break;
|
|
162
56
|
}
|
|
163
|
-
default: {
|
|
164
|
-
if (isComment(token.text)) {
|
|
165
|
-
sink.writeComment(token.text);
|
|
166
|
-
breakLine();
|
|
167
|
-
} else if (token.text.startsWith("'")) {
|
|
168
|
-
const unescapedDoubleQuoteRegex = /(?:^|[^\\])(?:\\\\)*"/;
|
|
169
|
-
if (unescapedDoubleQuoteRegex.test(token.text)) {
|
|
170
|
-
sink.write(token.text);
|
|
171
|
-
} else {
|
|
172
|
-
// Switch to double quotes.
|
|
173
|
-
const unquoted = token.text.slice(1, -1);
|
|
174
|
-
sink.write(`"${unquoted}"`);
|
|
175
|
-
}
|
|
176
|
-
} else {
|
|
177
|
-
sink.write(token.text);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
57
|
}
|
|
181
|
-
}
|
|
182
58
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
59
|
+
// Determine the text to add after 'token' and before 'next': a possible
|
|
60
|
+
// trailing comma followed by whitespace.
|
|
61
|
+
let newSeparator = shouldAddTrailingComma(token, nextNonComment!, context)
|
|
62
|
+
? ","
|
|
63
|
+
: "";
|
|
64
|
+
newSeparator += getWhitespaceAfterToken(
|
|
65
|
+
token,
|
|
66
|
+
next,
|
|
67
|
+
nextNonComment!,
|
|
68
|
+
context,
|
|
69
|
+
);
|
|
70
|
+
const topOfStack = context.indentStack.at(-1)!;
|
|
71
|
+
if (newSeparator.endsWith("\n")) {
|
|
72
|
+
newSeparator = newSeparator + topOfStack.indent;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const oldSeparator = moduleTokens.sourceCode.slice(
|
|
76
|
+
token.position + token.text.length,
|
|
77
|
+
next.position,
|
|
78
|
+
);
|
|
79
|
+
if (oldSeparator !== newSeparator) {
|
|
80
|
+
textEdits.push({
|
|
81
|
+
oldStart: token.position + token.text.length,
|
|
82
|
+
oldEnd: next.position,
|
|
83
|
+
newText: newSeparator,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
newSourceCode += newSeparator;
|
|
88
|
+
|
|
89
|
+
appendToken(next);
|
|
186
90
|
}
|
|
187
91
|
|
|
188
|
-
return
|
|
92
|
+
return {
|
|
93
|
+
newSourceCode: newSourceCode,
|
|
94
|
+
textEdits: textEdits,
|
|
95
|
+
};
|
|
189
96
|
}
|
|
190
97
|
|
|
191
|
-
|
|
192
|
-
|
|
98
|
+
type Context = {
|
|
99
|
+
context:
|
|
100
|
+
| "const" // Between 'const' and '='
|
|
101
|
+
| "in-value" // After 'const', between '=' and ';'
|
|
102
|
+
| "removed" // Between 'removed' and ';'
|
|
103
|
+
| null;
|
|
104
|
+
readonly indentStack: IndentStackItem[];
|
|
105
|
+
};
|
|
193
106
|
|
|
194
|
-
|
|
107
|
+
interface IndentStackItem {
|
|
108
|
+
indent: string;
|
|
109
|
+
// If true, the new indentation level is for the declaration of an inline
|
|
110
|
+
// record as a method request type:
|
|
111
|
+
// method GetFoo(
|
|
112
|
+
// struct {
|
|
113
|
+
// ...
|
|
114
|
+
// }
|
|
115
|
+
// ): Foo;
|
|
116
|
+
inlineRecordInBracket?: true;
|
|
117
|
+
}
|
|
195
118
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
119
|
+
function getWhitespaceAfterToken(
|
|
120
|
+
token: Token,
|
|
121
|
+
next: Token,
|
|
122
|
+
// If 'next' is a comment, the next non-comment token after 'next'.
|
|
123
|
+
// Otherwise, 'next' itself.
|
|
124
|
+
nextNonComment: Token,
|
|
125
|
+
context: Context,
|
|
126
|
+
): "" | " " | " " | "\n" | "\n\n" {
|
|
127
|
+
const topOfStack: () => IndentStackItem = () => context.indentStack.at(-1)!;
|
|
202
128
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
129
|
+
const indentUnit = " ";
|
|
130
|
+
if (
|
|
131
|
+
token.text === "{" ||
|
|
132
|
+
token.text === "{|" ||
|
|
133
|
+
(context.context === "in-value" && token.text === "[")
|
|
134
|
+
) {
|
|
135
|
+
context.indentStack.push({
|
|
136
|
+
indent: topOfStack().indent + indentUnit,
|
|
137
|
+
});
|
|
138
|
+
} else if (
|
|
139
|
+
token.text === "(" &&
|
|
140
|
+
["struct", "enum"].includes(nextNonComment.text)
|
|
141
|
+
) {
|
|
142
|
+
context.indentStack.push({
|
|
143
|
+
indent: topOfStack().indent + indentUnit,
|
|
144
|
+
inlineRecordInBracket: true,
|
|
145
|
+
});
|
|
208
146
|
}
|
|
209
147
|
|
|
210
|
-
|
|
211
|
-
|
|
148
|
+
if (
|
|
149
|
+
next.text === "}" ||
|
|
150
|
+
next.text === "|}" ||
|
|
151
|
+
(context.context === "in-value" && next.text === "]") ||
|
|
152
|
+
(next.text === ")" && topOfStack().inlineRecordInBracket)
|
|
153
|
+
) {
|
|
154
|
+
context.indentStack.pop();
|
|
212
155
|
}
|
|
213
156
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
157
|
+
if (isComment(token)) {
|
|
158
|
+
return oneOrTwoLineBreaks(token, next);
|
|
159
|
+
} else if (
|
|
160
|
+
token.text !== "{" &&
|
|
161
|
+
next.text === "}" &&
|
|
162
|
+
context.context !== "in-value"
|
|
163
|
+
) {
|
|
164
|
+
return "\n";
|
|
165
|
+
} else if (isComment(next)) {
|
|
166
|
+
return token.line.lineNumber === next.line.lineNumber
|
|
167
|
+
? " "
|
|
168
|
+
: oneOrTwoLineBreaks(token, next);
|
|
169
|
+
} else if (next.text === "=") {
|
|
170
|
+
return " ";
|
|
171
|
+
} else if (
|
|
172
|
+
(token.text === "[" && next.text === "]") ||
|
|
173
|
+
(token.text === "{" && next.text === "}") ||
|
|
174
|
+
(token.text === "{|" && next.text === "|}")
|
|
175
|
+
) {
|
|
176
|
+
return "";
|
|
177
|
+
} else if (["{", "{|"].includes(token.text)) {
|
|
178
|
+
return "\n";
|
|
179
|
+
} else if (token.text === "[") {
|
|
180
|
+
return context.context === "in-value" ? "\n" : "";
|
|
181
|
+
} else if (["*", ":"].includes(token.text)) {
|
|
182
|
+
return " ";
|
|
183
|
+
} else if (token.text === "(") {
|
|
184
|
+
return ["struct", "enum"].includes(next.text) ? "\n" : "";
|
|
185
|
+
} else if (token.text === ")") {
|
|
186
|
+
return next.text === "{" ? " " : "";
|
|
187
|
+
} else if (token.text === ";") {
|
|
188
|
+
context.context = null;
|
|
189
|
+
return oneOrTwoLineBreaks(token, next);
|
|
190
|
+
} else if (token.text === "}") {
|
|
191
|
+
return [",", ";"].includes(next.text)
|
|
192
|
+
? ""
|
|
193
|
+
: oneOrTwoLineBreaks(token, next);
|
|
194
|
+
} else if (token.text === ",") {
|
|
195
|
+
return context.context === "removed" ? " " : "\n";
|
|
196
|
+
} else if (token.text === "=") {
|
|
197
|
+
if (context.context === "const") {
|
|
198
|
+
context.context = "in-value";
|
|
218
199
|
}
|
|
219
|
-
|
|
200
|
+
return " ";
|
|
201
|
+
} else if (token.text === "const") {
|
|
202
|
+
context.context = "const";
|
|
203
|
+
return " ";
|
|
204
|
+
} else if (token.text === "removed") {
|
|
205
|
+
context.context = "removed";
|
|
206
|
+
return next.text === ";" ? "" : " ";
|
|
207
|
+
} else if (
|
|
208
|
+
context.context === "in-value" &&
|
|
209
|
+
["]", "}", "|}"].includes(next.text)
|
|
210
|
+
) {
|
|
211
|
+
return "\n";
|
|
212
|
+
} else if (
|
|
213
|
+
/^[A-Za-z]/.test(token.text) &&
|
|
214
|
+
!["(", ":", ",", ";", "|", ".", ")", "]", "?"].includes(next.text)
|
|
215
|
+
) {
|
|
216
|
+
return " ";
|
|
217
|
+
} else {
|
|
218
|
+
return "";
|
|
220
219
|
}
|
|
221
220
|
}
|
|
222
221
|
|
|
223
|
-
function
|
|
224
|
-
|
|
222
|
+
function shouldAddTrailingComma(
|
|
223
|
+
first: Token,
|
|
224
|
+
nextNonComment: Token,
|
|
225
|
+
context: Context,
|
|
226
|
+
): boolean {
|
|
227
|
+
return (
|
|
228
|
+
context.context === "in-value" &&
|
|
229
|
+
["]", "}", "|}"].includes(nextNonComment.text) &&
|
|
230
|
+
!["[", "{", "{|", ","].includes(first.text)
|
|
231
|
+
);
|
|
225
232
|
}
|
|
226
233
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
this.endPosition = trimmed.endsWith(",")
|
|
238
|
-
? 0
|
|
239
|
-
: this.code.length + text.trimEnd().length;
|
|
240
|
-
}
|
|
241
|
-
this._code += text;
|
|
234
|
+
function oneOrTwoLineBreaks(first: Token, second: Token): "\n" | "\n\n" {
|
|
235
|
+
const firstLineNumber =
|
|
236
|
+
first.line.lineNumber + first.text.split("\n").length - 1;
|
|
237
|
+
if (
|
|
238
|
+
firstLineNumber < second.line.lineNumber - 1 &&
|
|
239
|
+
(isComment(second) || /^[A-Za-z]/.test(second.text))
|
|
240
|
+
) {
|
|
241
|
+
return "\n\n";
|
|
242
|
+
} else {
|
|
243
|
+
return "\n";
|
|
242
244
|
}
|
|
245
|
+
}
|
|
243
246
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
} else {
|
|
248
|
-
this._code = this.code.trimEnd() + " " + text;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
247
|
+
function isComment(token: Token): boolean {
|
|
248
|
+
return token.text.startsWith("//") || token.text.startsWith("/*");
|
|
249
|
+
}
|
|
251
250
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
251
|
+
function normalizeToken(token: string): string {
|
|
252
|
+
if (token.startsWith("//")) {
|
|
253
|
+
// Make sure there is a space between the double slash and the comment text.
|
|
254
|
+
if (
|
|
255
|
+
token.startsWith("// ") ||
|
|
256
|
+
token.startsWith("/// ") ||
|
|
257
|
+
token === "//" ||
|
|
258
|
+
token === "///"
|
|
259
|
+
) {
|
|
260
|
+
return token;
|
|
261
|
+
} else if (token.startsWith("///")) {
|
|
262
|
+
return "/// " + token.slice(3);
|
|
263
|
+
} else {
|
|
264
|
+
return "// " + token.slice(2);
|
|
255
265
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
266
|
+
} else if (token.startsWith("'")) {
|
|
267
|
+
// A single-quoted string
|
|
268
|
+
if (token.includes('"')) {
|
|
269
|
+
// Remove escape characters before single quotes.
|
|
270
|
+
return token.replace(/\\(?=(?:\\\\)*')/g, "");
|
|
271
|
+
} else {
|
|
272
|
+
// If the string does not contain double quotes, turn it into a
|
|
273
|
+
// double-quoted string for consistency
|
|
274
|
+
const content = token.slice(1, -1);
|
|
275
|
+
// Remove escape characters before double quotes.
|
|
276
|
+
return '"' + content.replace(/\\(?=(?:\\\\)*")/g, "") + '"';
|
|
264
277
|
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
return
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
get code(): string {
|
|
272
|
-
return this._code;
|
|
278
|
+
} else if (token.startsWith('"')) {
|
|
279
|
+
// A double-quoted string
|
|
280
|
+
// Remove escape characters before double quotes.
|
|
281
|
+
return token.replace(/\\(?=(?:\\\\)*')/g, "");
|
|
282
|
+
} else {
|
|
283
|
+
return token;
|
|
273
284
|
}
|
|
274
285
|
}
|
package/src/index.ts
CHANGED
package/src/language_server.ts
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import * as yaml from "yaml";
|
|
2
|
-
import { fromZodError } from "zod-validation-error";
|
|
3
|
-
import { SkirConfig } from "./config.js";
|
|
4
|
-
import { ModuleParser, ModuleSet } from "./module_set.js";
|
|
5
|
-
import { parseModule } from "./parser.js";
|
|
6
|
-
import { tokenizeModule } from "./tokenizer.js";
|
|
7
1
|
import type {
|
|
8
2
|
Module,
|
|
9
3
|
MutableModule,
|
|
@@ -11,7 +5,13 @@ import type {
|
|
|
11
5
|
RecordLocation,
|
|
12
6
|
Result,
|
|
13
7
|
SkirError,
|
|
14
|
-
} from "
|
|
8
|
+
} from "skir-internal";
|
|
9
|
+
import * as yaml from "yaml";
|
|
10
|
+
import { fromZodError } from "zod-validation-error";
|
|
11
|
+
import { SkirConfig } from "./config.js";
|
|
12
|
+
import { ModuleParser, ModuleSet } from "./module_set.js";
|
|
13
|
+
import { parseModule } from "./parser.js";
|
|
14
|
+
import { tokenizeModule } from "./tokenizer.js";
|
|
15
15
|
|
|
16
16
|
export class LanguageServerModuleSet {
|
|
17
17
|
constructor(private readonly rootPath: string) {}
|
|
@@ -120,7 +120,7 @@ export class LanguageServerModuleSet {
|
|
|
120
120
|
errors: tokens.errors,
|
|
121
121
|
};
|
|
122
122
|
} else {
|
|
123
|
-
astTree = parseModule(tokens.result
|
|
123
|
+
astTree = parseModule(tokens.result);
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
return {
|
package/src/literals.ts
CHANGED
|
@@ -1,17 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
for (let i = 0; i < parts.length; ++i) {
|
|
7
|
-
const part = parts[i]!.replace(/\\(\r\n|\n|\r)/g, "\\n")
|
|
8
|
-
// Escape unescaped double quotes which can appear in a single-quoted
|
|
9
|
-
// string literal.
|
|
10
|
-
.replace(/(?<=^|[^\\])"/g, '\\"');
|
|
11
|
-
parts[i] = JSON.parse(`"${part}"`);
|
|
12
|
-
}
|
|
13
|
-
return parts.join("\\");
|
|
14
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
unquoteAndUnescape,
|
|
3
|
+
type DenseJson,
|
|
4
|
+
type Primitive,
|
|
5
|
+
} from "skir-internal";
|
|
15
6
|
|
|
16
7
|
export function valueHasPrimitiveType(
|
|
17
8
|
token: string,
|