UNPKG

typings-core

Version:
396 lines 18.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var ts = require("typescript"); var extend = require("xtend"); var has = require("has"); var path_1 = require("path"); var fs_1 = require("../utils/fs"); var path_2 = require("../utils/path"); var path_3 = require("../utils/path"); var references_1 = require("../utils/references"); var config_1 = require("../utils/config"); var error_1 = require("./error"); function compile(tree, resolutions, options) { var name = options.name, cwd = options.cwd, global = options.global; var fileCache = {}; if (tree.global && !global) { return Promise.reject(new error_1.default("Unable to compile \"" + name + "\", the typings are meant to be installed as " + "global but attempted to be compiled as an external module")); } for (var _i = 0, resolutions_1 = resolutions; _i < resolutions_1.length; _i++) { var resolution = resolutions_1[_i]; if (resolution !== 'main' && resolution !== 'browser') { return Promise.reject(new error_1.default("Unable to resolve using \"" + resolution + "\" setting")); } } return Promise.all(resolutions.map(function (resolution) { var resolved = {}; var imported = {}; return compileDependencyTree(tree, extend(options, { resolution: resolution, fileCache: fileCache, imported: imported, resolved: resolved })); })) .then(function (output) { var results = {}; for (var i = 0; i < output.length; i++) { results[resolutions[i]] = output[i]; } return { cwd: cwd, name: name, tree: tree, global: global, results: results }; }); } exports.compile = compile; function resolveImportFrom(from, to) { return path_3.isModuleName(to) ? to : path_3.resolveFrom(from, to); } function resolveOverride(src, to, tree) { if (typeof to === 'string') { if (path_3.isModuleName(to)) { var _a = getModuleNameParts(to, tree), moduleName = _a[0], modulePath = _a[1]; return modulePath ? path_3.normalizeToDefinition(to) : moduleName; } return path_3.resolveFrom(src, path_3.normalizeToDefinition(to)); } return to ? src : undefined; } function getStringifyOptions(tree, options, parent) { var overrides = {}; var isTypings = typeof tree.typings === 'string'; var main = isTypings ? tree.typings : tree.main; var browser = isTypings ? tree.browserTypings : tree.browser; if (options.resolution === 'browser' && browser) { if (typeof browser === 'string') { var mainDefinition = path_3.resolveFrom(tree.src, path_3.normalizeToDefinition(main)); var browserDefinition = path_3.resolveFrom(tree.src, path_3.normalizeToDefinition(browser)); overrides[mainDefinition] = browserDefinition; } else { for (var _i = 0, _a = Object.keys(browser); _i < _a.length; _i++) { var key = _a[_i]; var from = resolveOverride(tree.src, key, tree); var to = resolveOverride(tree.src, browser[key], tree); overrides[from] = to; } } } var referenced = {}; var dependencies = {}; var entry = main == null ? undefined : path_3.normalizeToDefinition(main); var prefix = "" + (parent ? parent.prefix : '') + config_1.DEPENDENCY_SEPARATOR + options.name; return extend(options, { tree: tree, entry: entry, prefix: prefix, overrides: overrides, referenced: referenced, dependencies: dependencies, parent: parent }); } function compileDependencyTree(tree, options) { var stringifyOptions = getStringifyOptions(tree, options, undefined); var contents = []; var name = options.name, global = options.global, resolution = options.resolution; options.emitter.emit('compiledependency', { tree: tree, global: global, name: name, resolution: resolution }); if (Array.isArray(tree.files)) { for (var _i = 0, _a = tree.files; _i < _a.length; _i++) { var file = _a[_i]; contents.push(stringifyDependencyImport(path_3.resolveFrom(tree.src, file), DependencyImport.ALL_PATHS, false, stringifyOptions)); } } if (stringifyOptions.entry) { contents.push(stringifyDependencyImport(path_3.resolveFrom(tree.src, stringifyOptions.entry), DependencyImport.ALL_PATHS, true, stringifyOptions)); } if (contents.length === 0) { contents.push(stringifyDependencyImport(path_3.resolveFrom(tree.src, 'index.d.ts'), DependencyImport.DEFAULT_ONLY, true, stringifyOptions)); } return Promise.all(contents).then(function (out) { return out.join(path_2.EOL); }); } function cachedReadFileFrom(path, options) { if (!has(options.fileCache, path)) { options.fileCache[path] = fs_1.readFileFrom(path); } return options.fileCache[path]; } function cachedStringifyOptions(name, compileOptions, options) { if (!has(options.dependencies, name)) { var branch = options.tree.dependencies[name]; if (branch) { options.dependencies[name] = getStringifyOptions(branch, compileOptions, options); } else { options.dependencies[name] = null; } } return options.dependencies[name]; } function getPath(path, options) { if (has(options.overrides, path)) { return options.overrides[path]; } return path; } var DependencyImport; (function (DependencyImport) { DependencyImport[DependencyImport["DEFAULT_ONLY"] = 0] = "DEFAULT_ONLY"; DependencyImport[DependencyImport["SUFFIXES_ONLY"] = 1] = "SUFFIXES_ONLY"; DependencyImport[DependencyImport["ALL_PATHS"] = 2] = "ALL_PATHS"; })(DependencyImport || (DependencyImport = {})); function getDependencyImportPaths(importPath, mode) { var paths = []; if (mode === DependencyImport.DEFAULT_ONLY || mode === DependencyImport.ALL_PATHS) { paths.push(importPath); } if (mode === DependencyImport.SUFFIXES_ONLY || mode === DependencyImport.ALL_PATHS) { paths.push(path_3.appendToPath(importPath, '.d.ts'), path_3.appendToPath(importPath, '/index.d.ts')); } return paths; } function readDependencyImport(importPath, mode, isEntry, stringifyOptions, parent) { function attempt(cause, paths, index, isEntry, options) { var cwd = options.cwd, tree = options.tree, resolution = options.resolution, fileCache = options.fileCache, resolved = options.resolved, imported = options.imported, emitter = options.emitter, meta = options.meta; if (index >= paths.length) { var authorPhrase = options.parent ? "The author of \"" + options.parent.name + "\" needs to" : 'You should'; var relativePath = path_3.isModuleName(importPath) ? importPath : path_3.relativeTo(options.tree.src, importPath); if (isEntry) { return Promise.reject(new error_1.default("Unable to read typings for \"" + options.name + "\". " + (authorPhrase + " check the entry paths in \"" + path_1.basename(options.tree.src) + "\" are up to date"), cause)); } return Promise.reject(new error_1.default("Unable to read \"" + relativePath + "\" from \"" + options.name + "\". " + (authorPhrase + " validate all import paths are accurate (case sensitive and relative)"), cause)); } var path = getPath(paths[index], options); if (path_3.isModuleName(path)) { var _a = getModuleNameParts(path, tree), moduleName = _a[0], modulePath = _a[1]; var childOptions = cachedStringifyOptions(moduleName, { cwd: cwd, resolution: resolution, fileCache: fileCache, emitter: emitter, imported: imported, resolved: resolved, name: moduleName, global: false, meta: meta }, options); if (!childOptions) { stringifyOptions.resolved[getCachePath(importPath, stringifyOptions, false)] = path; return Promise.resolve(null); } var paths_1 = getDependencyImportPaths(path_3.resolveFrom(childOptions.tree.src, modulePath || childOptions.entry || 'index.d.ts'), modulePath ? DependencyImport.SUFFIXES_ONLY : (childOptions.entry ? DependencyImport.ALL_PATHS : DependencyImport.DEFAULT_ONLY)); return attempt(null, paths_1, 0, true, childOptions); } var cached = has(options.imported, path); if (!cached) { options.imported[path] = fs_1.readFileFrom(path).then(function (contents) { var fileInfo = ts.preProcessFile(contents); var sourceFile = ts.createSourceFile(path, contents.replace(references_1.REFERENCE_REGEXP, ''), ts.ScriptTarget.Latest, true); var modulePath = getCachePath(path, options, true); var moduleInfo = { path: path, modulePath: modulePath, isEntry: isEntry, parent: parent, sourceFile: sourceFile, options: options, fileInfo: fileInfo }; return moduleInfo; }, function (err) { if (err.code === 'ENOENT' || err.code === 'ENOTDIR' || err.code === 'EISDIR' || err.code === 'EINVALIDSTATUS') { return attempt(err, paths, index + 1, isEntry, options); } return Promise.reject(err); }); } return options.imported[path].then(function (moduleInfo) { if (moduleInfo) { stringifyOptions.resolved[getCachePath(importPath, stringifyOptions, false)] = moduleInfo.modulePath; } return !cached ? moduleInfo : undefined; }); } return attempt(null, getDependencyImportPaths(importPath, mode), 0, isEntry, stringifyOptions); } function stringifyDependencyImport(importPath, mode, isEntry, options, parent) { return readDependencyImport(importPath, mode, isEntry, options, parent) .then(function (info) { return info ? stringifyDependencyPath(info) : undefined; }); } function getCachePath(originalPath, options, strip) { var path = strip ? path_3.pathFromDefinition(originalPath) : originalPath; if (path_3.isModuleName(path)) { return path_3.normalizeSlashes("" + options.prefix + config_1.DEPENDENCY_SEPARATOR + path); } return path_3.normalizeSlashes(path_1.join(options.prefix, path_3.relativeTo(options.tree.src, path))); } function stringifyDependencyPath(moduleInfo) { var path = moduleInfo.path, options = moduleInfo.options, sourceFile = moduleInfo.sourceFile, fileInfo = moduleInfo.fileInfo; var tree = options.tree, global = options.global, resolution = options.resolution, name = options.name, prefix = options.prefix, emitter = options.emitter; emitter.emit('compile', { name: name, prefix: prefix, path: path, tree: tree, resolution: resolution }); var importedFiles = fileInfo.importedFiles.map(function (x) { return resolveImportFrom(path, x.fileName); }); var referencedFiles = fileInfo.referencedFiles.map(function (x) { return path_3.resolveFrom(path, x.fileName); }); if (global) { Object.keys(tree.dependencies).forEach(function (x) { return importedFiles.push(x); }); } var imports = importedFiles.map(function (importedFile) { var mode = path_3.isModuleName(importedFile) ? DependencyImport.DEFAULT_ONLY : DependencyImport.SUFFIXES_ONLY; return stringifyDependencyImport(importedFile, mode, false, options, moduleInfo); }); return Promise.all(imports).then(function (imports) { var stringified = stringifyModuleFile(moduleInfo); for (var _i = 0, referencedFiles_1 = referencedFiles; _i < referencedFiles_1.length; _i++) { var reference = referencedFiles_1[_i]; emitter.emit('reference', { name: name, prefix: prefix, path: path, reference: reference, tree: tree, resolution: resolution }); } var contents = imports.filter(function (x) { return x != null; }).concat(stringified).join(path_2.EOL); emitter.emit('compiled', { name: name, prefix: prefix, path: path, tree: tree, resolution: resolution, contents: contents }); return contents; }); } function getModuleNameParts(name, tree) { var parts = name.split(/[\\\/]/g); var len = parts.length; while (len) { len--; var name_1 = parts.slice(0, len).join('/'); var path = parts.slice(len).join('/'); if (tree.dependencies[name_1]) { return [name_1, path]; } } return [parts.join('/'), null]; } function getImportPath(path, options) { return options.resolved[getCachePath(path, options, false)]; } function stringifyModuleFile(info) { var options = info.options, modulePath = info.modulePath; var tree = options.tree, name = options.name, prefix = options.prefix, parent = options.parent, cwd = options.cwd, global = options.global; var source = path_3.isHttp(info.path) ? info.path : path_3.normalizeSlashes(path_1.relative(cwd, info.path)); var meta = options.meta ? "// Generated by " + config_1.PROJECT_NAME + path_2.EOL + "// Source: " + source + path_2.EOL : ''; if (global) { if (ts.isExternalModule(info.sourceFile)) { throw new error_1.default("Attempted to compile \"" + name + "\" as a global " + "module, but it looks like an external module. " + "You'll need to remove the global option to continue."); } return "" + meta + path_2.normalizeEOL(info.sourceFile.getText().trim(), path_2.EOL) + path_2.EOL; } else { if (!ts.isExternalModule(info.sourceFile) && !(info.parent && ts.isExternalModule(info.parent.sourceFile))) { throw new error_1.default("Attempted to compile \"" + name + "\" as an external module, " + "but it looks like a global module. " + "You'll need to enable the global option to continue."); } } var hasExports = false; var hasDefaultExport = false; var hasExportEquals = false; var hasLocalImports = false; var wasDeclared = false; function replacer(node) { if (node.kind === ts.SyntaxKind.ExportAssignment) { hasDefaultExport = !node.isExportEquals; hasExportEquals = !hasDefaultExport; } else if (node.kind === ts.SyntaxKind.ExportDeclaration) { hasExports = true; } else if (node.kind === ts.SyntaxKind.ExportSpecifier) { hasDefaultExport = hasDefaultExport || node.name.getText() === 'default'; } var flags = ts.getCombinedModifierFlags(node); hasExports = hasExports || !!(flags & ts.ModifierFlags.Export); hasDefaultExport = hasDefaultExport || !!(flags & ts.ModifierFlags.Default); if (node.kind === ts.SyntaxKind.StringLiteral && (node.parent.kind === ts.SyntaxKind.ExportDeclaration || node.parent.kind === ts.SyntaxKind.ImportDeclaration || node.parent.kind === ts.SyntaxKind.ModuleDeclaration)) { hasLocalImports = hasLocalImports || !path_3.isModuleName(node.text); return " '" + getImportPath(resolveImportFrom(info.path, node.text), options) + "'"; } if (node.kind === ts.SyntaxKind.DeclareKeyword) { wasDeclared = true; return info.sourceFile.text.slice(node.getFullStart(), node.getStart()); } if (node.kind === ts.SyntaxKind.ExternalModuleReference) { var requirePath = getImportPath(resolveImportFrom(info.path, node.expression.text), options); return " require('" + requirePath + "')"; } } function read(start, end) { var text = info.sourceFile.text.slice(start, end); if (start === 0) { return text.replace(/^\s+$/, ''); } if (end == null) { return text.replace(/\s+$/, ''); } if (wasDeclared) { wasDeclared = false; return text.replace(/^\s+/, ''); } return text; } var moduleText = path_2.normalizeEOL(processTree(info.sourceFile, replacer, read), path_2.EOL); var moduleName = parent && parent.global ? name : modulePath; if (info.isEntry && !hasLocalImports) { return meta + declareText(parent ? moduleName : name, moduleText); } var prettyPath = path_3.normalizeSlashes(path_1.join(name, path_3.relativeTo(tree.src, path_3.pathFromDefinition(info.path)))); var declared = meta + declareText(modulePath, moduleText); function alias(name) { var imports = []; if (hasExportEquals) { imports.push("import main = require('" + modulePath + "');"); imports.push("export = main;"); } else { if (hasExports) { imports.push("export * from '" + modulePath + "';"); } if (hasDefaultExport) { imports.push("export { default } from '" + modulePath + "';"); } } if (imports.length === 0) { return ''; } return declareText(name, imports.join(path_2.EOL)); } if (info.isEntry && !parent) { return declared + alias(prettyPath) + alias(name); } return declared + (parent ? '' : alias(prettyPath)); } function declareText(name, text) { return "declare module '" + name + "' {" + (text ? path_2.EOL + text + path_2.EOL : '') + "}" + path_2.EOL; } function processTree(sourceFile, replacer, reader) { var code = ''; var position = 0; function skip(node) { position = node.end; } function readThrough(node) { if (node.pos > position) { code += reader(position, node.pos); position = node.pos; } } function visit(node) { readThrough(node); var replacement = replacer(node); if (replacement != null) { code += replacement; skip(node); } else { ts.forEachChild(node, visit); } } visit(sourceFile); code += reader(position); return code; } //# sourceMappingURL=compile.js.map