gulpfile.js 26 KB

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