fuse-box
Version:
Fuse-Box a bundler that does it right
103 lines (91 loc) • 3.21 kB
text/typescript
import * as path from "path";
import * as fs from "fs";
export interface ICSSDependencyExtractorOptions {
paths: string[];
extensions: string[],
content: string;
sassStyle?: boolean;
importer?: { (f: string, prev: any, done: { (info: { file: string }): void }): string }
}
export class CSSDependencyExtractor {
private dependencies: string[] = [];
constructor(public opts: ICSSDependencyExtractorOptions) {
this.extractDepsFromString(opts.content);
}
private extractDepsFromString(input: string) {
const re = /@import\s+("|')([^"']+)/g;
let match;
while (match = re.exec(input)) {
let target = this.findTarget(match[2]);
if (target) {
this.readFile(target);
this.dependencies.push(target);
}
}
}
private readFile(fileName: string) {
let contents = fs.readFileSync(fileName).toString();
this.extractDepsFromString(contents)
}
public getDependencies() {
return this.dependencies;
}
private tryFile(filePath: string): string {
// restrict node_module
// we don't want to detect stuff from there
if (filePath.indexOf("node_modules") > -1) {
return;
}
let fname = path.basename(filePath);
// if a filename doesn't have _ we need to try it with _ for sass cases
if (this.opts.sassStyle && !/^_/.test(fname)) {
const pathWithUnderScore = path.join(path.dirname(filePath), "_" + fname);
if (fs.existsSync(pathWithUnderScore)) {
return pathWithUnderScore;
}
}
if (fs.existsSync(filePath)) {
return filePath;
}
}
private getPath(suggested: string, fileName: string) {
let target = fileName;
if (this.opts.importer) {
fileName = this.opts.importer(fileName, null, info => {
target = info.file;
});
}
if (path.isAbsolute(target)) {
return target;
}
return path.join(suggested, target);
}
private findTarget(fileName: string): string {
let targetFile: any;
let extName = path.extname(fileName);
if (!extName) {
for (let p = 0; p < this.opts.paths.length; p++) {
for (let e = 0; e < this.opts.extensions.length; e++) {
let filePath = this.getPath(this.opts.paths[p], fileName + "." + this.opts.extensions[e]);
filePath = this.tryFile(filePath);
if (filePath) {
return filePath;
}
}
}
} else {
for (let p = 0; p < this.opts.paths.length; p++) {
let filePath = this.getPath(this.opts.paths[p], fileName);
filePath = this.tryFile(filePath);
if (filePath) {
return filePath;
}
}
}
return targetFile;
}
public static init(opts: ICSSDependencyExtractorOptions) {
return new CSSDependencyExtractor(opts);
}
//
}