UNPKG

3.92 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.GlobDependenciesPlugin = void 0;
4const BaseIncludePlugin_1 = require("./BaseIncludePlugin");
5const minimatch_1 = require("minimatch");
6const path = require("path");
7const TAP_NAME = "Aurelia:GlobDependencies";
8function* findFiles(root, glob, fs) {
9 // An easiest, naive approach consist of listing all files and then pass them through minimatch.
10 // This is a bad idea as `root` typically includes node_modules, which can contain *lots* of files.
11 // So we have to test partial paths to prune them early on.
12 const m = new minimatch_1.Minimatch(glob);
13 const queue = [''];
14 while (true) {
15 let folder = queue.pop();
16 if (folder === undefined)
17 return;
18 let full = path.resolve(root, folder);
19 for (let name of fs.readdirSync(full)) {
20 let stats = fs.statSync(path.resolve(full, name));
21 if (stats.isDirectory()) {
22 let subfolder = path.join(folder, name);
23 if (m.match(subfolder, /*partial:*/ true))
24 queue.push(subfolder);
25 }
26 else if (stats.isFile()) {
27 let file = path.join(folder, name);
28 if (m.match(file))
29 yield file;
30 }
31 }
32 }
33}
34class GlobDependenciesPlugin extends BaseIncludePlugin_1.BaseIncludePlugin {
35 /**
36 * Each hash member is a module name, for which globbed value(s) will be added as dependencies
37 **/
38 constructor(hash) {
39 super();
40 this.root = path.resolve();
41 for (let module in hash) {
42 let glob = hash[module];
43 if (!Array.isArray(glob))
44 hash[module] = [glob];
45 }
46 this.hash = hash;
47 }
48 apply(compiler) {
49 const hashKeys = Object.getOwnPropertyNames(this.hash);
50 if (hashKeys.length === 0)
51 return;
52 compiler.hooks.beforeCompile.tapPromise(TAP_NAME, () => {
53 // Map the modules passed in ctor to actual resources (files) so that we can
54 // recognize them no matter what the rawRequest was (loaders, relative paths, etc.)
55 this.modules = {};
56 const resolver = compiler.resolverFactory.get("normal", {});
57 return Promise.all(hashKeys.map(module => new Promise(resolve => {
58 resolver.resolve({}, this.root, module, {}, (err, resource) => {
59 if (err) {
60 resolve(undefined);
61 return;
62 }
63 this.modules[resource] = this.hash[module];
64 resolve(undefined);
65 });
66 })))
67 .then(() => { });
68 });
69 super.apply(compiler);
70 }
71 parser(compilation, parser, addDependency) {
72 const resolveFolders = compilation.options.resolve.modules;
73 // `resolveFolders` can be absolute paths, but by definition this plugin only
74 // looks for files in subfolders of the current `root` path.
75 const normalizers = resolveFolders.map(x => path.relative(this.root, x))
76 .filter(x => !x.startsWith(".."))
77 .map(x => new RegExp("^" + x + "/", "ig"));
78 parser.hooks.program.tap(TAP_NAME, () => {
79 const globs = this.modules[parser.state.module.resource];
80 if (!globs)
81 return;
82 for (let glob of globs)
83 for (let file of findFiles(this.root, glob, compilation.inputFileSystem)) {
84 file = file.replace(/\\/g, "/");
85 normalizers.forEach(x => file = file.replace(x, ""));
86 addDependency(file);
87 }
88 });
89 }
90}
91exports.GlobDependenciesPlugin = GlobDependenciesPlugin;
92;