@elice/material-exercise 1.220913.0 → 1.220919.0

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.
Files changed (87) hide show
  1. package/cjs/components/material-exercise/MaterialExercise.styled.js +1 -1
  2. package/cjs/components/material-exercise/exercise-menu/ExerciseMenuDropdown.js +9 -1
  3. package/cjs/components/material-exercise/exercise-runner/ExerciseRunner.js +5 -1
  4. package/cjs/components/shared/monaco-editor/MonacoEditor.js +9 -9
  5. package/cjs/components/shared/monaco-editor/editor-hooks/useMonacoMarkers.js +3 -3
  6. package/cjs/components/shared/monaco-editor/editor-languages/css/index.d.ts +4 -0
  7. package/cjs/components/shared/monaco-editor/editor-languages/css/index.js +12 -0
  8. package/cjs/components/shared/monaco-editor/editor-languages/html/index.d.ts +4 -0
  9. package/cjs/components/shared/monaco-editor/editor-languages/html/index.js +10 -0
  10. package/cjs/components/shared/monaco-editor/editor-languages/index.js +2 -2
  11. package/cjs/components/shared/monaco-editor/editor-languages/typescript/index.d.ts +4 -0
  12. package/cjs/components/shared/monaco-editor/editor-languages/typescript/index.js +10 -0
  13. package/cjs/components/shared/monaco-editor/utils/emmet/emmet.d.ts +13 -0
  14. package/cjs/components/shared/monaco-editor/utils/emmet/emmet.js +31 -0
  15. package/cjs/components/shared/monaco-editor/utils/emmet/index.d.ts +1 -0
  16. package/cjs/components/shared/monaco-editor/utils/emmet/registerProvider.d.ts +5 -0
  17. package/cjs/components/shared/monaco-editor/utils/emmet/registerProvider.js +26 -0
  18. package/cjs/components/shared/monaco-editor/utils/grammar/index.js +2 -2
  19. package/cjs/components/shared/monaco-editor/utils/prettier/index.js +6 -2
  20. package/cjs/components/shared/monaco-editor/vendors/vscode-emmet-helper/configCompat.d.ts +15 -0
  21. package/cjs/components/shared/monaco-editor/vendors/vscode-emmet-helper/configCompat.js +15 -0
  22. package/cjs/components/shared/monaco-editor/vendors/vscode-emmet-helper/data.d.ts +6 -0
  23. package/cjs/components/shared/monaco-editor/vendors/vscode-emmet-helper/data.js +22 -0
  24. package/cjs/components/shared/monaco-editor/vendors/vscode-emmet-helper/emmetHelper.d.ts +96 -0
  25. package/cjs/components/shared/monaco-editor/vendors/vscode-emmet-helper/emmetHelper.js +900 -0
  26. package/cjs/components/shared/monaco-editor/vendors/vscode-emmet-helper/index.d.ts +2 -0
  27. package/cjs/components/shared/monaco-editor/vendors/vscode-emmet-helper/utils.d.ts +12 -0
  28. package/cjs/components/shared/monaco-editor/vendors/vscode-emmet-helper/utils.js +42 -0
  29. package/cjs/components/shared/xterm/Xterm.js +10 -3
  30. package/es/components/material-exercise/MaterialExercise.styled.js +1 -1
  31. package/es/components/material-exercise/exercise-menu/ExerciseMenuDropdown.js +10 -2
  32. package/es/components/material-exercise/exercise-runner/ExerciseRunner.js +5 -1
  33. package/es/components/shared/monaco-editor/MonacoEditor.js +11 -11
  34. package/es/components/shared/monaco-editor/editor-hooks/useMonacoMarkers.js +3 -3
  35. package/es/components/shared/monaco-editor/editor-languages/css/index.d.ts +4 -0
  36. package/es/components/shared/monaco-editor/editor-languages/css/index.js +12 -1
  37. package/es/components/shared/monaco-editor/editor-languages/html/index.d.ts +4 -0
  38. package/es/components/shared/monaco-editor/editor-languages/html/index.js +10 -1
  39. package/es/components/shared/monaco-editor/editor-languages/index.js +2 -2
  40. package/es/components/shared/monaco-editor/editor-languages/typescript/index.d.ts +4 -0
  41. package/es/components/shared/monaco-editor/editor-languages/typescript/index.js +10 -1
  42. package/es/components/shared/monaco-editor/utils/emmet/emmet.d.ts +13 -0
  43. package/es/components/shared/monaco-editor/utils/emmet/emmet.js +25 -0
  44. package/es/components/shared/monaco-editor/utils/emmet/index.d.ts +1 -0
  45. package/es/components/shared/monaco-editor/utils/emmet/registerProvider.d.ts +5 -0
  46. package/es/components/shared/monaco-editor/utils/emmet/registerProvider.js +22 -0
  47. package/es/components/shared/monaco-editor/utils/grammar/index.js +2 -2
  48. package/es/components/shared/monaco-editor/utils/prettier/index.js +6 -2
  49. package/es/components/shared/monaco-editor/vendors/vscode-emmet-helper/configCompat.d.ts +15 -0
  50. package/es/components/shared/monaco-editor/vendors/vscode-emmet-helper/configCompat.js +11 -0
  51. package/es/components/shared/monaco-editor/vendors/vscode-emmet-helper/data.d.ts +6 -0
  52. package/es/components/shared/monaco-editor/vendors/vscode-emmet-helper/data.js +17 -0
  53. package/es/components/shared/monaco-editor/vendors/vscode-emmet-helper/emmetHelper.d.ts +96 -0
  54. package/es/components/shared/monaco-editor/vendors/vscode-emmet-helper/emmetHelper.js +883 -0
  55. package/es/components/shared/monaco-editor/vendors/vscode-emmet-helper/index.d.ts +2 -0
  56. package/es/components/shared/monaco-editor/vendors/vscode-emmet-helper/utils.d.ts +12 -0
  57. package/es/components/shared/monaco-editor/vendors/vscode-emmet-helper/utils.js +36 -0
  58. package/es/components/shared/xterm/Xterm.js +10 -3
  59. package/package.json +7 -6
  60. /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/OnDisposed.d.ts +0 -0
  61. /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursor.d.ts +0 -0
  62. /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursor.js +0 -0
  63. /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursorManager.d.ts +0 -0
  64. /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursorManager.js +0 -0
  65. /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursorWidget.d.ts +0 -0
  66. /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursorWidget.js +0 -0
  67. /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteSelection.d.ts +0 -0
  68. /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteSelection.js +0 -0
  69. /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteSelectionManager.d.ts +0 -0
  70. /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteSelectionManager.js +0 -0
  71. /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/index.d.ts +0 -0
  72. /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/styles.d.ts +0 -0
  73. /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/styles.js +0 -0
  74. /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/OnDisposed.d.ts +0 -0
  75. /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursor.d.ts +0 -0
  76. /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursor.js +0 -0
  77. /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursorManager.d.ts +0 -0
  78. /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursorManager.js +0 -0
  79. /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursorWidget.d.ts +0 -0
  80. /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursorWidget.js +0 -0
  81. /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteSelection.d.ts +0 -0
  82. /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteSelection.js +0 -0
  83. /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteSelectionManager.d.ts +0 -0
  84. /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteSelectionManager.js +0 -0
  85. /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/index.d.ts +0 -0
  86. /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/styles.d.ts +0 -0
  87. /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/styles.js +0 -0
@@ -0,0 +1,883 @@
1
+ import expand, { resolveConfig, extract } from 'emmet';
2
+ import { cssData, htmlData } from './data.js';
3
+ import { syntaxes } from './configCompat.js';
4
+
5
+ /* ====================================================================================================
6
+ * These codes forked and modified from `microsoft/vscode-emmet-helper`
7
+ * under the terms of the MIT license.
8
+ * Make sure to check the original project if any issue exists.
9
+ * - project: https://github.com/microsoft/vscode-emmet-helper
10
+ * - codes: https://github.com/microsoft/vscode-emmet-helper/blob/e64481648451f0189216794979ce2ace82ee8148/src/emmetHelper.ts
11
+ * ==================================================================================================== */
12
+ // @emmetio/extract-abbreviation has a cjs that uses a default export
13
+ // */
14
+ // const extract = typeof _extractAbbreviation === 'function' ? _extractAbbreviation : _extractAbbreviation.default;
15
+
16
+ const snippetKeyCache = new Map();
17
+ let markupSnippetKeys;
18
+ const stylesheetCustomSnippetsKeyCache = new Map();
19
+ const htmlAbbreviationStartRegex = /^[a-z,A-Z,!,(,[,#,\.\{]/; // take off { for jsx because it interferes with the language
20
+
21
+ const jsxAbbreviationStartRegex = /^[a-z,A-Z,!,(,[,#,\.]/;
22
+ const cssAbbreviationRegex = /^-?[a-z,A-Z,!,@,#]/;
23
+ const htmlAbbreviationRegex = /[a-z,A-Z\.]/;
24
+ const commonlyUsedTags = [...htmlData.tags, 'lorem'];
25
+ const bemFilterSuffix = 'bem';
26
+ const filterDelimitor = '|';
27
+ const trimFilterSuffix = 't';
28
+ const commentFilterSuffix = 'c';
29
+ const maxFilters = 3;
30
+ /**
31
+ * Returns all applicable emmet expansions for abbreviation at given position in a CompletionList
32
+ * @param document TextDocument in which completions are requested
33
+ * @param position Position in the document at which completions are requested
34
+ * @param syntax Emmet supported language
35
+ * @param emmetConfig Emmet Configurations as derived from VS Code
36
+ */
37
+
38
+ function doComplete(monaco, model, position, syntax, emmetConfig) {
39
+ var _a, _b;
40
+
41
+ if (emmetConfig.showExpandedAbbreviation === 'never' || !getEmmetMode(syntax, emmetConfig.excludeLanguages)) {
42
+ return;
43
+ }
44
+
45
+ const isStyleSheetRes = isStyleSheet(syntax); // Fetch markupSnippets so that we can provide possible abbreviation completions
46
+ // For example, when text at position is `a`, completions should return `a:blank`, `a:link`, `acr` etc.
47
+
48
+ if (!isStyleSheetRes) {
49
+ if (!snippetKeyCache.has(syntax)) {
50
+ const registry = (_a = customSnippetsRegistry[syntax]) !== null && _a !== void 0 ? _a : getDefaultSnippets(syntax);
51
+ snippetKeyCache.set(syntax, Object.keys(registry));
52
+ }
53
+
54
+ markupSnippetKeys = (_b = snippetKeyCache.get(syntax)) !== null && _b !== void 0 ? _b : [];
55
+ }
56
+
57
+ const extractOptions = {
58
+ lookAhead: !isStyleSheetRes,
59
+ type: isStyleSheetRes ? 'stylesheet' : 'markup'
60
+ };
61
+ const extractedValue = extractAbbreviation(monaco, model, position, extractOptions);
62
+
63
+ if (!extractedValue) {
64
+ return;
65
+ }
66
+
67
+ const {
68
+ abbreviationRange,
69
+ abbreviation,
70
+ filter
71
+ } = extractedValue;
72
+ const currentLineTillPosition = getCurrentLine(model, position).substr(0, position.column - 1);
73
+ const currentWord = getCurrentWord(currentLineTillPosition); // Don't attempt to expand open tags
74
+
75
+ if (currentWord === abbreviation && currentLineTillPosition.endsWith(`<${abbreviation}`) && syntaxes.markup.includes(syntax)) {
76
+ return;
77
+ }
78
+
79
+ const expandOptions = getExpandOptions(syntax, emmetConfig, filter);
80
+ let expandedText = "";
81
+ let expandedAbbr;
82
+ let completionItems = []; // Create completion item after expanding given abbreviation
83
+ // if abbreviation is valid and expanded value is not noise
84
+
85
+ const createExpandedAbbr = (syntax, abbr) => {
86
+ if (!isAbbreviationValid(syntax, abbreviation)) {
87
+ return;
88
+ }
89
+
90
+ try {
91
+ expandedText = expand(abbr, expandOptions); // manually patch https://github.com/microsoft/vscode/issues/120245 for now
92
+
93
+ if (isStyleSheetRes && '!important'.startsWith(abbr)) {
94
+ expandedText = '!important';
95
+ }
96
+ } catch (e) {}
97
+
98
+ if (!expandedText || isExpandedTextNoise(syntax, abbr, expandedText, expandOptions.options)) {
99
+ return;
100
+ }
101
+
102
+ expandedAbbr = {
103
+ kind: monaco.languages.CompletionItemKind.Property,
104
+ label: abbreviation + (filter ? '|' + filter.replace(',', '|') : ''),
105
+ documentation: replaceTabStopsWithCursors(expandedText),
106
+ detail: 'Emmet abbreviation',
107
+ insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
108
+ range: abbreviationRange,
109
+ insertText: escapeNonTabStopDollar(addFinalTabStop(expandedText))
110
+ };
111
+ completionItems = [expandedAbbr];
112
+ };
113
+
114
+ if (isStyleSheet(syntax)) {
115
+ createExpandedAbbr(syntax, abbreviation); // When abbr is longer than usual emmet snippets and matches better with existing css property, then no emmet
116
+
117
+ if (abbreviation.length > 4 && cssData.properties.find(x => x.startsWith(abbreviation))) {
118
+ return {
119
+ suggestions: [],
120
+ incomplete: true
121
+ };
122
+ }
123
+
124
+ if (expandedAbbr && expandedText.length) {
125
+ expandedAbbr.range = abbreviationRange;
126
+ expandedAbbr.insertText = escapeNonTabStopDollar(addFinalTabStop(expandedText));
127
+ expandedAbbr.documentation = replaceTabStopsWithCursors(expandedText);
128
+ expandedAbbr.label = removeTabStops(expandedText);
129
+ expandedAbbr.filterText = abbreviation; // Custom snippets should show up in completions if abbreviation is a prefix
130
+
131
+ const stylesheetCustomSnippetsKeys = stylesheetCustomSnippetsKeyCache.has(syntax) ? stylesheetCustomSnippetsKeyCache.get(syntax) : stylesheetCustomSnippetsKeyCache.get('css');
132
+ completionItems = makeSnippetSuggestion(monaco, stylesheetCustomSnippetsKeys !== null && stylesheetCustomSnippetsKeys !== void 0 ? stylesheetCustomSnippetsKeys : [], abbreviation, abbreviation, abbreviationRange, expandOptions, 'Emmet Custom Snippet', false);
133
+
134
+ if (!completionItems.find(x => x.insertText === (expandedAbbr === null || expandedAbbr === void 0 ? void 0 : expandedAbbr.insertText))) {
135
+ // Fix for https://github.com/Microsoft/vscode/issues/28933#issuecomment-309236902
136
+ // When user types in propertyname, emmet uses it to match with snippet names, resulting in width -> widows or font-family -> font: family
137
+ // Filter out those cases here.
138
+ const abbrRegex = new RegExp('.*' + abbreviation.split('').map(x => x === '$' || x === '+' ? '\\' + x : x).join('.*') + '.*', 'i');
139
+
140
+ if (/\d/.test(abbreviation) || abbrRegex.test(expandedAbbr.label)) {
141
+ completionItems.push(expandedAbbr);
142
+ }
143
+ }
144
+ }
145
+ } else {
146
+ createExpandedAbbr(syntax, abbreviation);
147
+ let tagToFindMoreSuggestionsFor = abbreviation;
148
+ const newTagMatches = /(>|\+)([\w:-]+)$/.exec(abbreviation);
149
+
150
+ if (newTagMatches && newTagMatches.length === 3) {
151
+ tagToFindMoreSuggestionsFor = newTagMatches[2];
152
+ }
153
+
154
+ if (syntax !== 'xml') {
155
+ const commonlyUsedTagSuggestions = makeSnippetSuggestion(monaco, commonlyUsedTags, tagToFindMoreSuggestionsFor, abbreviation, abbreviationRange, expandOptions, 'Emmet Abbreviation');
156
+ completionItems = completionItems.concat(commonlyUsedTagSuggestions);
157
+ }
158
+
159
+ if (emmetConfig.showAbbreviationSuggestions === true) {
160
+ const abbreviationSuggestions = makeSnippetSuggestion(monaco, markupSnippetKeys.filter(x => !commonlyUsedTags.includes(x)), tagToFindMoreSuggestionsFor, abbreviation, abbreviationRange, expandOptions, 'Emmet Abbreviation'); // Workaround for the main expanded abbr not appearing before the snippet suggestions
161
+
162
+ if (expandedAbbr && abbreviationSuggestions.length > 0 && tagToFindMoreSuggestionsFor !== abbreviation) {
163
+ expandedAbbr.sortText = '0' + expandedAbbr.label;
164
+ abbreviationSuggestions.forEach(item => {
165
+ // Workaround for snippet suggestions items getting filtered out as the complete abbr does not start with snippetKey
166
+ item.filterText = abbreviation; // Workaround for the main expanded abbr not appearing before the snippet suggestions
167
+
168
+ item.sortText = '9' + abbreviation;
169
+ });
170
+ }
171
+
172
+ completionItems = completionItems.concat(abbreviationSuggestions);
173
+ } // https://github.com/microsoft/vscode/issues/66680
174
+
175
+
176
+ if (syntax === 'html' && completionItems.length >= 2 && abbreviation.includes(":") && (expandedAbbr === null || expandedAbbr === void 0 ? void 0 : expandedAbbr.insertText) === `<${abbreviation}>\${0}</${abbreviation}>`) {
177
+ completionItems = completionItems.filter(item => item.label !== abbreviation);
178
+ }
179
+ }
180
+
181
+ if (emmetConfig.showSuggestionsAsSnippets === true) {
182
+ completionItems.forEach(x => x.kind = monaco.languages.CompletionItemKind.Snippet);
183
+ }
184
+
185
+ return completionItems.length ? {
186
+ suggestions: completionItems,
187
+ incomplete: true
188
+ } : undefined;
189
+ }
190
+ /**
191
+ * Create & return snippets for snippet keys that start with given prefix
192
+ */
193
+
194
+ function makeSnippetSuggestion(monaco, snippetKeys, prefix, abbreviation, abbreviationRange, expandOptions, snippetDetail, skipFullMatch = true) {
195
+ if (!prefix || !snippetKeys) {
196
+ return [];
197
+ }
198
+
199
+ const snippetCompletions = [];
200
+ snippetKeys.forEach(snippetKey => {
201
+ if (!snippetKey.startsWith(prefix.toLowerCase()) || skipFullMatch && snippetKey === prefix.toLowerCase()) {
202
+ return;
203
+ }
204
+
205
+ const currentAbbr = abbreviation + snippetKey.substr(prefix.length);
206
+ let expandedAbbr;
207
+
208
+ try {
209
+ expandedAbbr = expand(currentAbbr, expandOptions);
210
+ } catch (e) {}
211
+
212
+ if (!expandedAbbr) {
213
+ return;
214
+ }
215
+
216
+ const item = {
217
+ kind: monaco.languages.CompletionItemKind.Property,
218
+ label: prefix + snippetKey.substr(prefix.length),
219
+ documentation: replaceTabStopsWithCursors(expandedAbbr),
220
+ detail: snippetDetail,
221
+ insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
222
+ range: abbreviationRange,
223
+ insertText: escapeNonTabStopDollar(addFinalTabStop(expandedAbbr))
224
+ };
225
+ snippetCompletions.push(item);
226
+ });
227
+ return snippetCompletions;
228
+ }
229
+
230
+ function getCurrentWord(currentLineTillPosition) {
231
+ if (currentLineTillPosition) {
232
+ const matches = /[\w,:,-,\.]*$/.exec(currentLineTillPosition);
233
+
234
+ if (matches) {
235
+ return matches[0];
236
+ }
237
+ }
238
+ }
239
+
240
+ function replaceTabStopsWithCursors(expandedWord) {
241
+ return expandedWord.replace(/([^\\])\$\{\d+\}/g, '$1|').replace(/\$\{\d+:([^\}]+)\}/g, '$1');
242
+ }
243
+
244
+ function removeTabStops(expandedWord) {
245
+ return expandedWord.replace(/([^\\])\$\{\d+\}/g, '$1').replace(/\$\{\d+:([^\}]+)\}/g, '$1');
246
+ }
247
+
248
+ function escapeNonTabStopDollar(text) {
249
+ return text ? text.replace(/([^\\])(\$)([^\{])/g, '$1\\$2$3') : text;
250
+ }
251
+
252
+ function addFinalTabStop(text) {
253
+ if (!text || !text.trim()) {
254
+ return text;
255
+ }
256
+
257
+ let maxTabStop = -1;
258
+ let maxTabStopRanges = [];
259
+ let foundLastStop = false;
260
+ let replaceWithLastStop = false;
261
+ let i = 0;
262
+ const n = text.length;
263
+
264
+ try {
265
+ while (i < n && !foundLastStop) {
266
+ // Look for ${
267
+ if (text[i++] != '$' || text[i++] != '{') {
268
+ continue;
269
+ } // Find tabstop
270
+
271
+
272
+ let numberStart = -1;
273
+ let numberEnd = -1;
274
+
275
+ while (i < n && /\d/.test(text[i])) {
276
+ numberStart = numberStart < 0 ? i : numberStart;
277
+ numberEnd = i + 1;
278
+ i++;
279
+ } // If ${ was not followed by a number and either } or :, then its not a tabstop
280
+
281
+
282
+ if (numberStart === -1 || numberEnd === -1 || i >= n || text[i] != '}' && text[i] != ':') {
283
+ continue;
284
+ } // If ${0} was found, then break
285
+
286
+
287
+ const currentTabStop = text.substring(numberStart, numberEnd);
288
+ foundLastStop = currentTabStop === '0';
289
+
290
+ if (foundLastStop) {
291
+ break;
292
+ }
293
+
294
+ let foundPlaceholder = false;
295
+
296
+ if (text[i++] == ':') {
297
+ // TODO: Nested placeholders may break here
298
+ while (i < n) {
299
+ if (text[i] == '}') {
300
+ foundPlaceholder = true;
301
+ break;
302
+ }
303
+
304
+ i++;
305
+ }
306
+ } // Decide to replace currentTabStop with ${0} only if its the max among all tabstops and is not a placeholder
307
+
308
+
309
+ if (Number(currentTabStop) > Number(maxTabStop)) {
310
+ maxTabStop = Number(currentTabStop);
311
+ maxTabStopRanges = [{
312
+ numberStart,
313
+ numberEnd
314
+ }];
315
+ replaceWithLastStop = !foundPlaceholder;
316
+ } else if (Number(currentTabStop) === maxTabStop) {
317
+ maxTabStopRanges.push({
318
+ numberStart,
319
+ numberEnd
320
+ });
321
+ }
322
+ }
323
+ } catch (e) {}
324
+
325
+ if (replaceWithLastStop && !foundLastStop) {
326
+ for (let i = 0; i < maxTabStopRanges.length; i++) {
327
+ const rangeStart = maxTabStopRanges[i].numberStart;
328
+ const rangeEnd = maxTabStopRanges[i].numberEnd;
329
+ text = text.substr(0, rangeStart) + '0' + text.substr(rangeEnd);
330
+ }
331
+ }
332
+
333
+ return text;
334
+ }
335
+
336
+ function getCurrentLine(model, position) {
337
+ const currentLine = model.getLineContent(position.lineNumber);
338
+ return currentLine;
339
+ }
340
+
341
+ let customSnippetsRegistry = {};
342
+ let variablesFromFile = {};
343
+ let profilesFromFile = {};
344
+ const emmetSnippetField = (index, placeholder) => `\${${index}${placeholder ? ':' + placeholder : ''}}`;
345
+ /** Returns whether or not syntax is a supported stylesheet syntax, like CSS */
346
+
347
+ function isStyleSheet(syntax) {
348
+ return syntaxes.stylesheet.includes(syntax);
349
+ }
350
+ /** Returns the syntax type, either markup (e.g. for HTML) or stylesheet (e.g. for CSS) */
351
+
352
+ function getSyntaxType(syntax) {
353
+ return isStyleSheet(syntax) ? 'stylesheet' : 'markup';
354
+ }
355
+ /** Returns the default syntax (html or css) to use for the snippets registry */
356
+
357
+ function getDefaultSyntax(syntax) {
358
+ return isStyleSheet(syntax) ? 'css' : 'html';
359
+ }
360
+ /** Returns the default snippets that Emmet suggests */
361
+
362
+ function getDefaultSnippets(syntax) {
363
+ const syntaxType = getSyntaxType(syntax);
364
+ const emptyUserConfig = {
365
+ type: syntaxType,
366
+ syntax
367
+ };
368
+ const resolvedConfig = resolveConfig(emptyUserConfig); // https://github.com/microsoft/vscode/issues/97632
369
+ // don't return markup (HTML) snippets for XML
370
+
371
+ return syntax === 'xml' ? {} : resolvedConfig.snippets;
372
+ }
373
+
374
+ function getFilters(text, pos) {
375
+ let filter;
376
+
377
+ for (let i = 0; i < maxFilters; i++) {
378
+ if (text.endsWith(`${filterDelimitor}${bemFilterSuffix}`, pos)) {
379
+ pos -= bemFilterSuffix.length + 1;
380
+ filter = filter ? bemFilterSuffix + ',' + filter : bemFilterSuffix;
381
+ } else if (text.endsWith(`${filterDelimitor}${commentFilterSuffix}`, pos)) {
382
+ pos -= commentFilterSuffix.length + 1;
383
+ filter = filter ? commentFilterSuffix + ',' + filter : commentFilterSuffix;
384
+ } else if (text.endsWith(`${filterDelimitor}${trimFilterSuffix}`, pos)) {
385
+ pos -= trimFilterSuffix.length + 1;
386
+ filter = filter ? trimFilterSuffix + ',' + filter : trimFilterSuffix;
387
+ } else {
388
+ break;
389
+ }
390
+ }
391
+
392
+ return {
393
+ pos: pos,
394
+ filter: filter
395
+ };
396
+ }
397
+ /**
398
+ * Extracts abbreviation from the given position in the given document
399
+ */
400
+
401
+
402
+ function extractAbbreviation(monaco, model, position, options) {
403
+ const currentLine = model.getLineContent(position.lineNumber);
404
+ const currentLineTillPosition = currentLine.substr(0, position.column - 1);
405
+ const {
406
+ pos,
407
+ filter
408
+ } = getFilters(currentLineTillPosition, position.column - 1);
409
+ const lengthOccupiedByFilter = filter ? filter.length + 1 : 0;
410
+ const result = extract(currentLine, pos, options);
411
+
412
+ if (!result) {
413
+ return;
414
+ }
415
+
416
+ const rangeToReplace = new monaco.Range(position.lineNumber, result.location + 1, position.lineNumber, result.location + result.abbreviation.length + lengthOccupiedByFilter + 1);
417
+ return {
418
+ abbreviationRange: rangeToReplace,
419
+ abbreviation: result.abbreviation,
420
+ filter
421
+ };
422
+ }
423
+ /**
424
+ * Returns a boolean denoting validity of given abbreviation in the context of given syntax
425
+ * Not needed once https://github.com/emmetio/atom-plugin/issues/22 is fixed
426
+ * @param syntax string
427
+ * @param abbreviation string
428
+ */
429
+
430
+ function isAbbreviationValid(syntax, abbreviation) {
431
+ if (!abbreviation) {
432
+ return false;
433
+ }
434
+
435
+ if (isStyleSheet(syntax)) {
436
+ if (abbreviation.includes('#')) {
437
+ if (abbreviation.startsWith('#')) {
438
+ const hexColorRegex = /^#[\d,a-f,A-F]{1,6}$/;
439
+ return hexColorRegex.test(abbreviation);
440
+ } else if (commonlyUsedTags.includes(abbreviation.substring(0, abbreviation.indexOf('#')))) {
441
+ return false;
442
+ }
443
+ }
444
+
445
+ return cssAbbreviationRegex.test(abbreviation);
446
+ }
447
+
448
+ if (abbreviation.startsWith('!')) {
449
+ return !/[^!]/.test(abbreviation);
450
+ } // Its common for users to type (sometextinsidebrackets), this should not be treated as an abbreviation
451
+ // Grouping in abbreviation is valid only if it's inside a text node or preceeded/succeeded with one of the symbols for nesting, sibling, repeater or climb up
452
+
453
+
454
+ if ((/\(/.test(abbreviation) || /\)/.test(abbreviation)) && !/\{[^\}\{]*[\(\)]+[^\}\{]*\}(?:[>\+\*\^]|$)/.test(abbreviation) && !/\(.*\)[>\+\*\^]/.test(abbreviation) && !/[>\+\*\^]\(.*\)/.test(abbreviation)) {
455
+ return false;
456
+ }
457
+
458
+ if (syntax === 'jsx') {
459
+ return jsxAbbreviationStartRegex.test(abbreviation) && htmlAbbreviationRegex.test(abbreviation);
460
+ }
461
+
462
+ return htmlAbbreviationStartRegex.test(abbreviation) && htmlAbbreviationRegex.test(abbreviation);
463
+ }
464
+
465
+ function isExpandedTextNoise(syntax, abbreviation, expandedText, options) {
466
+ var _a, _b; // Unresolved css abbreviations get expanded to a blank property value
467
+ // Eg: abc -> abc: ; or abc:d -> abc: d; which is noise if it gets suggested for every word typed
468
+
469
+
470
+ if (isStyleSheet(syntax) && options) {
471
+ const between = (_a = options['stylesheet.between']) !== null && _a !== void 0 ? _a : ': ';
472
+ const after = (_b = options['stylesheet.after']) !== null && _b !== void 0 ? _b : ';'; // Remove overlapping between `abbreviation` and `between`, if any
473
+
474
+ let endPrefixIndex = abbreviation.indexOf(between[0], Math.max(abbreviation.length - between.length, 0));
475
+ endPrefixIndex = endPrefixIndex >= 0 ? endPrefixIndex : abbreviation.length;
476
+ const abbr = abbreviation.substring(0, endPrefixIndex);
477
+ return expandedText === `${abbr}${between}\${0}${after}` || expandedText.replace(/\s/g, '') === abbreviation.replace(/\s/g, '') + after;
478
+ } // we don't want common html tags suggested for xml
479
+
480
+
481
+ if (syntax === 'xml' && commonlyUsedTags.some(tag => tag.startsWith(abbreviation.toLowerCase()))) {
482
+ return true;
483
+ }
484
+
485
+ if (commonlyUsedTags.includes(abbreviation.toLowerCase()) || markupSnippetKeys.includes(abbreviation)) {
486
+ return false;
487
+ } // Custom tags can have - or :
488
+
489
+
490
+ if (/[-,:]/.test(abbreviation) && !/--|::/.test(abbreviation) && !abbreviation.endsWith(':')) {
491
+ return false;
492
+ } // Its common for users to type some text and end it with period, this should not be treated as an abbreviation
493
+ // Else it becomes noise.
494
+ // When user just types '.', return the expansion
495
+ // Otherwise emmet loses change to participate later
496
+ // For example in `.foo`. See https://github.com/Microsoft/vscode/issues/66013
497
+
498
+
499
+ if (abbreviation === '.') {
500
+ return false;
501
+ }
502
+
503
+ const dotMatches = /^([a-z,A-Z,\d]*)\.$/.exec(abbreviation);
504
+
505
+ if (dotMatches) {
506
+ // Valid html tags such as `div.`
507
+ if (dotMatches[1] && htmlData.tags.includes(dotMatches[1])) {
508
+ return false;
509
+ }
510
+
511
+ return true;
512
+ } // Fix for https://github.com/microsoft/vscode/issues/89746
513
+ // PascalCase tags are common in jsx code, which should not be treated as noise.
514
+ // Eg: MyAwesomComponent -> <MyAwesomComponent></MyAwesomComponent>
515
+
516
+
517
+ if (syntax === 'jsx' && /^([A-Z][A-Za-z0-9]*)+$/.test(abbreviation)) {
518
+ return false;
519
+ } // Unresolved html abbreviations get expanded as if it were a tag
520
+ // Eg: abc -> <abc></abc> which is noise if it gets suggested for every word typed
521
+
522
+
523
+ return expandedText.toLowerCase() === `<${abbreviation.toLowerCase()}>\${1}</${abbreviation.toLowerCase()}>`;
524
+ }
525
+ /**
526
+ * Returns options to be used by emmet
527
+ */
528
+
529
+
530
+ function getExpandOptions(syntax, emmetConfig, filter) {
531
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
532
+
533
+ emmetConfig = emmetConfig !== null && emmetConfig !== void 0 ? emmetConfig : {};
534
+ emmetConfig['preferences'] = (_a = emmetConfig['preferences']) !== null && _a !== void 0 ? _a : {};
535
+ const preferences = emmetConfig['preferences'];
536
+ const stylesheetSyntax = isStyleSheet(syntax) ? syntax : 'css'; // Fetch Profile
537
+
538
+ const profile = getProfile(syntax, (_b = emmetConfig['syntaxProfiles']) !== null && _b !== void 0 ? _b : {});
539
+ const filtersFromProfile = profile && profile['filters'] ? profile['filters'].split(',') : [];
540
+ const trimmedFilters = filtersFromProfile.map(filterFromProfile => filterFromProfile.trim());
541
+ const bemEnabled = filter && filter.split(',').some(x => x.trim() === 'bem') || trimmedFilters.includes('bem');
542
+ const commentEnabled = filter && filter.split(',').some(x => x.trim() === 'c') || trimmedFilters.includes('c'); // Fetch formatters
543
+
544
+ const formatters = getFormatters(syntax, emmetConfig['preferences']);
545
+ const unitAliases = (formatters === null || formatters === void 0 ? void 0 : formatters.stylesheet) && formatters.stylesheet['unitAliases'] || {}; // These options are the default values provided by vscode for
546
+ // extension preferences
547
+
548
+ const defaultVSCodeOptions = {
549
+ // inlineElements: string[],
550
+ // 'output.indent': string,
551
+ // 'output.baseIndent': string,
552
+ // 'output.newline': string,
553
+ // 'output.tagCase': profile['tagCase'],
554
+ // 'output.attributeCase': profile['attributeCase'],
555
+ // 'output.attributeQuotes': profile['attributeQuotes'],
556
+ // 'output.format': profile['format'] ?? true,
557
+ // 'output.formatLeafNode': boolean,
558
+ 'output.formatSkip': ['html'],
559
+ 'output.formatForce': ['body'],
560
+ 'output.inlineBreak': 0,
561
+ 'output.compactBoolean': false,
562
+ // 'output.booleanAttributes': string[],
563
+ 'output.reverseAttributes': false,
564
+ // 'output.selfClosingStyle': profile['selfClosingStyle'],
565
+ 'output.field': emmetSnippetField,
566
+ // 'output.text': TextOutput,
567
+ 'markup.href': true,
568
+ 'comment.enabled': false,
569
+ 'comment.trigger': ['id', 'class'],
570
+ 'comment.before': '',
571
+ 'comment.after': '\n<!-- /[#ID][.CLASS] -->',
572
+ 'bem.enabled': false,
573
+ 'bem.element': '__',
574
+ 'bem.modifier': '_',
575
+ 'jsx.enabled': syntax === 'jsx',
576
+ // 'stylesheet.keywords': string[],
577
+ // 'stylesheet.unitless': string[],
578
+ 'stylesheet.shortHex': true,
579
+ 'stylesheet.between': syntax === 'stylus' ? ' ' : ': ',
580
+ 'stylesheet.after': syntax === 'sass' || syntax === 'stylus' ? '' : ';',
581
+ 'stylesheet.intUnit': 'px',
582
+ 'stylesheet.floatUnit': 'em',
583
+ 'stylesheet.unitAliases': {
584
+ e: 'em',
585
+ p: '%',
586
+ x: 'ex',
587
+ r: 'rem'
588
+ },
589
+ // 'stylesheet.json': boolean,
590
+ // 'stylesheet.jsonDoubleQuotes': boolean,
591
+ 'stylesheet.fuzzySearchMinScore': 0.3
592
+ }; // These options come from user prefs in the vscode repo
593
+
594
+ const userPreferenceOptions = {
595
+ // inlineElements: string[],
596
+ // 'output.indent': string,
597
+ // 'output.baseIndent': string,
598
+ // 'output.newline': string,
599
+ 'output.tagCase': profile['tagCase'],
600
+ 'output.attributeCase': profile['attributeCase'],
601
+ 'output.attributeQuotes': profile['attributeQuotes'],
602
+ 'output.format': (_c = profile['format']) !== null && _c !== void 0 ? _c : true,
603
+ // 'output.formatLeafNode': boolean,
604
+ 'output.formatSkip': preferences['format.noIndentTags'],
605
+ 'output.formatForce': preferences['format.forceIndentationForTags'],
606
+ 'output.inlineBreak': (_d = profile['inlineBreak']) !== null && _d !== void 0 ? _d : preferences['output.inlineBreak'],
607
+ 'output.compactBoolean': (_e = profile['compactBooleanAttributes']) !== null && _e !== void 0 ? _e : preferences['profile.allowCompactBoolean'],
608
+ // 'output.booleanAttributes': string[],
609
+ 'output.reverseAttributes': preferences['output.reverseAttributes'],
610
+ 'output.selfClosingStyle': (_g = (_f = profile['selfClosingStyle']) !== null && _f !== void 0 ? _f : preferences['output.selfClosingStyle']) !== null && _g !== void 0 ? _g : getClosingStyle(syntax),
611
+ 'output.field': emmetSnippetField,
612
+ // 'output.text': TextOutput,
613
+ // 'markup.href': boolean,
614
+ 'comment.enabled': commentEnabled,
615
+ 'comment.trigger': preferences['filter.commentTrigger'],
616
+ 'comment.before': preferences['filter.commentBefore'],
617
+ 'comment.after': preferences['filter.commentAfter'],
618
+ 'bem.enabled': bemEnabled,
619
+ 'bem.element': (_h = preferences['bem.elementSeparator']) !== null && _h !== void 0 ? _h : '__',
620
+ 'bem.modifier': (_j = preferences['bem.modifierSeparator']) !== null && _j !== void 0 ? _j : '_',
621
+ 'jsx.enabled': syntax === 'jsx',
622
+ // 'stylesheet.keywords': string[],
623
+ // 'stylesheet.unitless': string[],
624
+ 'stylesheet.shortHex': preferences['css.color.short'],
625
+ 'stylesheet.between': preferences[`${stylesheetSyntax}.valueSeparator`],
626
+ 'stylesheet.after': preferences[`${stylesheetSyntax}.propertyEnd`],
627
+ 'stylesheet.intUnit': preferences['css.intUnit'],
628
+ 'stylesheet.floatUnit': preferences['css.floatUnit'],
629
+ 'stylesheet.unitAliases': unitAliases,
630
+ // 'stylesheet.json': boolean,
631
+ // 'stylesheet.jsonDoubleQuotes': boolean,
632
+ 'stylesheet.fuzzySearchMinScore': preferences['css.fuzzySearchMinScore']
633
+ };
634
+ const combinedOptions = {};
635
+ [...Object.keys(defaultVSCodeOptions), ...Object.keys(userPreferenceOptions)].forEach(key => {
636
+ var _a;
637
+
638
+ const castKey = key;
639
+ combinedOptions[castKey] = (_a = userPreferenceOptions[castKey]) !== null && _a !== void 0 ? _a : defaultVSCodeOptions[castKey];
640
+ });
641
+ const mergedAliases = Object.assign(Object.assign({}, defaultVSCodeOptions['stylesheet.unitAliases']), userPreferenceOptions['stylesheet.unitAliases']);
642
+ combinedOptions['stylesheet.unitAliases'] = mergedAliases;
643
+ const type = getSyntaxType(syntax);
644
+ const variables = getVariables(emmetConfig['variables']);
645
+ const baseSyntax = getDefaultSyntax(syntax);
646
+ const snippets = type === 'stylesheet' ? (_k = customSnippetsRegistry[syntax]) !== null && _k !== void 0 ? _k : customSnippetsRegistry[baseSyntax] : customSnippetsRegistry[syntax];
647
+ return {
648
+ type,
649
+ options: combinedOptions,
650
+ variables,
651
+ snippets,
652
+ syntax,
653
+ // context: null,
654
+ text: undefined,
655
+ maxRepeat: 1000 // cache: null
656
+
657
+ };
658
+ }
659
+
660
+ function getClosingStyle(syntax) {
661
+ switch (syntax) {
662
+ case 'xhtml':
663
+ return 'xhtml';
664
+
665
+ case 'xml':
666
+ return 'xml';
667
+
668
+ case 'xsl':
669
+ return 'xml';
670
+
671
+ case 'jsx':
672
+ return 'xhtml';
673
+
674
+ default:
675
+ return 'html';
676
+ }
677
+ }
678
+ /**
679
+ * Maps and returns syntaxProfiles of previous format to ones compatible with new emmet modules
680
+ * @param syntax
681
+ */
682
+
683
+ function getProfile(syntax, profilesFromSettings) {
684
+ if (!profilesFromSettings) {
685
+ profilesFromSettings = {};
686
+ }
687
+
688
+ const profilesConfig = Object.assign({}, profilesFromFile, profilesFromSettings);
689
+ const options = profilesConfig[syntax];
690
+
691
+ if (!options || typeof options === 'string') {
692
+ if (options === 'xhtml') {
693
+ return {
694
+ selfClosingStyle: 'xhtml'
695
+ };
696
+ }
697
+
698
+ return {};
699
+ }
700
+
701
+ const newOptions = {};
702
+
703
+ for (const key in options) {
704
+ switch (key) {
705
+ case 'tag_case':
706
+ newOptions['tagCase'] = options[key] === 'lower' || options[key] === 'upper' ? options[key] : '';
707
+ break;
708
+
709
+ case 'attr_case':
710
+ newOptions['attributeCase'] = options[key] === 'lower' || options[key] === 'upper' ? options[key] : '';
711
+ break;
712
+
713
+ case 'attr_quotes':
714
+ newOptions['attributeQuotes'] = options[key];
715
+ break;
716
+
717
+ case 'tag_nl':
718
+ newOptions['format'] = options[key] === true || options[key] === false ? options[key] : true;
719
+ break;
720
+
721
+ case 'inline_break':
722
+ newOptions['inlineBreak'] = options[key];
723
+ break;
724
+
725
+ case 'self_closing_tag':
726
+ if (options[key] === true) {
727
+ newOptions['selfClosingStyle'] = 'xml';
728
+ break;
729
+ }
730
+
731
+ if (options[key] === false) {
732
+ newOptions['selfClosingStyle'] = 'html';
733
+ break;
734
+ }
735
+
736
+ newOptions['selfClosingStyle'] = options[key];
737
+ break;
738
+
739
+ case 'compact_bool':
740
+ newOptions['compactBooleanAttributes'] = options[key];
741
+ break;
742
+
743
+ default:
744
+ newOptions[key] = options[key];
745
+ break;
746
+ }
747
+ }
748
+
749
+ return newOptions;
750
+ }
751
+ /**
752
+ * Returns variables to be used while expanding snippets
753
+ */
754
+
755
+
756
+ function getVariables(variablesFromSettings) {
757
+ if (!variablesFromSettings) {
758
+ return variablesFromFile;
759
+ }
760
+
761
+ return Object.assign({}, variablesFromFile, variablesFromSettings);
762
+ }
763
+
764
+ function getFormatters(syntax, preferences) {
765
+ if (!preferences || typeof preferences !== 'object') {
766
+ return {};
767
+ }
768
+
769
+ if (!isStyleSheet(syntax)) {
770
+ const commentFormatter = {};
771
+
772
+ for (const key in preferences) {
773
+ switch (key) {
774
+ case 'filter.commentAfter':
775
+ commentFormatter['after'] = preferences[key];
776
+ break;
777
+
778
+ case 'filter.commentBefore':
779
+ commentFormatter['before'] = preferences[key];
780
+ break;
781
+
782
+ case 'filter.commentTrigger':
783
+ commentFormatter['trigger'] = preferences[key];
784
+ break;
785
+ }
786
+ }
787
+
788
+ return {
789
+ comment: commentFormatter
790
+ };
791
+ }
792
+
793
+ let fuzzySearchMinScore = typeof (preferences === null || preferences === void 0 ? void 0 : preferences['css.fuzzySearchMinScore']) === 'number' ? preferences['css.fuzzySearchMinScore'] : 0.3;
794
+
795
+ if (fuzzySearchMinScore > 1) {
796
+ fuzzySearchMinScore = 1;
797
+ } else if (fuzzySearchMinScore < 0) {
798
+ fuzzySearchMinScore = 0;
799
+ }
800
+
801
+ const stylesheetFormatter = {
802
+ 'fuzzySearchMinScore': fuzzySearchMinScore
803
+ };
804
+
805
+ for (const key in preferences) {
806
+ switch (key) {
807
+ case 'css.floatUnit':
808
+ stylesheetFormatter['floatUnit'] = preferences[key];
809
+ break;
810
+
811
+ case 'css.intUnit':
812
+ stylesheetFormatter['intUnit'] = preferences[key];
813
+ break;
814
+
815
+ case 'css.unitAliases':
816
+ const unitAliases = {};
817
+ preferences[key].split(',').forEach(alias => {
818
+ if (!alias || !alias.trim() || !alias.includes(':')) {
819
+ return;
820
+ }
821
+
822
+ const aliasName = alias.substr(0, alias.indexOf(':'));
823
+ const aliasValue = alias.substr(aliasName.length + 1);
824
+
825
+ if (!aliasName.trim() || !aliasValue) {
826
+ return;
827
+ }
828
+
829
+ unitAliases[aliasName.trim()] = aliasValue;
830
+ });
831
+ stylesheetFormatter['unitAliases'] = unitAliases;
832
+ break;
833
+
834
+ case `${syntax}.valueSeparator`:
835
+ stylesheetFormatter['between'] = preferences[key];
836
+ break;
837
+
838
+ case `${syntax}.propertyEnd`:
839
+ stylesheetFormatter['after'] = preferences[key];
840
+ break;
841
+ }
842
+ }
843
+
844
+ return {
845
+ stylesheet: stylesheetFormatter
846
+ };
847
+ }
848
+ /**
849
+ * Get the corresponding emmet mode for given vscode language mode
850
+ * Eg: jsx for typescriptreact/javascriptreact or pug for jade
851
+ * If the language is not supported by emmet or has been exlcuded via `exlcudeLanguages` setting,
852
+ * then nothing is returned
853
+ *
854
+ * @param language
855
+ * @param exlcudedLanguages Array of language ids that user has chosen to exlcude for emmet
856
+ */
857
+
858
+
859
+ function getEmmetMode(language, excludedLanguages = []) {
860
+ if (!language || excludedLanguages.includes(language)) {
861
+ return;
862
+ }
863
+
864
+ if (/\b(typescriptreact|javascriptreact|jsx-tags)\b/.test(language)) {
865
+ // treat tsx like jsx
866
+ return 'jsx';
867
+ }
868
+
869
+ if (language === 'sass-indented') {
870
+ // map sass-indented to sass
871
+ return 'sass';
872
+ }
873
+
874
+ if (language === 'jade') {
875
+ return 'pug';
876
+ }
877
+
878
+ if (syntaxes.markup.includes(language) || syntaxes.stylesheet.includes(language)) {
879
+ return language;
880
+ }
881
+ }
882
+
883
+ export { doComplete, emmetSnippetField, extractAbbreviation, getDefaultSnippets, getDefaultSyntax, getEmmetMode, getExpandOptions, getSyntaxType, isAbbreviationValid, isStyleSheet };