UNPKG

fuse-box

Version:

Fuse-Box a bundler that does it right

328 lines (326 loc) • 12.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const FileAnalysis_1 = require("../analysis/FileAnalysis"); const SourceMapGenerator_1 = require("./SourceMapGenerator"); const realm_utils_1 = require("realm-utils"); const fs = require("fs"); const path = require("path"); const Utils_1 = require("../Utils"); class File { constructor(context, info) { this.context = context; this.info = info; this.isFuseBoxBundle = false; this.es6module = false; this.cached = false; this.isLoaded = false; this.isNodeModuleEntry = false; this.isTypeScript = false; this.properties = new Map(); this.analysis = new FileAnalysis_1.FileAnalysis(this); this.resolving = []; this.subFiles = []; this.groupMode = false; if (info.params) { this.params = info.params; } this.absPath = info.absPath; if (this.absPath) { this.relativePath = Utils_1.ensureFuseBoxPath(path.relative(this.context.appRoot, this.absPath)); } } addAlternativeContent(str) { this.alternativeContent = this.alternativeContent || ""; this.alternativeContent += "\n" + str; } static createByName(collection, name) { let info = { fuseBoxPath: name, absPath: name, }; let file = new File(collection.context, info); file.collection = collection; return file; } static createModuleReference(collection, packageInfo) { let info = { fuseBoxPath: name, absPath: name, isNodeModule: true, nodeModuleInfo: packageInfo, }; let file = new File(collection.context, info); file.collection = collection; return file; } addProperty(key, obj) { this.properties.set(key, obj); } addStringDependency(name) { let deps = this.analysis.dependencies; if (deps.indexOf(name) === -1) { deps.push(name); } } getProperty(key) { return this.properties.get(key); } hasSubFiles() { return this.subFiles.length > 0; } addSubFile(file) { this.subFiles.push(file); } getCrossPlatormPath() { let name = this.absPath; if (!name) { return; } name = name.replace(/\\/g, "/"); return name; } tryTypescriptPlugins() { if (this.context.plugins) { this.context.plugins.forEach((plugin) => { if (plugin && realm_utils_1.utils.isFunction(plugin.onTypescriptTransform)) { plugin.onTypescriptTransform(this); } }); } } tryPlugins(_ast) { if (this.context.runAllMatchedPlugins) { return this.tryAllPlugins(_ast); } if (this.context.plugins && this.relativePath) { let target; let index = 0; while (!target && index < this.context.plugins.length) { let item = this.context.plugins[index]; let itemTest; if (Array.isArray(item)) { let el = item[0]; if (el && typeof el.test === "function") { itemTest = el; } else { itemTest = el.test; } } else { itemTest = item && item.test; } if (itemTest && realm_utils_1.utils.isFunction(itemTest.test) && itemTest.test(this.relativePath)) { target = item; } index++; } const tasks = []; if (target) { if (Array.isArray(target)) { target.forEach(plugin => { if (realm_utils_1.utils.isFunction(plugin.transform)) { this.context.debugPlugin(plugin, `Captured ${this.info.fuseBoxPath}`); tasks.push(() => plugin.transform.apply(plugin, [this])); } }); } else { if (realm_utils_1.utils.isFunction(target.transform)) { this.context.debugPlugin(target, `Captured ${this.info.fuseBoxPath}`); tasks.push(() => target.transform.apply(target, [this])); } } } return this.context.queue(realm_utils_1.each(tasks, promise => promise())); } } tryAllPlugins(_ast) { const tasks = []; if (this.context.plugins && this.relativePath) { const addTask = item => { if (realm_utils_1.utils.isFunction(item.transform)) { this.context.debugPlugin(item, `Captured ${this.info.fuseBoxPath}`); tasks.push(() => item.transform.apply(item, [this])); } }; this.context.plugins.forEach(item => { let itemTest; if (Array.isArray(item)) { let el = item[0]; itemTest = (el && realm_utils_1.utils.isFunction(el.test)) ? el : el.test; } else { itemTest = item && item.test; } if (itemTest && realm_utils_1.utils.isFunction(itemTest.test) && itemTest.test(this.relativePath)) { Array.isArray(item) ? item.forEach(addTask, this) : addTask(item); } }, this); } return this.context.queue(realm_utils_1.each(tasks, promise => promise())); } addHeaderContent(str) { if (!this.headerContent) { this.headerContent = []; } this.headerContent.push(str); } loadContents() { if (this.isLoaded) { return; } this.contents = fs.readFileSync(this.info.absPath).toString(); this.isLoaded = true; } makeAnalysis(parserOptions, traversalOptions) { if (!this.analysis.astIsLoaded()) { this.analysis.parseUsingAcorn(parserOptions); } this.analysis.analyze(traversalOptions); } replaceDynamicImports() { if (this.context.experimentalFeaturesEnabled && this.contents && this.collection.name === this.context.defaultPackageName) { const expression = /(\s+|^)(import\()/g; if (expression.test(this.contents)) { this.contents = this.contents.replace(expression, "$1$fsmp$("); if (this.context.fuse && this.context.fuse.producer) { this.devLibsRequired = ["fuse-imports"]; if (!this.context.fuse.producer.devCodeHasBeenInjected("fuse-imports")) { this.context.fuse.producer.injectDevCode("fuse-imports", Utils_1.readFuseBoxModule("fuse-box-responsive-api/dev-imports.js")); } } } } } consume() { if (this.info.isRemoteFile) { return; } if (!this.absPath) { return; } if (!fs.existsSync(this.info.absPath)) { this.notFound = true; return; } if (/\.ts(x)?$/.test(this.absPath)) { this.context.debug("Typescript", `Captured ${this.info.fuseBoxPath}`); return this.handleTypescript(); } if (/\.js(x)?$/.test(this.absPath)) { this.loadContents(); this.replaceDynamicImports(); this.tryPlugins(); const vendorSourceMaps = this.context.sourceMapsVendor && this.collection.name !== this.context.defaultPackageName; if (vendorSourceMaps) { this.loadVendorSourceMap(); } else { this.makeAnalysis(); } return; } this.tryPlugins(); if (!this.isLoaded) { this.contents = ""; this.context.fuse.producer.addWarning("missing-plugin", `The contents of ${this.absPath} weren't loaded. Missing a plugin?`); } } loadFromCache() { let cached = this.context.cache.getStaticCache(this); if (cached) { if (cached.sourceMap) { this.sourceMap = cached.sourceMap; } this.isLoaded = true; this.cached = true; if (cached.devLibsRequired) { cached.devLibsRequired.forEach(item => { if (!this.context.fuse.producer.devCodeHasBeenInjected(item)) { this.context.fuse.producer.injectDevCode(item, Utils_1.readFuseBoxModule("fuse-box-responsive-api/dev-imports.js")); } }); } if (cached.headerContent) { this.headerContent = cached.headerContent; } this.analysis.skip(); this.analysis.dependencies = cached.dependencies; this.contents = cached.contents; return true; } return false; } loadVendorSourceMap() { if (!this.context.cache) { return this.makeAnalysis(); } const key = `vendor/${this.collection.name}/${this.info.fuseBoxPath}`; this.context.debug("File", `Vendor sourcemap ${key}`); let cachedMaps = this.context.cache.getPermanentCache(key); if (cachedMaps) { this.sourceMap = cachedMaps; this.makeAnalysis(); } else { const tokens = []; this.makeAnalysis({ onToken: tokens }); SourceMapGenerator_1.SourceMapGenerator.generate(this, tokens); this.generateCorrectSourceMap(key); this.context.cache.setPermanentCache(key, this.sourceMap); } } handleTypescript() { if (this.context.useCache) { if (this.loadFromCache()) { this.tryPlugins(); return; } } const ts = require("typescript"); this.loadContents(); this.replaceDynamicImports(); this.tryTypescriptPlugins(); this.context.debug("TypeScript", `Transpile ${this.info.fuseBoxPath}`); let result = ts.transpileModule(this.contents, this.getTranspilationConfig()); if (result.sourceMapText && this.context.useSourceMaps) { let jsonSourceMaps = JSON.parse(result.sourceMapText); jsonSourceMaps.file = this.info.fuseBoxPath; jsonSourceMaps.sources = [this.context.sourceMapsRoot + "/" + this.info.fuseBoxPath.replace(/\.js(x?)$/, ".ts$1")]; if (!this.context.inlineSourceMaps) { delete jsonSourceMaps.sourcesContent; } result.outputText = result.outputText.replace("//# sourceMappingURL=module.js.map", ""); this.sourceMap = JSON.stringify(jsonSourceMaps); } this.contents = result.outputText; this.makeAnalysis(); this.tryPlugins(); if (this.context.useCache) { this.context.emitJavascriptHotReload(this); this.context.cache.writeStaticCache(this, this.sourceMap); } } generateCorrectSourceMap(fname) { if (this.sourceMap) { let jsonSourceMaps = JSON.parse(this.sourceMap); jsonSourceMaps.file = this.info.fuseBoxPath; jsonSourceMaps.sources = [this.context.sourceMapsRoot + "/" + (fname || this.info.fuseBoxPath)]; if (!this.context.inlineSourceMaps) { delete jsonSourceMaps.sourcesContent; } this.sourceMap = JSON.stringify(jsonSourceMaps); } return this.sourceMap; } getTranspilationConfig() { return Object.assign({}, this.context.getTypeScriptConfig(), { fileName: this.info.absPath, }); } } exports.File = File; //# sourceMappingURL=File.js.map