volar-service-css 0.0.30 → 0.0.31
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/index.d.ts +16 -5
- package/index.js +206 -104
- package/package.json +5 -5
package/index.d.ts
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
|
-
import type { ServicePlugin } from '@volar/language-service';
|
|
1
|
+
import type { Disposable, DocumentSelector, Result, ServiceContext, ServicePlugin } from '@volar/language-service';
|
|
2
2
|
import * as css from 'vscode-css-languageservice';
|
|
3
|
-
import
|
|
3
|
+
import { TextDocument } from 'vscode-languageserver-textdocument';
|
|
4
4
|
export interface Provide {
|
|
5
|
-
'css/stylesheet': (document: TextDocument) => css.Stylesheet
|
|
6
|
-
'css/languageService': (
|
|
5
|
+
'css/stylesheet': (document: TextDocument, ls: css.LanguageService) => css.Stylesheet;
|
|
6
|
+
'css/languageService': (document: TextDocument) => css.LanguageService | undefined;
|
|
7
7
|
}
|
|
8
|
-
export declare function create(
|
|
8
|
+
export declare function create({ cssDocumentSelector, scssDocumentSelector, lessDocumentSelector, useDefaultDataProvider, getDocumentContext, isFormattingEnabled, getFormatConfiguration, getLanguageSettings, getCustomData, onDidChangeCustomData, }?: {
|
|
9
|
+
cssDocumentSelector?: DocumentSelector;
|
|
10
|
+
scssDocumentSelector?: DocumentSelector;
|
|
11
|
+
lessDocumentSelector?: DocumentSelector;
|
|
12
|
+
useDefaultDataProvider?: boolean;
|
|
13
|
+
getDocumentContext?(context: ServiceContext): css.DocumentContext;
|
|
14
|
+
isFormattingEnabled?(document: TextDocument, context: ServiceContext): Result<boolean>;
|
|
15
|
+
getFormatConfiguration?(document: TextDocument, context: ServiceContext): Result<css.CSSFormatConfiguration | undefined>;
|
|
16
|
+
getLanguageSettings?(document: TextDocument, context: ServiceContext): Result<css.LanguageSettings | undefined>;
|
|
17
|
+
getCustomData?(context: ServiceContext): Result<css.ICSSDataProvider[]>;
|
|
18
|
+
onDidChangeCustomData?(listener: () => void, context: ServiceContext): Disposable;
|
|
19
|
+
}): ServicePlugin;
|
|
9
20
|
//# sourceMappingURL=index.d.ts.map
|
package/index.js
CHANGED
|
@@ -2,70 +2,88 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.create = void 0;
|
|
4
4
|
const css = require("vscode-css-languageservice");
|
|
5
|
+
const vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument");
|
|
5
6
|
const vscode_uri_1 = require("vscode-uri");
|
|
6
|
-
function create(
|
|
7
|
+
function create({ cssDocumentSelector = ['css'], scssDocumentSelector = ['scss'], lessDocumentSelector = ['less'], useDefaultDataProvider = true, getDocumentContext = context => {
|
|
8
|
+
return {
|
|
9
|
+
resolveReference(ref, base) {
|
|
10
|
+
if (ref.match(/^\w[\w\d+.-]*:/)) {
|
|
11
|
+
// starts with a schema
|
|
12
|
+
return ref;
|
|
13
|
+
}
|
|
14
|
+
if (ref[0] === '/') { // resolve absolute path against the current workspace folder
|
|
15
|
+
let folderUri = context.env.workspaceFolder;
|
|
16
|
+
if (!folderUri.endsWith('/')) {
|
|
17
|
+
folderUri += '/';
|
|
18
|
+
}
|
|
19
|
+
return folderUri + ref.substring(1);
|
|
20
|
+
}
|
|
21
|
+
const baseUri = vscode_uri_1.URI.parse(base);
|
|
22
|
+
const baseUriDir = baseUri.path.endsWith('/') ? baseUri : vscode_uri_1.Utils.dirname(baseUri);
|
|
23
|
+
return vscode_uri_1.Utils.resolvePath(baseUriDir, ref).toString(true);
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}, isFormattingEnabled = async (document, context) => {
|
|
27
|
+
return await context.env.getConfiguration?.(document.languageId + '.format.enable') ?? true;
|
|
28
|
+
}, getFormatConfiguration = async (document, context) => {
|
|
29
|
+
return await context.env.getConfiguration?.(document.languageId + '.format');
|
|
30
|
+
}, getLanguageSettings = async (document, context) => {
|
|
31
|
+
return await context.env.getConfiguration?.(document.languageId);
|
|
32
|
+
}, getCustomData = async (context) => {
|
|
33
|
+
const customData = await context.env.getConfiguration?.('css.customData') ?? [];
|
|
34
|
+
const newData = [];
|
|
35
|
+
for (const customDataPath of customData) {
|
|
36
|
+
const uri = vscode_uri_1.Utils.resolvePath(vscode_uri_1.URI.parse(context.env.workspaceFolder), customDataPath);
|
|
37
|
+
const json = await context.env.fs?.readFile?.(uri.toString());
|
|
38
|
+
if (json) {
|
|
39
|
+
try {
|
|
40
|
+
const data = JSON.parse(json);
|
|
41
|
+
newData.push(css.newCSSDataProvider(data));
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
console.error(error);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return newData;
|
|
49
|
+
}, onDidChangeCustomData = (listener, context) => {
|
|
50
|
+
const disposable = context.env.onDidChangeConfiguration?.(listener);
|
|
51
|
+
return {
|
|
52
|
+
dispose() {
|
|
53
|
+
disposable?.dispose();
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}, } = {}) {
|
|
7
57
|
return {
|
|
8
58
|
name: 'css',
|
|
9
59
|
// https://github.com/microsoft/vscode/blob/09850876e652688fb142e2e19fd00fd38c0bc4ba/extensions/css-language-features/server/src/cssServer.ts#L97
|
|
10
60
|
triggerCharacters: ['/', '-', ':'],
|
|
11
61
|
create(context) {
|
|
12
|
-
let inited = false;
|
|
13
62
|
const stylesheets = new WeakMap();
|
|
14
63
|
const fileSystemProvider = {
|
|
15
|
-
stat: async (uri) => await context.env.fs?.stat(uri)
|
|
16
|
-
type: css.FileType.Unknown,
|
|
17
|
-
ctime: 0,
|
|
18
|
-
mtime: 0,
|
|
19
|
-
size: 0,
|
|
20
|
-
},
|
|
64
|
+
stat: async (uri) => await context.env.fs?.stat(uri)
|
|
65
|
+
?? { type: css.FileType.Unknown, ctime: 0, mtime: 0, size: 0 },
|
|
21
66
|
readDirectory: async (uri) => await context.env.fs?.readDirectory(uri) ?? [],
|
|
22
67
|
};
|
|
23
|
-
const documentContext =
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return base + ref;
|
|
31
|
-
}
|
|
32
|
-
const baseUri = vscode_uri_1.URI.parse(base);
|
|
33
|
-
const baseUriDir = baseUri.path.endsWith('/') ? baseUri : vscode_uri_1.Utils.dirname(baseUri);
|
|
34
|
-
return vscode_uri_1.Utils.resolvePath(baseUriDir, ref).toString(true);
|
|
35
|
-
},
|
|
36
|
-
};
|
|
37
|
-
const cssLs = css.getCSSLanguageService({
|
|
38
|
-
fileSystemProvider,
|
|
39
|
-
clientCapabilities: context.env.clientCapabilities,
|
|
40
|
-
});
|
|
41
|
-
const scssLs = css.getSCSSLanguageService({
|
|
42
|
-
fileSystemProvider,
|
|
43
|
-
clientCapabilities: context.env.clientCapabilities,
|
|
44
|
-
});
|
|
45
|
-
const lessLs = css.getLESSLanguageService({
|
|
46
|
-
fileSystemProvider,
|
|
47
|
-
clientCapabilities: context.env.clientCapabilities,
|
|
48
|
-
});
|
|
49
|
-
const postcssLs = {
|
|
50
|
-
...scssLs,
|
|
51
|
-
doValidation: (document, stylesheet, documentSettings) => {
|
|
52
|
-
let errors = scssLs.doValidation(document, stylesheet, documentSettings);
|
|
53
|
-
errors = errors.filter(error => error.code !== 'css-semicolonexpected');
|
|
54
|
-
errors = errors.filter(error => error.code !== 'css-ruleorselectorexpected');
|
|
55
|
-
errors = errors.filter(error => error.code !== 'unknownAtRules');
|
|
56
|
-
return errors;
|
|
57
|
-
},
|
|
58
|
-
};
|
|
68
|
+
const documentContext = getDocumentContext(context);
|
|
69
|
+
const disposable = onDidChangeCustomData(() => initializing = undefined, context);
|
|
70
|
+
let cssLs;
|
|
71
|
+
let scssLs;
|
|
72
|
+
let lessLs;
|
|
73
|
+
let customData = [];
|
|
74
|
+
let initializing;
|
|
59
75
|
return {
|
|
76
|
+
dispose() {
|
|
77
|
+
disposable.dispose();
|
|
78
|
+
},
|
|
60
79
|
provide: {
|
|
61
80
|
'css/stylesheet': getStylesheet,
|
|
62
81
|
'css/languageService': getCssLs,
|
|
63
82
|
},
|
|
64
83
|
async provideCompletionItems(document, position) {
|
|
65
84
|
return worker(document, async (stylesheet, cssLs) => {
|
|
66
|
-
const settings = await
|
|
67
|
-
|
|
68
|
-
return cssResult;
|
|
85
|
+
const settings = await getLanguageSettings(document, context);
|
|
86
|
+
return await cssLs.doComplete2(document, position, stylesheet, documentContext, settings?.completion);
|
|
69
87
|
});
|
|
70
88
|
},
|
|
71
89
|
provideRenameRange(document, position) {
|
|
@@ -97,13 +115,13 @@ function create() {
|
|
|
97
115
|
},
|
|
98
116
|
async provideDiagnostics(document) {
|
|
99
117
|
return worker(document, async (stylesheet, cssLs) => {
|
|
100
|
-
const settings = await
|
|
118
|
+
const settings = await getLanguageSettings(document, context);
|
|
101
119
|
return cssLs.doValidation(document, stylesheet, settings);
|
|
102
120
|
});
|
|
103
121
|
},
|
|
104
122
|
async provideHover(document, position) {
|
|
105
123
|
return worker(document, async (stylesheet, cssLs) => {
|
|
106
|
-
const settings = await
|
|
124
|
+
const settings = await getLanguageSettings(document, context);
|
|
107
125
|
return cssLs.doHover(document, position, stylesheet, settings?.hover);
|
|
108
126
|
});
|
|
109
127
|
},
|
|
@@ -138,8 +156,8 @@ function create() {
|
|
|
138
156
|
});
|
|
139
157
|
},
|
|
140
158
|
provideFoldingRanges(document) {
|
|
141
|
-
return worker(document, (
|
|
142
|
-
return cssLs.getFoldingRanges(document,
|
|
159
|
+
return worker(document, (_stylesheet, cssLs) => {
|
|
160
|
+
return cssLs.getFoldingRanges(document, context.env.clientCapabilities?.textDocument?.foldingRange);
|
|
143
161
|
});
|
|
144
162
|
},
|
|
145
163
|
provideSelectionRanges(document, positions) {
|
|
@@ -147,59 +165,142 @@ function create() {
|
|
|
147
165
|
return cssLs.getSelectionRanges(document, positions, stylesheet);
|
|
148
166
|
});
|
|
149
167
|
},
|
|
150
|
-
async provideDocumentFormattingEdits(document, formatRange, options) {
|
|
168
|
+
async provideDocumentFormattingEdits(document, formatRange, options, codeOptions) {
|
|
151
169
|
return worker(document, async (_stylesheet, cssLs) => {
|
|
152
|
-
|
|
153
|
-
if (options_2?.enable === false) {
|
|
170
|
+
if (!await isFormattingEnabled(document, context)) {
|
|
154
171
|
return;
|
|
155
172
|
}
|
|
156
|
-
|
|
157
|
-
|
|
173
|
+
const formatSettings = await getFormatConfiguration(document, context);
|
|
174
|
+
const formatOptions = {
|
|
158
175
|
...options,
|
|
159
|
-
|
|
176
|
+
...formatSettings,
|
|
177
|
+
};
|
|
178
|
+
let formatDocument = document;
|
|
179
|
+
let prefixes = [];
|
|
180
|
+
let suffixes = [];
|
|
181
|
+
if (codeOptions?.initialIndentLevel) {
|
|
182
|
+
for (let i = 0; i < codeOptions.initialIndentLevel; i++) {
|
|
183
|
+
if (i === codeOptions.initialIndentLevel - 1) {
|
|
184
|
+
prefixes.push('_', '{');
|
|
185
|
+
suffixes.unshift('}');
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
prefixes.push('_', '{\n');
|
|
189
|
+
suffixes.unshift('\n}');
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
formatDocument = vscode_languageserver_textdocument_1.TextDocument.create(document.uri, document.languageId, document.version, prefixes.join('') + document.getText() + suffixes.join(''));
|
|
193
|
+
formatRange = {
|
|
194
|
+
start: formatDocument.positionAt(0),
|
|
195
|
+
end: formatDocument.positionAt(formatDocument.getText().length),
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
let edits = cssLs.format(formatDocument, formatRange, formatOptions);
|
|
199
|
+
if (codeOptions) {
|
|
200
|
+
let newText = vscode_languageserver_textdocument_1.TextDocument.applyEdits(formatDocument, edits);
|
|
201
|
+
for (const prefix of prefixes) {
|
|
202
|
+
newText = newText.trimStart().slice(prefix.trim().length);
|
|
203
|
+
}
|
|
204
|
+
for (const suffix of suffixes.reverse()) {
|
|
205
|
+
newText = newText.trimEnd().slice(0, -suffix.trim().length);
|
|
206
|
+
}
|
|
207
|
+
if (!codeOptions.initialIndentLevel && codeOptions.level > 0) {
|
|
208
|
+
newText = ensureNewLines(newText);
|
|
209
|
+
}
|
|
210
|
+
edits = [{
|
|
211
|
+
range: {
|
|
212
|
+
start: document.positionAt(0),
|
|
213
|
+
end: document.positionAt(document.getText().length),
|
|
214
|
+
},
|
|
215
|
+
newText,
|
|
216
|
+
}];
|
|
217
|
+
}
|
|
218
|
+
return edits;
|
|
219
|
+
function ensureNewLines(newText) {
|
|
220
|
+
const verifyDocument = vscode_languageserver_textdocument_1.TextDocument.create(document.uri, document.languageId, document.version, '_ {' + newText + '}');
|
|
221
|
+
const verifyEdits = cssLs.format(verifyDocument, undefined, formatOptions);
|
|
222
|
+
let verifyText = vscode_languageserver_textdocument_1.TextDocument.applyEdits(verifyDocument, verifyEdits);
|
|
223
|
+
verifyText = verifyText.trimStart().slice('_'.length);
|
|
224
|
+
verifyText = verifyText.trim().slice('{'.length, -'}'.length);
|
|
225
|
+
if (startWithNewLine(verifyText) !== startWithNewLine(newText)) {
|
|
226
|
+
if (startWithNewLine(verifyText)) {
|
|
227
|
+
newText = '\n' + newText;
|
|
228
|
+
}
|
|
229
|
+
else if (newText.startsWith('\n')) {
|
|
230
|
+
newText = newText.slice(1);
|
|
231
|
+
}
|
|
232
|
+
else if (newText.startsWith('\r\n')) {
|
|
233
|
+
newText = newText.slice(2);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (endWithNewLine(verifyText) !== endWithNewLine(newText)) {
|
|
237
|
+
if (endWithNewLine(verifyText)) {
|
|
238
|
+
newText = newText + '\n';
|
|
239
|
+
}
|
|
240
|
+
else if (newText.endsWith('\n')) {
|
|
241
|
+
newText = newText.slice(0, -1);
|
|
242
|
+
}
|
|
243
|
+
else if (newText.endsWith('\r\n')) {
|
|
244
|
+
newText = newText.slice(0, -2);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return newText;
|
|
248
|
+
}
|
|
249
|
+
function startWithNewLine(text) {
|
|
250
|
+
return text.startsWith('\n') || text.startsWith('\r\n');
|
|
251
|
+
}
|
|
252
|
+
function endWithNewLine(text) {
|
|
253
|
+
return text.endsWith('\n') || text.endsWith('\r\n');
|
|
254
|
+
}
|
|
160
255
|
});
|
|
161
256
|
},
|
|
162
257
|
};
|
|
163
|
-
|
|
164
|
-
if (
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
inited = true;
|
|
258
|
+
function getCssLs(document) {
|
|
259
|
+
if (matchDocument(cssDocumentSelector, document)) {
|
|
260
|
+
if (!cssLs) {
|
|
261
|
+
cssLs = css.getCSSLanguageService({
|
|
262
|
+
fileSystemProvider,
|
|
263
|
+
clientCapabilities: context.env.clientCapabilities,
|
|
264
|
+
useDefaultDataProvider,
|
|
265
|
+
customDataProviders: customData,
|
|
266
|
+
});
|
|
267
|
+
cssLs.setDataProviders(useDefaultDataProvider, customData);
|
|
268
|
+
}
|
|
269
|
+
return cssLs;
|
|
176
270
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
newData.push(css.newCSSDataProvider(require(jsonPath)));
|
|
271
|
+
else if (matchDocument(scssDocumentSelector, document)) {
|
|
272
|
+
if (!scssLs) {
|
|
273
|
+
scssLs = css.getSCSSLanguageService({
|
|
274
|
+
fileSystemProvider,
|
|
275
|
+
clientCapabilities: context.env.clientCapabilities,
|
|
276
|
+
useDefaultDataProvider,
|
|
277
|
+
customDataProviders: customData,
|
|
278
|
+
});
|
|
279
|
+
scssLs.setDataProviders(useDefaultDataProvider, customData);
|
|
187
280
|
}
|
|
188
|
-
|
|
189
|
-
|
|
281
|
+
return scssLs;
|
|
282
|
+
}
|
|
283
|
+
else if (matchDocument(lessDocumentSelector, document)) {
|
|
284
|
+
if (!lessLs) {
|
|
285
|
+
lessLs = css.getLESSLanguageService({
|
|
286
|
+
fileSystemProvider,
|
|
287
|
+
clientCapabilities: context.env.clientCapabilities,
|
|
288
|
+
useDefaultDataProvider,
|
|
289
|
+
customDataProviders: customData,
|
|
290
|
+
});
|
|
291
|
+
lessLs.setDataProviders(useDefaultDataProvider, customData);
|
|
190
292
|
}
|
|
293
|
+
return lessLs;
|
|
191
294
|
}
|
|
192
|
-
return newData;
|
|
193
295
|
}
|
|
194
|
-
function
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
296
|
+
async function worker(document, callback) {
|
|
297
|
+
const cssLs = getCssLs(document);
|
|
298
|
+
if (!cssLs)
|
|
299
|
+
return;
|
|
300
|
+
await (initializing ??= initialize());
|
|
301
|
+
return callback(getStylesheet(document, cssLs), cssLs);
|
|
201
302
|
}
|
|
202
|
-
function getStylesheet(document) {
|
|
303
|
+
function getStylesheet(document, ls) {
|
|
203
304
|
const cache = stylesheets.get(document);
|
|
204
305
|
if (cache) {
|
|
205
306
|
const [cacheVersion, cacheStylesheet] = cache;
|
|
@@ -207,25 +308,26 @@ function create() {
|
|
|
207
308
|
return cacheStylesheet;
|
|
208
309
|
}
|
|
209
310
|
}
|
|
210
|
-
const
|
|
211
|
-
if (!cssLs)
|
|
212
|
-
return;
|
|
213
|
-
const stylesheet = cssLs.parseStylesheet(document);
|
|
311
|
+
const stylesheet = ls.parseStylesheet(document);
|
|
214
312
|
stylesheets.set(document, [document.version, stylesheet]);
|
|
215
313
|
return stylesheet;
|
|
216
314
|
}
|
|
217
|
-
async function
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
if (!cssLs)
|
|
223
|
-
return;
|
|
224
|
-
await initCustomData();
|
|
225
|
-
return callback(stylesheet, cssLs);
|
|
315
|
+
async function initialize() {
|
|
316
|
+
customData = await getCustomData(context);
|
|
317
|
+
cssLs?.setDataProviders(useDefaultDataProvider, customData);
|
|
318
|
+
scssLs?.setDataProviders(useDefaultDataProvider, customData);
|
|
319
|
+
lessLs?.setDataProviders(useDefaultDataProvider, customData);
|
|
226
320
|
}
|
|
227
321
|
},
|
|
228
322
|
};
|
|
229
323
|
}
|
|
230
324
|
exports.create = create;
|
|
325
|
+
function matchDocument(selector, document) {
|
|
326
|
+
for (const sel of selector) {
|
|
327
|
+
if (sel === document.languageId || (typeof sel === 'object' && sel.language === document.languageId)) {
|
|
328
|
+
return true;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
231
333
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "volar-service-css",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.31",
|
|
4
4
|
"description": "Integrate vscode-css-languageservice into Volar",
|
|
5
5
|
"homepage": "https://github.com/volarjs/services/tree/master/packages/css",
|
|
6
6
|
"bugs": "https://github.com/volarjs/services/issues",
|
|
@@ -25,19 +25,19 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"vscode-css-languageservice": "^6.2.10",
|
|
28
|
+
"vscode-languageserver-textdocument": "^1.0.11",
|
|
28
29
|
"vscode-uri": "^3.0.8"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
|
31
|
-
"@types/node": "latest"
|
|
32
|
-
"vscode-languageserver-textdocument": "^1.0.11"
|
|
32
|
+
"@types/node": "latest"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@volar/language-service": "~2.0
|
|
35
|
+
"@volar/language-service": "~2.1.0"
|
|
36
36
|
},
|
|
37
37
|
"peerDependenciesMeta": {
|
|
38
38
|
"@volar/language-service": {
|
|
39
39
|
"optional": true
|
|
40
40
|
}
|
|
41
41
|
},
|
|
42
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "f7005aef724767786ee9fe943fa976231cc79bf1"
|
|
43
43
|
}
|