gulpfile.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. var gulp = require('gulp');
  2. var metadata = require('./metadata');
  3. var es = require('event-stream');
  4. var path = require('path');
  5. var fs = require('fs');
  6. var rimraf = require('rimraf');
  7. var cp = require('child_process');
  8. var httpServer = require('http-server');
  9. var typedoc = require("gulp-typedoc");
  10. var WEBSITE_GENERATED_PATH = path.join(__dirname, 'website/playground/new-samples');
  11. var MONACO_EDITOR_VERSION = (function() {
  12. var packageJsonPath = path.join(__dirname, 'package.json');
  13. var packageJson = JSON.parse(fs.readFileSync(packageJsonPath).toString());
  14. var version = packageJson.version;
  15. if (!/\d+\.\d+\.\d+/.test(version)) {
  16. console.log('unrecognized package.json version: ' + version);
  17. process.exit(0);
  18. }
  19. return version;
  20. })();
  21. gulp.task('clean-release', function(cb) { rimraf('release', { maxBusyTries: 1 }, cb); });
  22. gulp.task('release', ['clean-release'], function() {
  23. return es.merge(
  24. // dev folder
  25. releaseOne('dev'),
  26. // min folder
  27. releaseOne('min'),
  28. // package.json
  29. gulp.src('package.json')
  30. .pipe(es.through(function(data) {
  31. var json = JSON.parse(data.contents.toString());
  32. json.private = false;
  33. data.contents = new Buffer(JSON.stringify(json, null, ' '));
  34. this.emit('data', data);
  35. }))
  36. .pipe(gulp.dest('release')),
  37. gulp.src('CHANGELOG.md'),
  38. // min-maps folder
  39. gulp.src('node_modules/monaco-editor-core/min-maps/**/*').pipe(gulp.dest('release/min-maps')),
  40. // other files
  41. gulp.src([
  42. 'node_modules/monaco-editor-core/LICENSE',
  43. 'node_modules/monaco-editor-core/monaco.d.ts',
  44. 'node_modules/monaco-editor-core/ThirdPartyNotices.txt',
  45. 'README.md'
  46. ])
  47. .pipe(addPluginDTS())
  48. .pipe(addPluginThirdPartyNotices())
  49. .pipe(gulp.dest('release'))
  50. )
  51. });
  52. function releaseOne(type) {
  53. return es.merge(
  54. gulp.src('node_modules/monaco-editor-core/' + type + '/**/*')
  55. .pipe(addPluginContribs())
  56. .pipe(gulp.dest('release/' + type)),
  57. pluginStreams('release/' + type + '/')
  58. )
  59. }
  60. function pluginStreams(destinationPath) {
  61. return es.merge(
  62. metadata.METADATA.PLUGINS.map(function(plugin) {
  63. return pluginStream(plugin, destinationPath);
  64. })
  65. );
  66. }
  67. function pluginStream(plugin, destinationPath) {
  68. var contribPath = path.join(plugin.paths.npm, plugin.contrib.substr(plugin.modulePrefix.length)) + '.js';
  69. return (
  70. gulp.src([
  71. plugin.paths.npm + '/**/*',
  72. '!' + contribPath,
  73. '!' + plugin.paths.npm + '/**/monaco.d.ts'
  74. ])
  75. .pipe(gulp.dest(destinationPath + plugin.modulePrefix))
  76. );
  77. }
  78. /**
  79. * Edit editor.main.js:
  80. * - rename the AMD module 'vs/editor/editor.main' to 'vs/editor/edcore.main'
  81. * - append contribs from plugins
  82. * - append new AMD module 'vs/editor/editor.main' that stiches things together
  83. */
  84. function addPluginContribs() {
  85. return es.through(function(data) {
  86. if (!/editor\.main\.js$/.test(data.path)) {
  87. this.emit('data', data);
  88. return;
  89. }
  90. var contents = data.contents.toString();
  91. // Rename the AMD module 'vs/editor/editor.main' to 'vs/editor/edcore.main'
  92. contents = contents.replace(/"vs\/editor\/editor\.main\"/, '"vs/editor/edcore.main"');
  93. var extraContent = [];
  94. var allPluginsModuleIds = [];
  95. metadata.METADATA.PLUGINS.forEach(function(plugin) {
  96. allPluginsModuleIds.push(plugin.contrib);
  97. var contribPath = path.join(__dirname, plugin.paths.npm, plugin.contrib.substr(plugin.modulePrefix.length)) + '.js';
  98. var contribContents = fs.readFileSync(contribPath).toString();
  99. var contribDefineIndex = contribContents.indexOf('define("' + plugin.contrib);
  100. if (contribDefineIndex === -1) {
  101. console.error('(1) CANNOT DETERMINE AMD define location for contribution', plugin);
  102. process.exit(-1);
  103. }
  104. var depsEndIndex = contribContents.indexOf(']', contribDefineIndex);
  105. if (contribDefineIndex === -1) {
  106. console.error('(2) CANNOT DETERMINE AMD define location for contribution', plugin);
  107. process.exit(-1);
  108. }
  109. contribContents = contribContents.substring(0, depsEndIndex) + ',"vs/editor/edcore.main"' + contribContents.substring(depsEndIndex);
  110. extraContent.push(contribContents);
  111. });
  112. extraContent.push(`define("vs/editor/editor.main", ["vs/editor/edcore.main","${allPluginsModuleIds.join('","')}"], function() {});`);
  113. var insertIndex = contents.lastIndexOf('//# sourceMappingURL=');
  114. if (insertIndex === -1) {
  115. insertIndex = contents.length;
  116. }
  117. contents = contents.substring(0, insertIndex) + '\n' + extraContent.join('\n') + '\n' + contents.substring(insertIndex);
  118. data.contents = new Buffer(contents);
  119. this.emit('data', data);
  120. });
  121. }
  122. /**
  123. * Edit monaco.d.ts:
  124. * - append monaco.d.ts from plugins
  125. */
  126. function addPluginDTS() {
  127. return es.through(function(data) {
  128. if (!/monaco\.d\.ts$/.test(data.path)) {
  129. this.emit('data', data);
  130. return;
  131. }
  132. var contents = data.contents.toString();
  133. var extraContent = [];
  134. metadata.METADATA.PLUGINS.forEach(function(plugin) {
  135. var dtsPath = path.join(plugin.paths.npm, 'monaco.d.ts');
  136. try {
  137. extraContent.push(fs.readFileSync(dtsPath).toString());
  138. } catch (err) {
  139. return;
  140. }
  141. });
  142. contents = [
  143. '/*!-----------------------------------------------------------',
  144. ' * Copyright (c) Microsoft Corporation. All rights reserved.',
  145. ' * Type definitions for monaco-editor v'+MONACO_EDITOR_VERSION,
  146. ' * Released under the MIT license',
  147. '*-----------------------------------------------------------*/',
  148. ].join('\n') + '\n' + contents + '\n' + extraContent.join('\n');
  149. // Ensure consistent indentation and line endings
  150. contents = cleanFile(contents);
  151. // Mark events in doc!!
  152. contents = contents.replace(/( \*\/\n\s+)on(.*IDisposable)/gm, function(_, m0, m1) {
  153. var m = m0.match(/( +)$/);
  154. var indentation = m[1];
  155. return ' * @event\n' + indentation + ' */\n' + indentation + 'on' + m1;
  156. });
  157. data.contents = new Buffer(contents);
  158. fs.writeFileSync('website/playground/monaco.d.ts.txt', contents);
  159. fs.writeFileSync('monaco.d.ts', contents);
  160. this.emit('data', data);
  161. });
  162. }
  163. /**
  164. * Normalize line endings and ensure consistent 4 spaces indentation
  165. */
  166. function cleanFile(contents) {
  167. return contents.split(/\r\n|\r|\n/).map(function(line) {
  168. var m = line.match(/^(\t+)/);
  169. if (!m) {
  170. return line;
  171. }
  172. var tabsCount = m[1].length;
  173. var newIndent = '';
  174. for (var i = 0; i < 4 * tabsCount; i++) {
  175. newIndent += ' ';
  176. }
  177. return newIndent + line.substring(tabsCount);
  178. }).join('\n');
  179. }
  180. /**
  181. * Edit ThirdPartyNotices.txt:
  182. * - append ThirdPartyNotices.txt from plugins
  183. */
  184. function addPluginThirdPartyNotices() {
  185. return es.through(function(data) {
  186. if (!/ThirdPartyNotices\.txt$/.test(data.path)) {
  187. this.emit('data', data);
  188. return;
  189. }
  190. var contents = data.contents.toString();
  191. var extraContent = [];
  192. metadata.METADATA.PLUGINS.forEach(function(plugin) {
  193. var thirdPartyNoticePath = path.join(path.dirname(plugin.paths.npm), 'ThirdPartyNotices.txt');
  194. try {
  195. var thirdPartyNoticeContent = fs.readFileSync(thirdPartyNoticePath).toString();
  196. thirdPartyNoticeContent = thirdPartyNoticeContent.split('\n').slice(8).join('\n');
  197. extraContent.push(thirdPartyNoticeContent);
  198. } catch (err) {
  199. return;
  200. }
  201. });
  202. contents += '\n' + extraContent.join('\n');
  203. data.contents = new Buffer(contents);
  204. this.emit('data', data);
  205. });
  206. }
  207. // --- website
  208. gulp.task('clean-website', function(cb) { rimraf('../monaco-editor-website', { maxBusyTries: 1 }, cb); });
  209. gulp.task('website', ['clean-website'], function() {
  210. return (
  211. es.merge(
  212. gulp.src([
  213. 'website/**/*',
  214. '!website/typedoc-theme/**'
  215. ], { dot: true })
  216. .pipe(es.through(function(data) {
  217. if (!data.contents || !/\.(html)$/.test(data.path)) {
  218. return this.emit('data', data);
  219. }
  220. var contents = data.contents.toString();
  221. contents = contents.replace(/\.\.\/release\/dev/g, 'node_modules/monaco-editor/min');
  222. contents = contents.replace(/{{version}}/g, MONACO_EDITOR_VERSION);
  223. // contents = contents.replace('&copy; 2016 Microsoft', '&copy; 2016 Microsoft [' + builtTime + ']');
  224. data.contents = new Buffer(contents);
  225. this.emit('data', data);
  226. }))
  227. .pipe(gulp.dest('../monaco-editor-website')),
  228. // node_modules\.bin\typedoc --mode file --out out src\monaco.d.ts --includeDeclarations --theme default --entryPoint monaco --name "Monaco Editor v0.7.0 API" --readme none --hideGenerator
  229. gulp.src('monaco.d.ts')
  230. .pipe(typedoc({
  231. mode: 'file',
  232. out: '../monaco-editor-website/api',
  233. includeDeclarations: true,
  234. theme: 'website/typedoc-theme',
  235. entryPoint: 'monaco',
  236. name: 'Monaco Editor API v' + MONACO_EDITOR_VERSION,
  237. readme: 'none',
  238. hideGenerator: true
  239. }))
  240. )
  241. .pipe(es.through(function(data) {
  242. this.emit('data', data);
  243. }, function() {
  244. // temporarily create package.json so that npm install doesn't bark
  245. fs.writeFileSync('../monaco-editor-website/package.json', '{}');
  246. fs.writeFileSync('../monaco-editor-website/.nojekyll', '');
  247. cp.execSync('npm install monaco-editor', {
  248. cwd: path.join(__dirname, '../monaco-editor-website')
  249. });
  250. fs.unlink('../monaco-editor-website/package.json');
  251. cp.execSync('git init', {
  252. cwd: path.join(__dirname, '../monaco-editor-website')
  253. });
  254. cp.execSync('git checkout -b gh-pages', {
  255. cwd: path.join(__dirname, '../monaco-editor-website')
  256. });
  257. cp.execSync('git add .', {
  258. cwd: path.join(__dirname, '../monaco-editor-website')
  259. });
  260. cp.execSync('git commit -m "Publish website"', {
  261. cwd: path.join(__dirname, '../monaco-editor-website')
  262. });
  263. cp.execSync('git remote add origin https://github.com/Microsoft/monaco-editor.git', {
  264. cwd: path.join(__dirname, '../monaco-editor-website')
  265. });
  266. console.log('RUN monaco-editor-website>git push origin gh-pages --force')
  267. this.emit('end');
  268. }))
  269. );
  270. });
  271. gulp.task('generate-test-samples', function() {
  272. var sampleNames = fs.readdirSync(path.join(__dirname, 'test/samples'));
  273. var samples = sampleNames.map(function(sampleName) {
  274. var samplePath = path.join(__dirname, 'test/samples', sampleName);
  275. var sampleContent = fs.readFileSync(samplePath).toString();
  276. return {
  277. name: sampleName,
  278. content: sampleContent
  279. };
  280. });
  281. var prefix = '//This is a generated file via gulp generate-test-samples\ndefine([], function() { return';
  282. var suffix = '; });'
  283. fs.writeFileSync(path.join(__dirname, 'test/samples-all.generated.js'), prefix + JSON.stringify(samples, null, '\t') + suffix );
  284. var PLAY_SAMPLES = require(path.join(WEBSITE_GENERATED_PATH, 'all.js')).PLAY_SAMPLES;
  285. var locations = [];
  286. for (var i = 0; i < PLAY_SAMPLES.length; i++) {
  287. var sample = PLAY_SAMPLES[i];
  288. var sampleId = sample.id;
  289. var samplePath = path.join(WEBSITE_GENERATED_PATH, sample.path);
  290. var html = fs.readFileSync(path.join(samplePath, 'sample.html'));
  291. var js = fs.readFileSync(path.join(samplePath, 'sample.js'));
  292. var css = fs.readFileSync(path.join(samplePath, 'sample.css'));
  293. var result = [
  294. '<!DOCTYPE html>',
  295. '<!-- THIS IS A GENERATED FILE VIA gulp generate-test-samples -->',
  296. '<html>',
  297. '<head>',
  298. ' <base href="..">',
  299. ' <meta http-equiv="X-UA-Compatible" content="IE=edge" />',
  300. ' <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />',
  301. '</head>',
  302. '<body>',
  303. '<style>',
  304. '/*----------------------------------------SAMPLE CSS START*/',
  305. '',
  306. css,
  307. '',
  308. '/*----------------------------------------SAMPLE CSS END*/',
  309. '</style>',
  310. '<a class="loading-opts" href="playground.generated/index.html">[&lt;&lt; BACK]</a> <br/>',
  311. 'THIS IS A GENERATED FILE VIA gulp generate-test-samples',
  312. '',
  313. '<div id="bar" style="margin-bottom: 6px;"></div>',
  314. '',
  315. '<div style="clear:both"></div>',
  316. '<div id="outer-container" style="width:800px;height:450px;border: 1px solid grey">',
  317. '<!-- ----------------------------------------SAMPLE HTML START-->',
  318. '',
  319. html,
  320. '',
  321. '<!-- ----------------------------------------SAMPLE HTML END-->',
  322. '</div>',
  323. '<div style="clear:both"></div>',
  324. '',
  325. '<script src="../metadata.js"></script>',
  326. '<script src="dev-setup.js"></script>',
  327. '<script>',
  328. 'loadEditor(function() {',
  329. '/*----------------------------------------SAMPLE JS START*/',
  330. '',
  331. js,
  332. '',
  333. '/*----------------------------------------SAMPLE CSS END*/',
  334. '});',
  335. '</script>',
  336. '</body>',
  337. '</html>',
  338. ];
  339. fs.writeFileSync(path.join(__dirname, 'test/playground.generated/' + sampleId + '.html'), result.join('\n'));
  340. locations.push({
  341. path: sampleId + '.html',
  342. name: sample.chapter + ' &gt; ' + sample.name
  343. })
  344. }
  345. var index = [
  346. '<!DOCTYPE html>',
  347. '<!-- THIS IS A GENERATED FILE VIA gulp generate-test-samples -->',
  348. '<html>',
  349. '<head>',
  350. ' <base href="..">',
  351. '</head>',
  352. '<body>',
  353. '<a class="loading-opts" href="index.html">[&lt;&lt; BACK]</a><br/>',
  354. 'THIS IS A GENERATED FILE VIA gulp generate-test-samples<br/><br/>',
  355. locations.map(function(location) {
  356. return '<a class="loading-opts" href="playground.generated/' + location.path + '">' + location.name + '</a>';
  357. }).join('<br/>\n'),
  358. '<script src="../metadata.js"></script>',
  359. '<script src="dev-setup.js"></script>',
  360. '</body>',
  361. '</html>',
  362. ]
  363. fs.writeFileSync(path.join(__dirname, 'test/playground.generated/index.html'), index.join('\n'));
  364. });
  365. gulp.task('simpleserver', ['generate-test-samples'], function(cb) {
  366. httpServer.createServer({ root: '../', cache: 5 }).listen(8080);
  367. httpServer.createServer({ root: '../', cache: 5 }).listen(8088);
  368. console.log('LISTENING on 8080 and 8088');
  369. });