gulp-validateImports.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. // Gulp Tools
  2. var fs = require("fs");
  3. var path = require("path");
  4. var through = require('through2');
  5. var PluginError = require('plugin-error');
  6. var colorConsole = require("../../NodeHelpers/colorConsole");
  7. var config = require("../../Config/config");
  8. const indexExlclusion = ["States", "EmitterTypes"];
  9. var validateImports = function(data, fileLocation, options) {
  10. var str = "" + data;
  11. var errors = [];
  12. // Start process by extracting all lines.
  13. let lines = str.split('\n');
  14. // Let's go line by line and check if we have special folder replacements
  15. // Replaces declare module '...'; by declare module 'babylonjs/...'; for instance
  16. for (let index = 0; index < lines.length; index++) {
  17. let line = lines[index];
  18. let module = null, externalModule = null;
  19. // Find Imports.
  20. if (line.indexOf("import") > -1) {
  21. let regexTypeImport = new RegExp(`import .* from ['"](.*)['"];`, "g");
  22. let match = regexTypeImport.exec(line);
  23. if (match) {
  24. module = match[1];
  25. }
  26. else {
  27. let regexSideEffectImport = new RegExp(`import \\(*['"](.*)['"]\\)*;`, "g");
  28. let matchSideEffects = regexSideEffectImport.exec(line);
  29. if (matchSideEffects) {
  30. module = matchSideEffects[1];
  31. }
  32. else {
  33. continue;
  34. }
  35. }
  36. // Checks if line is about external module
  37. if (options.externals) {
  38. for (let ext in options.externals) {
  39. if (line.indexOf(ext) > -1) {
  40. externalModule = ext;
  41. break;
  42. }
  43. }
  44. }
  45. // Check if path is correct internal.
  46. if (externalModule) {
  47. const mapping = {
  48. "babylonjs": "core",
  49. "babylonjs-loaders": "loaders",
  50. "babylonjs-serializers": "serializers",
  51. "babylonjs-gui": "gui",
  52. };
  53. const splitter = module.indexOf("/");
  54. const baseModule = module.substring(0, splitter);
  55. if (mapping[baseModule]) {
  56. const configName = mapping[baseModule];
  57. const directory = config[configName].computed.srcDirectory;
  58. module = module.substring(splitter);
  59. let internalModulePath = path.join(directory, module + ".ts");
  60. if (!fs.existsSync(internalModulePath)) {
  61. let internalModulePath = path.join(directory, module + ".tsx");
  62. if (!fs.existsSync(internalModulePath)) {
  63. if (fileLocation.indexOf("legacy") > -1 || fileLocation.indexOf("index") > -1) {
  64. let internalModulePath = path.join(directory, module + "index.ts");
  65. if (!fs.existsSync(internalModulePath)) {
  66. let internalModulePath = path.join(directory, module + "/index.ts");
  67. if (!fs.existsSync(internalModulePath)) {
  68. errors.push(`Line ${index} Imports needs to be full path. ${module}`);
  69. }
  70. }
  71. }
  72. else {
  73. errors.push(`Line ${index} Imports ${module} needs to be full path.`);
  74. }
  75. }
  76. }
  77. if (internalModulePath.indexOf("index.") > -1) {
  78. if (fileLocation.indexOf("legacy") === -1) {
  79. let excluded = false;
  80. for (let exclusion of indexExlclusion) {
  81. if (internalModulePath.indexOf(exclusion) > -1) {
  82. excluded = true;
  83. break;
  84. }
  85. }
  86. if (!excluded) {
  87. errors.push(`Line ${index} Imports ${module} should not be from index for tree shaking.`);
  88. }
  89. }
  90. }
  91. }
  92. }
  93. else {
  94. // Check Relative.
  95. if (!module.startsWith(".")) {
  96. errors.push(`Line ${index} Imports needs to be relative. ${module}`);
  97. }
  98. const directory = path.dirname(fileLocation);
  99. let internalModulePath = path.join(directory, module + ".ts");
  100. if (!fs.existsSync(internalModulePath)) {
  101. let internalModulePath = path.join(directory, module + ".tsx");
  102. if (!fs.existsSync(internalModulePath)) {
  103. if (fileLocation.indexOf("legacy") > -1 || fileLocation.indexOf("index") > -1) {
  104. let internalModulePath = path.join(directory, module + "index.ts");
  105. if (!fs.existsSync(internalModulePath)) {
  106. let internalModulePath = path.join(directory, module + "/index.ts");
  107. if (!fs.existsSync(internalModulePath)) {
  108. errors.push(`Line ${index} Imports needs to be full path. ${module}`);
  109. }
  110. }
  111. }
  112. else {
  113. errors.push(`Line ${index} Imports ${module} needs to be full path.`);
  114. }
  115. }
  116. }
  117. if (internalModulePath.indexOf("index.") > -1) {
  118. if (fileLocation.indexOf("legacy") === -1) {
  119. let excluded = false;
  120. for (let exclusion of indexExlclusion) {
  121. if (internalModulePath.indexOf(exclusion) > -1) {
  122. excluded = true;
  123. break;
  124. }
  125. }
  126. if (!excluded) {
  127. errors.push(`Line ${index} Imports ${module} should not be from index for tree shaking.`);
  128. }
  129. }
  130. }
  131. }
  132. }
  133. }
  134. return errors;
  135. }
  136. function gulpValidateImports(options) {
  137. var globalErrors = [];
  138. return through.obj(function (file, enc, cb) {
  139. if (file.isNull()) {
  140. cb(null, file);
  141. return;
  142. }
  143. if (file.isStream()) {
  144. cb(new PluginError("Validate imports", "Streaming not supported."));
  145. }
  146. let data = file.contents.toString();
  147. let result = validateImports(data, file.path, options);
  148. if (result.length > 0) {
  149. for (let error of result) {
  150. globalErrors.push({
  151. message: error,
  152. path: file.path
  153. });
  154. }
  155. }
  156. return cb();
  157. },
  158. function endStream(cb) {
  159. if (globalErrors.length > 0) {
  160. for (let error of globalErrors) {
  161. colorConsole.error(error.message + " " + error.path);
  162. }
  163. colorConsole.error(`Import validation failed with ${globalErrors.length} errors.`);
  164. var finalMessage = new PluginError('gulp-validateImports', `gulp-validateImports: ${globalErrors.length} errors found.`);
  165. this.emit('error', finalMessage);
  166. }
  167. cb();
  168. });
  169. }
  170. module.exports = gulpValidateImports;