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 Relative.
  46. if (!externalModule && !module.startsWith(".")) {
  47. errors.push(`Line ${index} Imports needs to be relative. ${module}`);
  48. }
  49. // Check if path is correct internal.
  50. if (!externalModule) {
  51. const directory = path.dirname(fileLocation);
  52. let internalModulePath = path.join(directory, module + ".ts");
  53. if (!fs.existsSync(internalModulePath)) {
  54. let internalModulePath = path.join(directory, module + ".tsx");
  55. if (!fs.existsSync(internalModulePath)) {
  56. if (fileLocation.indexOf("legacy") > -1 || fileLocation.indexOf("index") > -1) {
  57. let internalModulePath = path.join(directory, module + "index.ts");
  58. if (!fs.existsSync(internalModulePath)) {
  59. let internalModulePath = path.join(directory, module + "/index.ts");
  60. if (!fs.existsSync(internalModulePath)) {
  61. errors.push(`Line ${index} Imports needs to be full path. ${module}`);
  62. }
  63. }
  64. }
  65. else {
  66. errors.push(`Line ${index} Imports ${module} needs to be full path.`);
  67. }
  68. }
  69. }
  70. if (internalModulePath.indexOf("index.") > -1) {
  71. if (fileLocation.indexOf("legacy") === -1) {
  72. let excluded = false;
  73. for (let exclusion of indexExlclusion) {
  74. if (internalModulePath.indexOf(exclusion) > -1) {
  75. excluded = true;
  76. break;
  77. }
  78. }
  79. if (!excluded) {
  80. errors.push(`Line ${index} Imports ${module} should not be from index for tree shaking.`);
  81. }
  82. }
  83. }
  84. }
  85. else {
  86. const mapping = {
  87. "babylonjs": "core",
  88. "babylonjs-loaders": "loaders",
  89. "babylonjs-serializers": "serializers",
  90. "babylonjs-gui": "gui",
  91. };
  92. const splitter = module.indexOf("/");
  93. const baseModule = module.substring(0, splitter);
  94. if (mapping[baseModule]) {
  95. const configName = mapping[baseModule];
  96. const directory = config[configName].computed.srcDirectory;
  97. module = module.substring(splitter);
  98. let internalModulePath = path.join(directory, module + ".ts");
  99. if (!fs.existsSync(internalModulePath)) {
  100. let internalModulePath = path.join(directory, module + ".tsx");
  101. if (!fs.existsSync(internalModulePath)) {
  102. if (fileLocation.indexOf("legacy") > -1 || fileLocation.indexOf("index") > -1) {
  103. let internalModulePath = path.join(directory, module + "index.ts");
  104. if (!fs.existsSync(internalModulePath)) {
  105. let internalModulePath = path.join(directory, module + "/index.ts");
  106. if (!fs.existsSync(internalModulePath)) {
  107. errors.push(`Line ${index} Imports needs to be full path. ${module}`);
  108. }
  109. }
  110. }
  111. else {
  112. errors.push(`Line ${index} Imports ${module} needs to be full path.`);
  113. }
  114. }
  115. }
  116. if (internalModulePath.indexOf("index.") > -1) {
  117. if (fileLocation.indexOf("legacy") === -1) {
  118. let excluded = false;
  119. for (let exclusion of indexExlclusion) {
  120. if (internalModulePath.indexOf(exclusion) > -1) {
  121. excluded = true;
  122. break;
  123. }
  124. }
  125. if (!excluded) {
  126. errors.push(`Line ${index} Imports ${module} should not be from index for tree shaking.`);
  127. }
  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;