gulp-validateImports.js 5.7 KB

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