8
0

utils.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /* jshint node: true, esnext: true */
  2. 'use strict';
  3. const path = require( 'path' );
  4. const gulp = require( 'gulp' );
  5. const rename = require( 'gulp-rename' );
  6. const babel = require( 'gulp-babel' );
  7. const gulpWatch = require( 'gulp-watch' );
  8. const gulpPlumber = require( 'gulp-plumber' );
  9. const gutil = require( 'gulp-util' );
  10. const multipipe = require( 'multipipe' );
  11. const sep = path.sep;
  12. const utils = {
  13. /**
  14. * Returns a stream of files matching the given glob pattern.
  15. *
  16. * @param {String} root The root directory.
  17. * @param {String} glob The glob pattern.
  18. * @param {Boolean} [watch] Whether to watch the files.
  19. * @returns {Stream}
  20. */
  21. src( root, glob, watch ) {
  22. const srcDir = path.join( root, glob );
  23. let stream = gulp.src( srcDir );
  24. if ( watch ) {
  25. stream = stream
  26. // Let's use plumber only when watching. In other cases we should fail quickly and loudly.
  27. .pipe( gulpPlumber() )
  28. .pipe( gulpWatch( srcDir ) );
  29. }
  30. return stream;
  31. },
  32. /**
  33. * Saves the files piped into this stream to the `dist/` directory.
  34. *
  35. * @param {String} distDir The `dist/` directory path.
  36. * @param {String} format The format of the distribution (`esnext`, `amd`, or `cjs`).
  37. * @returns {Stream}
  38. */
  39. dist( distDir, format ) {
  40. const destDir = path.join( distDir, format );
  41. return gulp.dest( destDir );
  42. },
  43. /**
  44. * Transpiles files piped into this stream to the given format (`amd` or `cjs`).
  45. *
  46. * @param {String} format
  47. * @returns {Stream}
  48. */
  49. transpile( format ) {
  50. const babelModuleTranspilers = {
  51. amd: 'amd',
  52. cjs: 'commonjs'
  53. };
  54. const babelModuleTranspiler = babelModuleTranspilers[ format ];
  55. if ( !babelModuleTranspiler ) {
  56. throw new Error( `Incorrect format: ${ format }` );
  57. }
  58. return babel( {
  59. plugins: [ `transform-es2015-modules-${ babelModuleTranspiler }` ],
  60. // Ensure that all paths ends with '.js' because Require.JS (unlike Common.JS/System.JS)
  61. // will not add it to module names which look like paths.
  62. resolveModuleSource: ( source ) => {
  63. return utils.appendModuleExtension( source );
  64. }
  65. } );
  66. },
  67. /**
  68. * Creates a function adding transpilation pipes to the `pipes` param.
  69. * Used to generate `formats.reduce()` callback where `formats` is an array
  70. * of formats that should be generated.
  71. *
  72. * @param {String} distDir The `dist/` directory path.
  73. * @returns {Function}
  74. */
  75. addFormat( distDir ) {
  76. return ( pipes, format ) => {
  77. const conversionPipes = [];
  78. conversionPipes.push( utils.pickVersionedFile( format ) );
  79. if ( format != 'esnext' ) {
  80. conversionPipes.push( utils.transpile( format ) );
  81. }
  82. conversionPipes.push(
  83. utils.dist( distDir, format )
  84. .on( 'data', ( file ) => {
  85. gutil.log( `Finished writing '${ gutil.colors.cyan( file.path ) }'` );
  86. } )
  87. );
  88. pipes.push( multipipe.apply( null, conversionPipes ) );
  89. return pipes;
  90. };
  91. },
  92. /**
  93. * Allows us to pick one of files suffixed with the format (`__esnext`, `__amd`, or `__cjs`).
  94. *
  95. * For example: we have `load__esnext.js`, `load__amd.js` and `load__cjs.js`. After applying this
  96. * transformation when compiling code for a specific format the proper file will be renamed to `load.js`.
  97. *
  98. * @param {String} format
  99. * @returns {Stream}
  100. */
  101. pickVersionedFile( format ) {
  102. return rename( ( path ) => {
  103. const regexp = new RegExp( `__${ format }$` );
  104. path.basename = path.basename.replace( regexp, '' );
  105. } );
  106. },
  107. /**
  108. * Moves files out of `node_modules/ckeditor5-xxx/src/*` directories to `ckeditor5-xxx/*`.
  109. *
  110. * @param {RegExp} modulePathPattern
  111. * @returns {Stream}
  112. */
  113. unpackModules( modulePathPattern ) {
  114. return rename( ( file ) => {
  115. file.dirname = file.dirname.replace( modulePathPattern, `${ sep }$1${ sep }` );
  116. // Remove now empty src/ dirs.
  117. if ( !file.extname && file.basename == 'src' ) {
  118. file.basename = '';
  119. }
  120. } );
  121. },
  122. /**
  123. * Adds `ckeditor5/` to a file path.
  124. *
  125. * @returns {Stream}
  126. */
  127. wrapCKEditor5Module() {
  128. return rename( ( file ) => {
  129. file.dirname = path.join( file.dirname, 'ckeditor5' );
  130. } );
  131. },
  132. /**
  133. * Appends file extension to file URLs. Tries to not touch named modules.
  134. *
  135. * @param {String} source
  136. * @returns {String}
  137. */
  138. appendModuleExtension( source ) {
  139. if ( /^https?:|\.[\/\\]/.test( source ) && !/\.js$/.test( source ) ) {
  140. return source + '.js';
  141. }
  142. return source;
  143. }
  144. };
  145. module.exports = utils;