import-editor.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See LICENSE in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. const glob = require('glob');
  6. const path = require('path');
  7. const fs = require('fs');
  8. const customFeatureLabels = {
  9. 'vs/editor/browser/controller/coreCommands': 'coreCommands',
  10. 'vs/editor/contrib/caretOperations/caretOperations': 'caretOperations',
  11. 'vs/editor/contrib/caretOperations/transpose': 'transpose',
  12. 'vs/editor/contrib/colorPicker/colorDetector': 'colorDetector',
  13. 'vs/editor/contrib/rename/onTypeRename': 'onTypeRename',
  14. 'vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition': 'gotoSymbol',
  15. 'vs/editor/contrib/snippet/snippetController2': 'snippets',
  16. 'vs/editor/standalone/browser/quickAccess/standaloneGotoLineQuickAccess': 'gotoLine',
  17. 'vs/editor/standalone/browser/quickAccess/standaloneCommandsQuickAccess': 'quickCommand',
  18. 'vs/editor/standalone/browser/quickAccess/standaloneGotoSymbolQuickAccess': 'quickOutline',
  19. 'vs/editor/standalone/browser/quickAccess/standaloneHelpQuickAccess': 'quickHelp',
  20. };
  21. generateLanguages();
  22. generateFeatures();
  23. /**
  24. * @returns { Promise<{ label: string; entry: string; }[]> }
  25. */
  26. function getBasicLanguages() {
  27. return new Promise((resolve, reject) => {
  28. glob('./node_modules/monaco-editor/esm/vs/basic-languages/*/*.contribution.js', { cwd: path.dirname(__dirname) }, (err, files) => {
  29. if (err) {
  30. reject(err);
  31. return;
  32. }
  33. resolve(files.map((file) => {
  34. const entry = file.substring('./node_modules/monaco-editor/esm/'.length).replace(/\.js$/, '');
  35. const label = path.basename(file).replace(/\.contribution\.js$/, '');
  36. return {
  37. label: label,
  38. entry: entry
  39. };
  40. }));
  41. });
  42. });
  43. }
  44. /**
  45. * @returns { Promise<string[]> }
  46. */
  47. function readAdvancedLanguages() {
  48. return new Promise((resolve, reject) => {
  49. glob('./node_modules/monaco-editor/esm/vs/language/*/monaco.contribution.js', { cwd: path.dirname(__dirname) }, (err, files) => {
  50. if (err) {
  51. reject(err);
  52. return;
  53. }
  54. resolve(
  55. files
  56. .map(file => file.substring('./node_modules/monaco-editor/esm/vs/language/'.length))
  57. .map(file => file.substring(0, file.length - '/monaco.contribution.js'.length))
  58. );
  59. });
  60. });
  61. }
  62. /**
  63. * @returns { Promise<{ label: string; entry: string; worker: { id: string; entry: string; }; }[]> }
  64. */
  65. function getAdvancedLanguages() {
  66. return readAdvancedLanguages().then((languages) => {
  67. let result = [];
  68. for (const lang of languages) {
  69. let shortLang = (lang === 'typescript' ? 'ts' : lang);
  70. const entry = `vs/language/${lang}/monaco.contribution`;
  71. checkFileExists(entry);
  72. const workerId = `vs/language/${lang}/${shortLang}Worker`;
  73. checkFileExists(workerId);
  74. const workerEntry = `vs/language/${lang}/${shortLang}.worker`;
  75. checkFileExists(workerEntry);
  76. result.push({
  77. label: lang,
  78. entry: entry,
  79. worker: {
  80. id: workerId,
  81. entry: workerEntry
  82. }
  83. });
  84. }
  85. return result;
  86. });
  87. function checkFileExists(moduleName) {
  88. const filePath = path.join(__dirname, '..', 'node_modules/monaco-editor/esm', `${moduleName}.js`);
  89. if (!fs.existsSync(filePath)) {
  90. console.error(`Could not find ${filePath}.`);
  91. process.exit(1);
  92. }
  93. }
  94. }
  95. function generateLanguages() {
  96. return Promise.all([getBasicLanguages(), getAdvancedLanguages()]).then(([basicLanguages, advancedLanguages]) => {
  97. basicLanguages.sort(strcmp);
  98. advancedLanguages.sort(strcmp);
  99. let i = 0, len = basicLanguages.length;
  100. let j = 0, lenJ = advancedLanguages.length;
  101. let result = [];
  102. while (i < len || j < lenJ) {
  103. if (i < len && j < lenJ) {
  104. if (basicLanguages[i].label === advancedLanguages[j].label) {
  105. let entry = [];
  106. entry.push(basicLanguages[i].entry);
  107. entry.push(advancedLanguages[j].entry);
  108. result.push({
  109. label: basicLanguages[i].label,
  110. entry: entry,
  111. worker: advancedLanguages[j].worker
  112. });
  113. i++;
  114. j++;
  115. } else if (basicLanguages[i].label < advancedLanguages[j].label) {
  116. result.push(basicLanguages[i]);
  117. i++;
  118. } else {
  119. result.push(advancedLanguages[j]);
  120. j++;
  121. }
  122. } else if (i < len) {
  123. result.push(basicLanguages[i]);
  124. i++;
  125. } else {
  126. result.push(advancedLanguages[j]);
  127. j++;
  128. }
  129. }
  130. const code = `//
  131. // THIS IS A GENERATED FILE. PLEASE DO NOT EDIT DIRECTLY.
  132. // GENERATED USING node scripts/import-editor.js
  133. //
  134. import { IFeatureDefinition } from "./types";
  135. export const languagesArr: IFeatureDefinition[] = ${
  136. JSON.stringify(result, null, ' ')
  137. .replace(/"label":/g, 'label:')
  138. .replace(/"entry":/g, 'entry:')
  139. .replace(/"worker":/g, 'worker:')
  140. .replace(/"id":/g, 'id:')
  141. .replace(/"/g, '\'')
  142. };
  143. export type EditorLanguage = ${
  144. result.map(el => `'${el.label}'`).join(' | ')
  145. };
  146. `
  147. fs.writeFileSync(path.join(__dirname, '../src/languages.ts'), code.replace(/\r\n/g, '\n'));
  148. const readmeLanguages = (
  149. JSON.stringify(result.map(r => r.label))
  150. .replace(/"/g, '\'')
  151. .replace(/','/g, '\', \'')
  152. );
  153. let readme = fs.readFileSync(path.join(__dirname, '../README.md')).toString();
  154. readme = readme.replace(/<!-- LANGUAGES_BEGIN -->([^<]+)<!-- LANGUAGES_END -->/, `<!-- LANGUAGES_BEGIN -->\`${readmeLanguages}\`<!-- LANGUAGES_END -->`);
  155. fs.writeFileSync(path.join(__dirname, '../README.md'), readme);
  156. });
  157. }
  158. function strcmp(a, b) {
  159. if (a < b) {
  160. return -1;
  161. }
  162. if (a > b) {
  163. return 1;
  164. }
  165. return 0;
  166. }
  167. /**
  168. * @returns { string[] }
  169. */
  170. function generateFeatures() {
  171. const skipImports = [
  172. 'vs/editor/browser/widget/codeEditorWidget',
  173. 'vs/editor/browser/widget/diffEditorWidget',
  174. 'vs/editor/browser/widget/diffNavigator',
  175. 'vs/editor/common/standaloneStrings',
  176. 'vs/editor/contrib/tokenization/tokenization',
  177. 'vs/editor/editor.all',
  178. 'vs/base/browser/ui/codicons/codiconStyles',
  179. 'vs/editor/contrib/gotoSymbol/documentSymbols',
  180. ];
  181. let features = [];
  182. const files = (
  183. fs.readFileSync(path.join(__dirname, '../node_modules/monaco-editor/esm/vs/editor/edcore.main.js')).toString()
  184. + fs.readFileSync(path.join(__dirname, '../node_modules/monaco-editor/esm/vs/editor/editor.all.js')).toString()
  185. );
  186. files.split(/\r\n|\n/).forEach(line => {
  187. const m = line.match(/import '([^']+)'/);
  188. if (m) {
  189. const tmp = path.posix.join('vs/editor', m[1]).replace(/\.js$/, '');
  190. if (skipImports.indexOf(tmp) === -1) {
  191. features.push(tmp);
  192. }
  193. }
  194. });
  195. let result = features.map((feature) => {
  196. return {
  197. label: customFeatureLabels[feature] || path.basename(path.dirname(feature)),
  198. entry: feature
  199. };
  200. });
  201. result.sort((a, b) => {
  202. const labelCmp = strcmp(a.label, b.label);
  203. if (labelCmp === 0) {
  204. return strcmp(a.entry, b.entry);
  205. }
  206. return labelCmp;
  207. });
  208. for (let i = 0; i < result.length; i++) {
  209. if (i + 1 < result.length && result[i].label === result[i + 1].label) {
  210. if (typeof result[i].entry === 'string') {
  211. result[i].entry = [result[i].entry];
  212. }
  213. result[i].entry.push(result[i + 1].entry);
  214. result.splice(i + 1, 1);
  215. }
  216. }
  217. const code = `//
  218. // THIS IS A GENERATED FILE. PLEASE DO NOT EDIT DIRECTLY.
  219. // GENERATED USING node scripts/import-editor.js
  220. //
  221. import { IFeatureDefinition } from "./types";
  222. export const featuresArr: IFeatureDefinition[] = ${
  223. JSON.stringify(result, null, ' ')
  224. .replace(/"label":/g, 'label:')
  225. .replace(/"entry":/g, 'entry:')
  226. .replace(/"/g, '\'')
  227. };
  228. export type EditorFeature = ${
  229. result.map(el => `'${el.label}'`).join(' | ')
  230. };
  231. export type NegatedEditorFeature = ${
  232. result.map(el => `'!${el.label}'`).join(' | ')
  233. };
  234. `
  235. fs.writeFileSync(path.join(__dirname, '../src/features.ts'), code.replace(/\r\n/g, '\n'));
  236. const readmeFeatures = (
  237. JSON.stringify(result.map(r => r.label))
  238. .replace(/"/g, '\'')
  239. .replace(/','/g, '\', \'')
  240. );
  241. let readme = fs.readFileSync(path.join(__dirname, '../README.md')).toString();
  242. readme = readme.replace(/<!-- FEATURES_BEGIN -->([^<]+)<!-- FEATURES_END -->/, `<!-- FEATURES_BEGIN -->\`${readmeFeatures}\`<!-- FEATURES_END -->`);
  243. fs.writeFileSync(path.join(__dirname, '../README.md'), readme);
  244. }