123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- 'use strict';
- const path = require('path');
- function CaseSensitivePathsPlugin(options) {
- this.options = options || {};
- this.logger = this.options.logger || console;
- this.pathCache = new Map();
- this.reset();
- }
- CaseSensitivePathsPlugin.prototype.reset = function() {
- this.pathCache = new Map();
- this.fsOperations = 0;
- this.primed = false;
- };
- CaseSensitivePathsPlugin.prototype.getFilenamesInDir = function(dir, callback) {
- const that = this;
- const fs = this.compiler.inputFileSystem;
- this.fsOperations += 1;
- if (this.pathCache.has(dir)) {
- callback(this.pathCache.get(dir));
- return;
- }
- if (this.options.debug) {
- this.logger.log('[CaseSensitivePathsPlugin] Reading directory', dir);
- }
- fs.readdir(dir, (err, files) => {
- if (err) {
- if (that.options.debug) {
- this.logger.log(
- '[CaseSensitivePathsPlugin] Failed to read directory',
- dir,
- err,
- );
- }
- callback([]);
- return;
- }
- callback(files.map((f) => (f.normalize ? f.normalize('NFC') : f)));
- });
- };
- CaseSensitivePathsPlugin.prototype.fileExistsWithCase = function(
- filepath,
- callback,
- ) {
-
- const that = this;
- const dir = path.dirname(filepath);
- const filename = path.basename(filepath);
- const parsedPath = path.parse(dir);
-
- if (
- parsedPath.dir === parsedPath.root ||
- dir === '.' ||
- that.pathCache.has(filepath)
- ) {
- callback();
- return;
- }
-
-
- that.getFilenamesInDir(dir, (filenames) => {
-
- if (filenames.indexOf(filename) === -1) {
-
- let correctFilename = '!nonexistent';
- for (let i = 0; i < filenames.length; i += 1) {
- if (filenames[i].toLowerCase() === filename.toLowerCase()) {
- correctFilename = `\`${filenames[i]}\`.`;
- break;
- }
- }
- callback(correctFilename);
- return;
- }
-
- that.fileExistsWithCase(dir, (recurse) => {
-
-
- if (!recurse) {
- that.pathCache.set(dir, filenames);
- }
- callback(recurse);
- });
- });
- };
- CaseSensitivePathsPlugin.prototype.primeCache = function(callback) {
- if (this.primed) {
- callback();
- return;
- }
- const that = this;
-
-
- const currentPath = path.resolve();
- that.getFilenamesInDir(currentPath, (files) => {
- that.pathCache.set(currentPath,files);
- that.primed = true;
- callback();
- });
- };
- CaseSensitivePathsPlugin.prototype.apply = function(compiler) {
- this.compiler = compiler;
- const onDone = () => {
- if (this.options.debug) {
- this.logger.log(
- '[CaseSensitivePathsPlugin] Total filesystem reads:',
- this.fsOperations,
- );
- }
- this.reset();
- };
- const checkFile = (pathName, data, done) => {
- this.fileExistsWithCase(pathName, (realName) => {
- if (realName) {
- if (realName === '!nonexistent') {
-
- if (data.createData) done(null);
- else done(null, data);
- } else {
- done(
- new Error(
- `[CaseSensitivePathsPlugin] \`${pathName}\` does not match the corresponding path on disk ${realName}`,
- ),
- );
- }
- } else if (data.createData) {
- done(null);
- } else {
- done(null, data);
- }
- });
- };
- const cleanupPath = (resourcePath) => {
-
- return resourcePath.split('?')[0]
-
- .replace('\u0000#', '#');
- }
- const onAfterResolve = (data, done) => {
- this.primeCache(() => {
-
- let pathName = cleanupPath((data.createData || data).resource);
- pathName = pathName.normalize ? pathName.normalize('NFC') : pathName;
- checkFile(pathName, data, done);
- });
- };
- if (compiler.hooks) {
- compiler.hooks.done.tap('CaseSensitivePathsPlugin', onDone);
- if (this.options.useBeforeEmitHook) {
- if (this.options.debug) {
- this.logger.log(
- '[CaseSensitivePathsPlugin] Using the hook for before emit.',
- );
- }
- compiler.hooks.emit.tapAsync(
- 'CaseSensitivePathsPlugin',
- (compilation, callback) => {
- let resolvedFilesCount = 0;
- const errors = [];
- this.primeCache(() => {
- compilation.fileDependencies.forEach((filename) => {
- checkFile(filename, filename, (error) => {
- resolvedFilesCount += 1;
- if (error) {
- errors.push(error);
- }
- if (resolvedFilesCount === compilation.fileDependencies.size) {
- if (errors.length) {
-
- Array.prototype.push.apply(compilation.errors, errors);
- }
- callback();
- }
- });
- });
- });
- },
- );
- } else {
- compiler.hooks.normalModuleFactory.tap(
- 'CaseSensitivePathsPlugin',
- (nmf) => {
- nmf.hooks.afterResolve.tapAsync(
- 'CaseSensitivePathsPlugin',
- onAfterResolve,
- );
- },
- );
- }
- } else {
- compiler.plugin('done', onDone);
- compiler.plugin('normal-module-factory', (nmf) => {
- nmf.plugin('after-resolve', onAfterResolve);
- });
- }
- };
- module.exports = CaseSensitivePathsPlugin;
|