123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- // Gulp Tools
- var fs = require("fs");
- var path = require("path");
- var through = require('through2');
- var PluginError = require('plugin-error');
- var colorConsole = require("../../NodeHelpers/colorConsole");
- var config = require("../../Config/config");
- const indexExlclusion = ["States", "EmitterTypes"];
- const forbiddenImports = ["meshBuilder"];
- const mapping = {};
- config.modules.forEach(moduleName => {
- mapping[config[moduleName].build.umd.packageName] = moduleName;
- });
- var validatePath = function(fileLocation, directory, module, lineNumber, errors, isExport) {
- let expressionType = isExport ? "Export" : "Import";
- //Not checking svg files
- if(module.endsWith(".svg")){
- return;
- }
- let internalModulePath = path.join(directory, module + ".ts");
- // Check .ts path.
- if (!fs.existsSync(internalModulePath)) {
- internalModulePath = path.join(directory, module + ".tsx");
- // Check .tsx path.
- if (!fs.existsSync(internalModulePath)) {
- // If not found, check index.ts for legacy and index files.
- if (fileLocation.indexOf("legacy") > -1 || fileLocation.indexOf("index") > -1) {
- internalModulePath = path.join(directory, module, "index.ts");
- if (!fs.existsSync(internalModulePath)) {
- errors.push(`Line ${lineNumber} ${expressionType} from folder only allows if index is present. ${module}`);
- }
- }
- else {
- errors.push(`Line ${lineNumber} ${expressionType}s ${module} needs to be full path (not from directory) for tree shaking.`);
- }
- }
- }
- if (internalModulePath.indexOf("index.") > -1) {
- if (fileLocation.indexOf("legacy") === -1) {
- if (isExport) {
- internalModulePath = path.join(directory, module + ".ts");
- // Check .ts path.
- if (!fs.existsSync(internalModulePath)) {
- errors.push(`Line ${lineNumber} Exports ${module} should be from the full path including index.`);
- }
- }
- else {
- let excluded = false;
- for (let exclusion of indexExlclusion) {
- if (internalModulePath.indexOf(exclusion) > -1) {
- excluded = true;
- break;
- }
- }
- if (!excluded && fileLocation.indexOf("index.ts") === -1) {
- errors.push(`Line ${internalModulePath} Imports ${module} should not be from index for tree shaking.`);
- }
- }
- }
- }
- if (!isExport) {
- for (let forbiddenImport of forbiddenImports) {
- if (module.endsWith(forbiddenImport)) {
- errors.push(`Line ${lineNumber} ${expressionType}s ${module} is forbidden for tree shaking.`);
- }
- }
- }
- }
- var validateImports = function(data, fileLocation, options) {
- var str = "" + data;
- var errors = [];
- // Start process by extracting all lines.
- let lines = str.split('\n');
- // Let's go line by line and check if we have special folder replacements
- // Replaces declare module '...'; by declare module 'babylonjs/...'; for instance
- mainSearch:
- for (let index = 0; index < lines.length; index++) {
- let line = lines[index];
- let module = null, externalModule = null;
- // Find Imports.
- if (line.indexOf("import") > -1) {
- let regexTypeImport = new RegExp(`import .* from ['"](.*)['"];`, "g");
- let match = regexTypeImport.exec(line);
- if (match) {
- module = match[1];
- }
- else {
- let regexSideEffectImport = new RegExp(`import \\(*['"](.*)['"]\\)*;`, "g");
- let matchSideEffects = regexSideEffectImport.exec(line);
- if (matchSideEffects) {
- module = matchSideEffects[1];
- }
- else {
- continue;
- }
- }
- // Checks if line is about external module
- if (options.externals) {
- for (let ext in options.externals) {
- if (line.indexOf(ext) > -1) {
- externalModule = ext;
- break;
- }
- }
- }
- if (options.uncheckedLintImports) {
- for (let ext of options.uncheckedLintImports) {
- if (line.indexOf(ext) > -1) {
- continue mainSearch;
- }
- }
- }
- // Check if path is correct internal.
- if (externalModule) {
- const splitter = module.indexOf("/");
- if (splitter === -1 && module !== "babylonjs-gltf2interface") {
- errors.push(`Line ${index + 1} Import ${module} needs to be relative.`);
- }
- const baseModule = module.substring(0, splitter);
- if (mapping[baseModule]) {
- const configName = mapping[baseModule];
- const directory = config[configName].computed.srcDirectory;
- module = module.substring(splitter);
- validatePath(fileLocation, directory, module, index + 1, errors, false);
- }
- }
- else {
- // Check Relative.
- if (!module.startsWith(".")) {
- errors.push(`Line ${index + 1} Import ${module} needs to be relative.`);
- }
- else {
- const directory = path.dirname(fileLocation);
- validatePath(fileLocation, directory, module, index + 1, errors, false);
- }
- }
- }
- // Find Exports.
- if (options.isCore && line.indexOf("export") > -1) {
- let regexTypeExport = new RegExp(`export .* from ['"](.*)['"];`, "g");
- let match = regexTypeExport.exec(line);
- if (match) {
- module = match[1];
- // Checks if line is about external module
- if (options.externals) {
- for (let ext in options.externals) {
- if (line.indexOf(ext) > -1) {
- externalModule = ext;
- break;
- }
- }
- }
- // Check if path is correct internal.
- if (externalModule) {
- const splitter = module.indexOf("/");
- const baseModule = module.substring(0, splitter);
- if (mapping[baseModule]) {
- const configName = mapping[baseModule];
- const directory = config[configName].computed.srcDirectory;
- module = module.substring(splitter);
- validatePath(fileLocation, directory, module, index + 1, errors, true);
- }
- }
- else {
- // Check Relative.
- if (!module.startsWith(".")) {
- errors.push(`Line ${index + 1} Export ${module} needs to be relative.`);
- }
- else {
- const directory = path.dirname(fileLocation);
- validatePath(fileLocation, directory, module, index + 1, errors, true);
- }
- }
- }
- }
- }
- return errors;
- }
- function gulpValidateImports(options) {
- var globalErrors = [];
- return through.obj(function(file, enc, cb) {
- if (file.isNull()) {
- cb(null, file);
- return;
- }
- if (file.isStream()) {
- cb(new PluginError("Validate imports", "Streaming not supported."));
- }
- let data = file.contents.toString();
- let result = validateImports(data, file.path, options);
- if (result.length > 0) {
- for (let error of result) {
- globalErrors.push({
- message: error,
- path: file.path
- });
- }
- }
- return cb();
- },
- function endStream(cb) {
- if (globalErrors.length > 0) {
- for (let error of globalErrors) {
- colorConsole.error(error.message + " " + error.path);
- }
- colorConsole.error(`Import validation failed with ${globalErrors.length} errors.`);
- var finalMessage = new PluginError('gulp-validateImports', `gulp-validateImports: ${globalErrors.length} errors found.`);
- this.emit('error', finalMessage);
- }
- cb();
- });
- }
- module.exports = gulpValidateImports;
|