gulpfile.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838
  1. const gulp = require('gulp');
  2. const metadata = require('./metadata');
  3. const es = require('event-stream');
  4. const path = require('path');
  5. const fs = require('fs');
  6. const rimraf = require('rimraf');
  7. const cp = require('child_process');
  8. const os = require('os');
  9. const httpServer = require('http-server');
  10. const typedoc = require("gulp-typedoc");
  11. const CleanCSS = require('clean-css');
  12. const uncss = require('uncss');
  13. const File = require('vinyl');
  14. const ts = require('typescript');
  15. const WEBSITE_GENERATED_PATH = path.join(__dirname, 'website/playground/new-samples');
  16. const MONACO_EDITOR_VERSION = (function() {
  17. const packageJsonPath = path.join(__dirname, 'package.json');
  18. const packageJson = JSON.parse(fs.readFileSync(packageJsonPath).toString());
  19. const version = packageJson.version;
  20. if (!/\d+\.\d+\.\d+/.test(version)) {
  21. console.log('unrecognized package.json version: ' + version);
  22. process.exit(0);
  23. }
  24. return version;
  25. })();
  26. async function _execute(task) {
  27. // Always invoke as if it were a callback task
  28. return new Promise((resolve, reject) => {
  29. if (task.length === 1) {
  30. // this is a calback task
  31. task((err) => {
  32. if (err) {
  33. return reject(err);
  34. }
  35. resolve();
  36. });
  37. return;
  38. }
  39. const taskResult = task();
  40. if (typeof taskResult === 'undefined') {
  41. // this is a sync task
  42. resolve();
  43. return;
  44. }
  45. if (typeof taskResult.then === 'function') {
  46. // this is a promise returning task
  47. taskResult.then(resolve, reject);
  48. return;
  49. }
  50. // this is a stream returning task
  51. taskResult.on('end', _ => resolve());
  52. taskResult.on('error', err => reject(err));
  53. });
  54. }
  55. function taskSeries(...tasks) {
  56. return async () => {
  57. for (let i = 0; i < tasks.length; i++) {
  58. await _execute(tasks[i]);
  59. }
  60. };
  61. }
  62. const cleanReleaseTask = function(cb) { rimraf('release', { maxBusyTries: 1 }, cb); };
  63. gulp.task('release', taskSeries(cleanReleaseTask, function() {
  64. return es.merge(
  65. // dev folder
  66. releaseOne('dev'),
  67. // min folder
  68. releaseOne('min'),
  69. // esm folder
  70. ESM_release(),
  71. // package.json
  72. gulp.src('package.json')
  73. .pipe(es.through(function(data) {
  74. var json = JSON.parse(data.contents.toString());
  75. json.private = false;
  76. data.contents = Buffer.from(JSON.stringify(json, null, ' '));
  77. this.emit('data', data);
  78. }))
  79. .pipe(gulp.dest('release')),
  80. gulp.src('CHANGELOG.md')
  81. .pipe(gulp.dest('release')),
  82. // min-maps folder
  83. gulp.src('node_modules/monaco-editor-core/min-maps/**/*')
  84. .pipe(gulp.dest('release/min-maps')),
  85. // other files
  86. gulp.src([
  87. 'node_modules/monaco-editor-core/LICENSE',
  88. 'node_modules/monaco-editor-core/monaco.d.ts',
  89. 'node_modules/monaco-editor-core/ThirdPartyNotices.txt',
  90. 'README.md'
  91. ])
  92. .pipe(addPluginDTS())
  93. .pipe(addPluginThirdPartyNotices())
  94. .pipe(gulp.dest('release'))
  95. )
  96. }));
  97. /**
  98. * Release to `dev` or `min`.
  99. */
  100. function releaseOne(type) {
  101. return es.merge(
  102. gulp.src('node_modules/monaco-editor-core/' + type + '/**/*')
  103. .pipe(addPluginContribs(type))
  104. .pipe(gulp.dest('release/' + type)),
  105. pluginStreams(type, 'release/' + type + '/')
  106. )
  107. }
  108. /**
  109. * Release plugins to `dev` or `min`.
  110. */
  111. function pluginStreams(type, destinationPath) {
  112. return es.merge(
  113. metadata.METADATA.PLUGINS.map(function(plugin) {
  114. return pluginStream(plugin, type, destinationPath);
  115. })
  116. );
  117. }
  118. /**
  119. * Release a plugin to `dev` or `min`.
  120. */
  121. function pluginStream(plugin, type, destinationPath) {
  122. var pluginPath = plugin.paths[`npm/${type}`]; // npm/dev or npm/min
  123. var contribPath = path.join(pluginPath, plugin.contrib.substr(plugin.modulePrefix.length)) + '.js';
  124. return (
  125. gulp.src([
  126. pluginPath + '/**/*',
  127. '!' + contribPath
  128. ])
  129. .pipe(es.through(function(data) {
  130. if (!/_\.contribution/.test(data.path)) {
  131. this.emit('data', data);
  132. return;
  133. }
  134. let contents = data.contents.toString();
  135. contents = contents.replace('define(["require", "exports"],', 'define(["require", "exports", "vs/editor/editor.api"],');
  136. data.contents = Buffer.from(contents);
  137. this.emit('data', data);
  138. }))
  139. .pipe(gulp.dest(destinationPath + plugin.modulePrefix))
  140. );
  141. }
  142. /**
  143. * Edit editor.main.js:
  144. * - rename the AMD module 'vs/editor/editor.main' to 'vs/editor/edcore.main'
  145. * - append monaco.contribution modules from plugins
  146. * - append new AMD module 'vs/editor/editor.main' that stiches things together
  147. */
  148. function addPluginContribs(type) {
  149. return es.through(function(data) {
  150. if (!/editor\.main\.js$/.test(data.path)) {
  151. this.emit('data', data);
  152. return;
  153. }
  154. var contents = data.contents.toString();
  155. // Rename the AMD module 'vs/editor/editor.main' to 'vs/editor/edcore.main'
  156. contents = contents.replace(/"vs\/editor\/editor\.main\"/, '"vs/editor/edcore.main"');
  157. var extraContent = [];
  158. var allPluginsModuleIds = [];
  159. metadata.METADATA.PLUGINS.forEach(function(plugin) {
  160. allPluginsModuleIds.push(plugin.contrib);
  161. var pluginPath = plugin.paths[`npm/${type}`]; // npm/dev or npm/min
  162. var contribPath = path.join(__dirname, pluginPath, plugin.contrib.substr(plugin.modulePrefix.length)) + '.js';
  163. var contribContents = fs.readFileSync(contribPath).toString();
  164. // Check for the anonymous define call case 1
  165. // transform define(function() {...}) to define("moduleId",["require"],function() {...})
  166. var anonymousContribDefineCase1 = contribContents.indexOf('define(function');
  167. if (anonymousContribDefineCase1 >= 0) {
  168. contribContents = (
  169. contribContents.substring(0, anonymousContribDefineCase1)
  170. + `define("${plugin.contrib}",["require"],function`
  171. + contribContents.substring(anonymousContribDefineCase1 + 'define(function'.length)
  172. );
  173. }
  174. // Check for the anonymous define call case 2
  175. // transform define([ to define("moduleId",[
  176. var anonymousContribDefineCase2 = contribContents.indexOf('define([');
  177. if (anonymousContribDefineCase2 >= 0) {
  178. contribContents = (
  179. contribContents.substring(0, anonymousContribDefineCase2)
  180. + `define("${plugin.contrib}",[`
  181. + contribContents.substring(anonymousContribDefineCase2 + 'define(['.length)
  182. );
  183. }
  184. var contribDefineIndex = contribContents.indexOf('define("' + plugin.contrib);
  185. if (contribDefineIndex === -1) {
  186. contribDefineIndex = contribContents.indexOf('define(\'' + plugin.contrib);
  187. if (contribDefineIndex === -1) {
  188. console.error('(1) CANNOT DETERMINE AMD define location for contribution', pluginPath);
  189. process.exit(-1);
  190. }
  191. }
  192. var depsEndIndex = contribContents.indexOf(']', contribDefineIndex);
  193. if (contribDefineIndex === -1) {
  194. console.error('(2) CANNOT DETERMINE AMD define location for contribution', pluginPath);
  195. process.exit(-1);
  196. }
  197. contribContents = contribContents.substring(0, depsEndIndex) + ',"vs/editor/editor.api"' + contribContents.substring(depsEndIndex);
  198. contribContents = contribContents.replace(
  199. 'define("vs/basic-languages/_.contribution",["require","exports"],',
  200. 'define("vs/basic-languages/_.contribution",["require","exports","vs/editor/editor.api"],',
  201. );
  202. extraContent.push(contribContents);
  203. });
  204. extraContent.push(`define("vs/editor/editor.main", ["vs/editor/edcore.main","${allPluginsModuleIds.join('","')}"], function(api) { return api; });`);
  205. var insertIndex = contents.lastIndexOf('//# sourceMappingURL=');
  206. if (insertIndex === -1) {
  207. insertIndex = contents.length;
  208. }
  209. contents = contents.substring(0, insertIndex) + '\n' + extraContent.join('\n') + '\n' + contents.substring(insertIndex);
  210. data.contents = Buffer.from(contents);
  211. this.emit('data', data);
  212. });
  213. }
  214. function ESM_release() {
  215. return es.merge(
  216. gulp.src([
  217. 'node_modules/monaco-editor-core/esm/**/*',
  218. // we will create our own editor.api.d.ts which also contains the plugins API
  219. '!node_modules/monaco-editor-core/esm/vs/editor/editor.api.d.ts'
  220. ])
  221. .pipe(ESM_addImportSuffix())
  222. .pipe(ESM_addPluginContribs('release/esm'))
  223. .pipe(gulp.dest('release/esm')),
  224. ESM_pluginStreams('release/esm/')
  225. )
  226. }
  227. /**
  228. * Release plugins to `esm`.
  229. */
  230. function ESM_pluginStreams(destinationPath) {
  231. return es.merge(
  232. metadata.METADATA.PLUGINS.map(function(plugin) {
  233. return ESM_pluginStream(plugin, destinationPath);
  234. })
  235. );
  236. }
  237. /**
  238. * Release a plugin to `esm`.
  239. * Adds a dependency to 'vs/editor/editor.api' in contrib files in order for `monaco` to be defined.
  240. * Rewrites imports for 'monaco-editor-core/**'
  241. */
  242. function ESM_pluginStream(plugin, destinationPath) {
  243. const DESTINATION = path.join(__dirname, destinationPath);
  244. let pluginPath = plugin.paths[`esm`];
  245. return (
  246. gulp.src([
  247. pluginPath + '/**/*'
  248. ])
  249. .pipe(es.through(function(data) {
  250. if (!/\.js$/.test(data.path)) {
  251. this.emit('data', data);
  252. return;
  253. }
  254. let contents = data.contents.toString();
  255. const info = ts.preProcessFile(contents);
  256. for (let i = info.importedFiles.length - 1; i >= 0; i--) {
  257. const importText = info.importedFiles[i].fileName;
  258. const pos = info.importedFiles[i].pos;
  259. const end = info.importedFiles[i].end;
  260. if (!/(^\.\/)|(^\.\.\/)/.test(importText)) {
  261. // non-relative import
  262. if (!/^monaco-editor-core/.test(importText)) {
  263. console.error(`Non-relative import for unknown module: ${importText} in ${data.path}`);
  264. process.exit(0);
  265. }
  266. const myFileDestPath = path.join(DESTINATION, plugin.modulePrefix, data.relative);
  267. const importFilePath = path.join(DESTINATION, importText.substr('monaco-editor-core/esm/'.length));
  268. let relativePath = path.relative(path.dirname(myFileDestPath), importFilePath).replace(/\\/g, '/');
  269. if (!/(^\.\/)|(^\.\.\/)/.test(relativePath)) {
  270. relativePath = './' + relativePath;
  271. }
  272. contents = (
  273. contents.substring(0, pos + 1)
  274. + relativePath
  275. + contents.substring(end + 1)
  276. );
  277. }
  278. }
  279. data.contents = Buffer.from(contents);
  280. this.emit('data', data);
  281. }))
  282. .pipe(es.through(function(data) {
  283. if (!/monaco\.contribution\.js$/.test(data.path)) {
  284. this.emit('data', data);
  285. return;
  286. }
  287. const myFileDestPath = path.join(DESTINATION, plugin.modulePrefix, data.relative);
  288. const apiFilePath = path.join(DESTINATION, 'vs/editor/editor.api');
  289. let relativePath = path.relative(path.dirname(myFileDestPath), apiFilePath).replace(/\\/g, '/');
  290. if (!/(^\.\/)|(^\.\.\/)/.test(relativePath)) {
  291. relativePath = './' + relativePath;
  292. }
  293. let contents = data.contents.toString();
  294. contents = (
  295. `import '${relativePath}';\n` +
  296. contents
  297. );
  298. data.contents = Buffer.from(contents);
  299. this.emit('data', data);
  300. }))
  301. .pipe(ESM_addImportSuffix())
  302. .pipe(gulp.dest(destinationPath + plugin.modulePrefix))
  303. );
  304. }
  305. function ESM_addImportSuffix() {
  306. return es.through(function(data) {
  307. if (!/\.js$/.test(data.path)) {
  308. this.emit('data', data);
  309. return;
  310. }
  311. let contents = data.contents.toString();
  312. const info = ts.preProcessFile(contents);
  313. for (let i = info.importedFiles.length - 1; i >= 0; i--) {
  314. const importText = info.importedFiles[i].fileName;
  315. const pos = info.importedFiles[i].pos;
  316. const end = info.importedFiles[i].end;
  317. if (/\.css$/.test(importText)) {
  318. continue;
  319. }
  320. contents = (
  321. contents.substring(0, pos + 1)
  322. + importText + '.js'
  323. + contents.substring(end + 1)
  324. );
  325. }
  326. data.contents = Buffer.from(contents);
  327. this.emit('data', data);
  328. });
  329. }
  330. /**
  331. * - Rename esm/vs/editor/editor.main.js to esm/vs/editor/edcore.main.js
  332. * - Create esm/vs/editor/editor.main.js that that stiches things together
  333. */
  334. function ESM_addPluginContribs(dest) {
  335. const DESTINATION = path.join(__dirname, dest);
  336. return es.through(function(data) {
  337. if (!/editor\.main\.js$/.test(data.path)) {
  338. this.emit('data', data);
  339. return;
  340. }
  341. this.emit('data', new File({
  342. path: data.path.replace(/editor\.main/, 'edcore.main'),
  343. base: data.base,
  344. contents: data.contents
  345. }));
  346. const mainFileDestPath = path.join(DESTINATION, 'vs/editor/editor.main.js');
  347. let mainFileImports = [];
  348. metadata.METADATA.PLUGINS.forEach(function(plugin) {
  349. const contribDestPath = path.join(DESTINATION, plugin.contrib);
  350. let relativePath = path.relative(path.dirname(mainFileDestPath), contribDestPath).replace(/\\/g, '/');
  351. if (!/(^\.\/)|(^\.\.\/)/.test(relativePath)) {
  352. relativePath = './' + relativePath;
  353. }
  354. mainFileImports.push(relativePath);
  355. });
  356. let mainFileContents = (
  357. mainFileImports.map((name) => `import '${name}';`).join('\n')
  358. + `\n\nexport * from './edcore.main';`
  359. );
  360. this.emit('data', new File({
  361. path: data.path,
  362. base: data.base,
  363. contents: Buffer.from(mainFileContents)
  364. }));
  365. });
  366. }
  367. /**
  368. * Edit monaco.d.ts:
  369. * - append monaco.d.ts from plugins
  370. */
  371. function addPluginDTS() {
  372. return es.through(function(data) {
  373. if (!/monaco\.d\.ts$/.test(data.path)) {
  374. this.emit('data', data);
  375. return;
  376. }
  377. var contents = data.contents.toString();
  378. var extraContent = [];
  379. metadata.METADATA.PLUGINS.forEach(function(plugin) {
  380. var pluginPath = plugin.paths[`npm/min`]; // npm/dev or npm/min
  381. var dtsPath = path.join(pluginPath, '../monaco.d.ts');
  382. try {
  383. let plugindts = fs.readFileSync(dtsPath).toString();
  384. plugindts = plugindts.replace('declare module', 'declare namespace');
  385. extraContent.push(plugindts);
  386. } catch (err) {
  387. return;
  388. }
  389. });
  390. contents = [
  391. '/*!-----------------------------------------------------------',
  392. ' * Copyright (c) Microsoft Corporation. All rights reserved.',
  393. ' * Type definitions for monaco-editor v'+MONACO_EDITOR_VERSION,
  394. ' * Released under the MIT license',
  395. '*-----------------------------------------------------------*/',
  396. ].join('\n') + '\n' + contents + '\n' + extraContent.join('\n');
  397. // Ensure consistent indentation and line endings
  398. contents = cleanFile(contents);
  399. data.contents = Buffer.from(contents);
  400. this.emit('data', new File({
  401. path: path.join(path.dirname(data.path), 'esm/vs/editor/editor.api.d.ts'),
  402. base: data.base,
  403. contents: Buffer.from(toExternalDTS(contents))
  404. }));
  405. fs.writeFileSync('website/playground/monaco.d.ts.txt', contents);
  406. fs.writeFileSync('monaco.d.ts', contents);
  407. this.emit('data', data);
  408. });
  409. }
  410. function toExternalDTS(contents) {
  411. let lines = contents.split('\n');
  412. let killNextCloseCurlyBrace = false;
  413. for (let i = 0; i < lines.length; i++) {
  414. let line = lines[i];
  415. if (killNextCloseCurlyBrace) {
  416. if ('}' === line) {
  417. lines[i] = '';
  418. killNextCloseCurlyBrace = false;
  419. continue;
  420. }
  421. if (line.indexOf(' ') === 0) {
  422. lines[i] = line.substr(4);
  423. } else if (line.charAt(0) === '\t') {
  424. lines[i] = line.substr(1);
  425. }
  426. continue;
  427. }
  428. if ('declare namespace monaco {' === line) {
  429. lines[i] = '';
  430. killNextCloseCurlyBrace = true;
  431. continue;
  432. }
  433. if (line.indexOf('declare namespace monaco.') === 0) {
  434. lines[i] = line.replace('declare namespace monaco.', 'export namespace ');
  435. }
  436. }
  437. return lines.join('\n');
  438. }
  439. /**
  440. * Normalize line endings and ensure consistent 4 spaces indentation
  441. */
  442. function cleanFile(contents) {
  443. return contents.split(/\r\n|\r|\n/).map(function(line) {
  444. var m = line.match(/^(\t+)/);
  445. if (!m) {
  446. return line;
  447. }
  448. var tabsCount = m[1].length;
  449. var newIndent = '';
  450. for (var i = 0; i < 4 * tabsCount; i++) {
  451. newIndent += ' ';
  452. }
  453. return newIndent + line.substring(tabsCount);
  454. }).join('\n');
  455. }
  456. /**
  457. * Edit ThirdPartyNotices.txt:
  458. * - append ThirdPartyNotices.txt from plugins
  459. */
  460. function addPluginThirdPartyNotices() {
  461. return es.through(function(data) {
  462. if (!/ThirdPartyNotices\.txt$/.test(data.path)) {
  463. this.emit('data', data);
  464. return;
  465. }
  466. var contents = data.contents.toString();
  467. var extraContent = [];
  468. metadata.METADATA.PLUGINS.forEach(function(plugin) {
  469. if (!plugin.thirdPartyNotices) {
  470. return;
  471. }
  472. console.log('ADDING ThirdPartyNotices from ' + plugin.thirdPartyNotices);
  473. var thirdPartyNoticeContent = fs.readFileSync(plugin.thirdPartyNotices).toString();
  474. thirdPartyNoticeContent = thirdPartyNoticeContent.split('\n').slice(8).join('\n');
  475. extraContent.push(thirdPartyNoticeContent);
  476. });
  477. contents += '\n' + extraContent.join('\n');
  478. data.contents = Buffer.from(contents);
  479. this.emit('data', data);
  480. });
  481. }
  482. // --- website
  483. const cleanWebsiteTask = function(cb) { rimraf('../monaco-editor-website', { maxBusyTries: 1 }, cb); };
  484. const buildWebsiteTask = taskSeries(cleanWebsiteTask, function() {
  485. const initialCWD = process.cwd();
  486. function replaceWithRelativeResource(dataPath, contents, regex, callback) {
  487. return contents.replace(regex, function(_, m0) {
  488. var filePath = path.join(path.dirname(dataPath), m0);
  489. return callback(m0, fs.readFileSync(filePath));
  490. });
  491. }
  492. var waiting = 0;
  493. var done = false;
  494. return (
  495. es.merge(
  496. gulp.src([
  497. 'website/**/*',
  498. '!website/typedoc-theme/**'
  499. ], { dot: true })
  500. .pipe(es.through(function(data) {
  501. if (!data.contents || !/\.(html)$/.test(data.path) || /new-samples/.test(data.path)) {
  502. return this.emit('data', data);
  503. }
  504. var contents = data.contents.toString();
  505. contents = contents.replace(/\.\.\/release\/dev/g, 'node_modules/monaco-editor/min');
  506. contents = contents.replace(/{{version}}/g, MONACO_EDITOR_VERSION);
  507. // contents = contents.replace('&copy; 2017 Microsoft', '&copy; 2017 Microsoft [' + builtTime + ']');
  508. // Preload xhr contents
  509. contents = replaceWithRelativeResource(data.path, contents, /<pre data-preload="([^"]+)".*/g, function(m0, fileContents) {
  510. return (
  511. '<pre data-preload="' + m0 + '" style="display:none">'
  512. + fileContents.toString('utf8')
  513. .replace(/&/g, '&amp;')
  514. .replace(/</g, '&lt;')
  515. .replace(/>/g, '&gt;')
  516. + '</pre>'
  517. );
  518. });
  519. // Inline fork.png
  520. contents = replaceWithRelativeResource(data.path, contents, /src="(\.\/fork.png)"/g, function(m0, fileContents) {
  521. return (
  522. 'src="data:image/png;base64,' + fileContents.toString('base64') + '"'
  523. );
  524. });
  525. var allCSS = '';
  526. var tmpcontents = replaceWithRelativeResource(data.path, contents, /<link data-inline="yes-please" href="([^"]+)".*/g, function(m0, fileContents) {
  527. allCSS += fileContents.toString('utf8');
  528. return '';
  529. });
  530. tmpcontents = tmpcontents.replace(/<script.*/g, '');
  531. tmpcontents = tmpcontents.replace(/<link.*/g, '');
  532. waiting++;
  533. uncss(tmpcontents, {
  534. raw: allCSS,
  535. ignore: [/\.alert\b/, /\.alert-error\b/, /\.playground-page\b/]
  536. }, function(err, output) {
  537. waiting--;
  538. if (!err) {
  539. output = new CleanCSS().minify(output).styles;
  540. var isFirst = true;
  541. contents = contents.replace(/<link data-inline="yes-please" href="([^"]+)".*/g, function(_, m0) {
  542. if (isFirst) {
  543. isFirst = false;
  544. return '<style>' + output + '</style>';
  545. }
  546. return '';
  547. });
  548. }
  549. // Inline javascript
  550. contents = replaceWithRelativeResource(data.path, contents, /<script data-inline="yes-please" src="([^"]+)".*/g, function(m0, fileContents) {
  551. return '<script>' + fileContents.toString('utf8') + '</script>';
  552. });
  553. data.contents = Buffer.from(contents.split(/\r\n|\r|\n/).join('\n'));
  554. this.emit('data', data);
  555. if (done && waiting === 0) {
  556. this.emit('end');
  557. }
  558. }.bind(this));
  559. }, function() {
  560. done = true;
  561. if (waiting === 0) {
  562. this.emit('end');
  563. }
  564. }))
  565. .pipe(gulp.dest('../monaco-editor-website')),
  566. // TypeDoc is silly and consumes the `exclude` option.
  567. // This option does not make it to typescript compiler, which ends up including /node_modules/ .d.ts files.
  568. // We work around this by changing the cwd... :O
  569. gulp.src('monaco.d.ts')
  570. .pipe(es.through(undefined, function() {
  571. process.chdir(os.tmpdir());
  572. this.emit('end');
  573. }))
  574. .pipe(typedoc({
  575. mode: 'file',
  576. out: path.join(__dirname, '../monaco-editor-website/api'),
  577. includeDeclarations: true,
  578. theme: path.join(__dirname, 'website/typedoc-theme'),
  579. entryPoint: 'monaco',
  580. name: 'Monaco Editor API v' + MONACO_EDITOR_VERSION,
  581. readme: 'none',
  582. hideGenerator: true
  583. }))
  584. .pipe(es.through(undefined, function() {
  585. process.chdir(initialCWD);
  586. this.emit('end');
  587. }))
  588. )
  589. .pipe(es.through(function(data) {
  590. this.emit('data', data);
  591. }, function() {
  592. // temporarily create package.json so that npm install doesn't bark
  593. fs.writeFileSync('../monaco-editor-website/package.json', '{}');
  594. fs.writeFileSync('../monaco-editor-website/.nojekyll', '');
  595. cp.execSync('npm install monaco-editor', {
  596. cwd: path.join(__dirname, '../monaco-editor-website')
  597. });
  598. fs.unlinkSync('../monaco-editor-website/package.json');
  599. this.emit('end');
  600. }))
  601. );
  602. });
  603. gulp.task('build-website', buildWebsiteTask);
  604. gulp.task('website', taskSeries(buildWebsiteTask, function() {
  605. cp.execSync('git init', {
  606. cwd: path.join(__dirname, '../monaco-editor-website')
  607. });
  608. let remoteUrl = cp.execSync('git remote get-url origin')
  609. let committerUserName = cp.execSync('git log --format=\'%an\' -1');
  610. let committerEmail = cp.execSync('git log --format=\'%ae\' -1');
  611. cp.execSync(`git config user.name ${committerUserName}`, {
  612. cwd: path.join(__dirname, '../monaco-editor-website')
  613. });
  614. cp.execSync(`git config user.email ${committerEmail}`, {
  615. cwd: path.join(__dirname, '../monaco-editor-website')
  616. });
  617. cp.execSync(`git remote add origin ${remoteUrl}`, {
  618. cwd: path.join(__dirname, '../monaco-editor-website')
  619. });
  620. cp.execSync('git checkout -b gh-pages', {
  621. cwd: path.join(__dirname, '../monaco-editor-website')
  622. });
  623. cp.execSync('git add .', {
  624. cwd: path.join(__dirname, '../monaco-editor-website')
  625. });
  626. cp.execSync('git commit -m "Publish website"', {
  627. cwd: path.join(__dirname, '../monaco-editor-website')
  628. });
  629. console.log('RUN monaco-editor-website>git push origin gh-pages --force');
  630. }));
  631. const generateTestSamplesTask = function() {
  632. var sampleNames = fs.readdirSync(path.join(__dirname, 'test/samples'));
  633. var samples = sampleNames.map(function(sampleName) {
  634. var samplePath = path.join(__dirname, 'test/samples', sampleName);
  635. var sampleContent = fs.readFileSync(samplePath).toString();
  636. return {
  637. name: sampleName,
  638. content: sampleContent
  639. };
  640. });
  641. var prefix = '//This is a generated file via gulp generate-test-samples\ndefine([], function() { return';
  642. var suffix = '; });'
  643. fs.writeFileSync(path.join(__dirname, 'test/samples-all.generated.js'), prefix + JSON.stringify(samples, null, '\t') + suffix );
  644. var PLAY_SAMPLES = require(path.join(WEBSITE_GENERATED_PATH, 'all.js')).PLAY_SAMPLES;
  645. var locations = [];
  646. for (var i = 0; i < PLAY_SAMPLES.length; i++) {
  647. var sample = PLAY_SAMPLES[i];
  648. var sampleId = sample.id;
  649. var samplePath = path.join(WEBSITE_GENERATED_PATH, sample.path);
  650. var html = fs.readFileSync(path.join(samplePath, 'sample.html'));
  651. var js = fs.readFileSync(path.join(samplePath, 'sample.js'));
  652. var css = fs.readFileSync(path.join(samplePath, 'sample.css'));
  653. var result = [
  654. '<!DOCTYPE html>',
  655. '<!-- THIS IS A GENERATED FILE VIA gulp generate-test-samples -->',
  656. '<html>',
  657. '<head>',
  658. ' <base href="..">',
  659. ' <meta http-equiv="X-UA-Compatible" content="IE=edge" />',
  660. ' <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />',
  661. '</head>',
  662. '<body>',
  663. '<style>',
  664. '/*----------------------------------------SAMPLE CSS START*/',
  665. '',
  666. css,
  667. '',
  668. '/*----------------------------------------SAMPLE CSS END*/',
  669. '</style>',
  670. '<a class="loading-opts" href="playground.generated/index.html">[&lt;&lt; BACK]</a> <br/>',
  671. 'THIS IS A GENERATED FILE VIA gulp generate-test-samples',
  672. '',
  673. '<div id="bar" style="margin-bottom: 6px;"></div>',
  674. '',
  675. '<div style="clear:both"></div>',
  676. '<div id="outer-container" style="width:800px;height:450px;border: 1px solid grey">',
  677. '<!-- ----------------------------------------SAMPLE HTML START-->',
  678. '',
  679. html,
  680. '',
  681. '<!-- ----------------------------------------SAMPLE HTML END-->',
  682. '</div>',
  683. '<div style="clear:both"></div>',
  684. '',
  685. '<script src="../metadata.js"></script>',
  686. '<script src="dev-setup.js"></script>',
  687. '<script>',
  688. 'loadEditor(function() {',
  689. '/*----------------------------------------SAMPLE JS START*/',
  690. '',
  691. js,
  692. '',
  693. '/*----------------------------------------SAMPLE CSS END*/',
  694. '});',
  695. '</script>',
  696. '</body>',
  697. '</html>',
  698. ];
  699. fs.writeFileSync(path.join(__dirname, 'test/playground.generated/' + sampleId + '.html'), result.join('\n'));
  700. locations.push({
  701. path: sampleId + '.html',
  702. name: sample.chapter + ' &gt; ' + sample.name
  703. })
  704. }
  705. var index = [
  706. '<!DOCTYPE html>',
  707. '<!-- THIS IS A GENERATED FILE VIA gulp generate-test-samples -->',
  708. '<html>',
  709. '<head>',
  710. ' <base href="..">',
  711. '</head>',
  712. '<body>',
  713. '<a class="loading-opts" href="index.html">[&lt;&lt; BACK]</a><br/>',
  714. 'THIS IS A GENERATED FILE VIA gulp generate-test-samples<br/><br/>',
  715. locations.map(function(location) {
  716. return '<a class="loading-opts" href="playground.generated/' + location.path + '">' + location.name + '</a>';
  717. }).join('<br/>\n'),
  718. '<script src="../metadata.js"></script>',
  719. '<script src="dev-setup.js"></script>',
  720. '</body>',
  721. '</html>',
  722. ]
  723. fs.writeFileSync(path.join(__dirname, 'test/playground.generated/index.html'), index.join('\n'));
  724. };
  725. gulp.task('simpleserver', taskSeries(generateTestSamplesTask, function() {
  726. httpServer.createServer({ root: '../', cache: 5 }).listen(8080);
  727. httpServer.createServer({ root: '../', cache: 5 }).listen(8088);
  728. console.log('LISTENING on 8080 and 8088');
  729. }));