UNPKG

flowgen

Version:

Generate flowtype definition files from TypeScript

240 lines (191 loc) 7.78 kB
"use strict"; exports.__esModule = true; exports.default = void 0; var _path = _interopRequireDefault(require("path")); var _fs = _interopRequireDefault(require("fs")); var _util = require("./util"); var _meta = _interopRequireDefault(require("./meta")); var _beautifier = _interopRequireDefault(require("./beautifier")); var _compiler = _interopRequireDefault(require("./compiler")); var _defaultExporter = _interopRequireDefault(require("./default-exporter")); var _flowTypedExporter = require("./flow-typed-exporter"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const readDir = (0, _util.promisify)(_fs.default.readdir); const readFile = (0, _util.promisify)(_fs.default.readFile); async function outputFile(flowDefinitions, { intro, index, file, moduleName, outputFile }, options, writeFile) { // Produce the flow library content try { // Write the output to disk let code = intro + flowDefinitions; try { code = (0, _beautifier.default)(code); } catch (e) { console.error(e); } const absoluteOutputFilePath = await writeFile(outputFile, code, index); // Check if we should compile tests as well if (options.compileTests) { // Assume tests file is in same dir, named <filename>-tests.ts // Based on DD conventions const testFileName = _path.default.dirname(file) + "/" + moduleName + "-tests.ts"; const testFileOutput = _path.default.dirname(absoluteOutputFilePath) + "/test_" + moduleName + ".js"; // Try to compile the test file. Will fail silently if not present. _compiler.default.compileTest(testFileName, testFileOutput); } } catch (e) { console.error("Parsing", file, "failed"); console.error(e); } } function getFile(file, options, rawFile, isInDir, index, pkg) { // Get the module name from the file name const moduleName = getModuleNameFromFile(file, pkg); const mode = getMode(options, file, isInDir); const mainTypes = pkg ? pkg.typings || pkg.types || "" : ""; const isMain = _path.default.join(rawFile, mainTypes) === file; // The format of the output argument varies a bit based on which // exporting format we're using. For flow-typed, only the module name // is required, otherwise we use the cli arg. const outputFile = getOutputFile(options, file, rawFile, mode, moduleName); // Get the intro text let intro = (0, _meta.default)(moduleName, options.version, options.addFlowHeader || mode === "directory"); if (mode === "directory-flow-typed") intro = ""; return { file, index, isMain, outputFile, moduleName, intro, mode }; } async function bfs(rootDir, options) { const queue = []; const files = []; let pkg; try { pkg = JSON.parse((await readFile(_path.default.join(rootDir, "package.json"))).toString()); } catch (err) {// ignored } queue.push(rootDir); let current; while (queue.length) { current = queue.shift(); try { const dir = await readDir(current, { withFileTypes: true }); for (const file of dir) { if (file.isDirectory()) { if (file.name === "node_modules") continue; queue.push(_path.default.join(current, file.name)); } else { if (!file.name.endsWith(".d.ts")) continue; files.push(getFile(_path.default.join(current, file.name), options, rootDir, true, files.length, pkg)); } } } catch { files.push(getFile(current, options, rootDir, false, files.length, pkg)); } } return files; } var _default = options => { const fileOptions = { jsdoc: options.jsdoc, quiet: options.quiet, interfaceRecords: options.interfaceRecords, moduleExports: options.moduleExports, inexact: options.inexact, asModule: options.asModule }; // No real reason to return an object here instead of combining // the compile function into the wrapper, but I like the API it produces. return { compile: async rawFiles => { const files = []; // Iterate all the files the user has passed in for (const rawFile of rawFiles) { files.push(...(await bfs(rawFile, options))); } const filesByPath = files.reduce((acc, file) => { acc.set(file.file, file); return acc; }, new Map()); const fileMapper = (sourceCode, fileName) => { if (!sourceCode) return; const file = filesByPath.get(fileName); if (!file) return sourceCode; if (file.mode !== "directory-flow-typed") return sourceCode; if (file.isMain) { return `declare module "${file.outputFile.moduleName}" {${sourceCode}} declare module "${file.outputFile.rootModuleName}" { declare export * from "${file.outputFile.moduleName}"; } `; } return `declare module "${file.outputFile.moduleName}" {${sourceCode}}`; }; if (files.length > 1) { const sources = _compiler.default.compileDefinitionFiles(files.map(v => v.file), fileOptions, fileMapper); for (let index = 0; index < sources.length; index++) { const [, flowDefinitions] = sources[index]; const file = files[index]; let writeFile = _defaultExporter.default; if (file.mode === "flow-typed") writeFile = _flowTypedExporter.flowTypedExporter; if (file.mode === "directory-flow-typed") writeFile = _flowTypedExporter.flowTypedDirectoryExporter; // Let the user know what's going on if (files.length >= 3) { // If we're compiling a lot of files, show more stats const progress = Math.round((index + 1) / files.length * 100); process.stdout.write("\r\x1b[K"); process.stdout.write(progress + "% | " + file.moduleName); } else { console.log("Parsing", file.moduleName); } outputFile(flowDefinitions, file, options, writeFile); } } else { const file = files[0]; const flowDefinitions = _compiler.default.compileDefinitionFile(file.file, fileOptions, fileMapper); let writeFile = _defaultExporter.default; if (file.mode === "flow-typed") writeFile = _flowTypedExporter.flowTypedExporter; if (file.mode === "directory-flow-typed") writeFile = _flowTypedExporter.flowTypedDirectoryExporter; // Let the user know what's going on console.log("Parsing", file.moduleName); outputFile(flowDefinitions, file, options, writeFile); } if (files.length >= 3) process.stdout.write("\n"); } }; }; exports.default = _default; function getModuleNameFromFile(fileName, pkg) { if (pkg) return pkg.name; return _path.default.basename(fileName).replace(".d.ts", ""); } function getMode(options, file, isDir) { if (isDir && options.flowTypedFormat) return "directory-flow-typed"; if (isDir) return "directory"; if (options.flowTypedFormat) return "flow-typed"; return "file"; } function getOutputFile(options, file, prefix, mode, moduleName) { switch (mode) { case "directory-flow-typed": return { rootModuleName: moduleName, moduleName: _path.default.join(moduleName, _path.default.relative(prefix, file).replace(".d.ts", "")), filename: _path.default.normalize(file.replace(prefix, "").replace(".d.ts", "")) }; case "directory": { var _options$out; const basedir = (_options$out = options.out) != null ? _options$out : "exports"; return _path.default.normalize(file.replace(prefix, `${basedir}${_path.default.sep}`).replace(".d.ts", ".js.flow")); } case "flow-typed": return moduleName; default: return options.out; } }