UNPKG

ts-migrate

Version:

A tool for migrating frontend application from JavaScript to TypeScript

112 lines 5.21 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); /* eslint-disable no-use-before-define, @typescript-eslint/no-use-before-define */ const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const updatable_log_1 = __importDefault(require("updatable-log")); const typescript_1 = __importDefault(require("typescript")); const json5_1 = __importDefault(require("json5")); const json5_writer_1 = __importDefault(require("json5-writer")); function rename({ rootDir, sources, }) { const configFile = path_1.default.resolve(rootDir, 'tsconfig.json'); if (!fs_1.default.existsSync(configFile)) { updatable_log_1.default.error('Could not find tsconfig.json at', configFile); return null; } let jsFiles; try { jsFiles = findJSFiles(rootDir, configFile, sources); } catch (err) { updatable_log_1.default.error(err); return null; } if (jsFiles.length === 0) { updatable_log_1.default.info('No JS/JSX files to rename.'); return []; } const toRename = jsFiles .map((oldFile) => { let newFile; if (oldFile.endsWith('.jsx')) { newFile = oldFile.replace(/\.jsx$/, '.tsx'); } else if (oldFile.endsWith('.js') && jsFileContainsJsx(oldFile)) { newFile = oldFile.replace(/\.js$/, '.tsx'); } else if (oldFile.endsWith('.js')) { newFile = oldFile.replace(/\.js$/, '.ts'); } return { oldFile, newFile }; }) .filter((result) => !!result.newFile); updatable_log_1.default.info(`Renaming ${toRename.length} JS/JSX files in ${rootDir}...`); toRename.forEach(({ oldFile, newFile }) => { fs_1.default.renameSync(oldFile, newFile); }); updateProjectJson(rootDir); updatable_log_1.default.info('Done.'); return toRename; } exports.default = rename; function findJSFiles(rootDir, configFile, sources) { const configFileContents = typescript_1.default.sys.readFile(configFile); if (configFileContents == null) { throw new Error(`Failed to read TypeScript config file: ${configFile}`); } const { config, error } = typescript_1.default.parseConfigFileTextToJson(configFile, configFileContents); if (error) { const errorMessage = typescript_1.default.flattenDiagnosticMessageText(error.messageText, typescript_1.default.sys.newLine); throw new Error(`Error parsing TypeScript config file text to json: ${configFile}\n${errorMessage}`); } let { include } = config; // Sources come from either `config.files` or `config.includes`. // If the --sources flag is set, let's ignore both of those config properties // and set our own `config.includes` instead. if (sources !== undefined) { include = Array.isArray(sources) ? sources : [sources]; delete config.files; } const { fileNames, errors } = typescript_1.default.parseJsonConfigFileContent(Object.assign(Object.assign({}, config), { compilerOptions: Object.assign(Object.assign({}, config.compilerOptions), { // Force JS/JSX files to be included allowJs: true }), include }), typescript_1.default.sys, rootDir); if (errors.length > 0) { const errorMessage = typescript_1.default.formatDiagnostics(errors, { getCanonicalFileName: (fileName) => fileName, getCurrentDirectory: () => rootDir, getNewLine: () => typescript_1.default.sys.newLine, }); throw new Error(`Errors parsing TypeScript config file content: ${configFile}\n${errorMessage}`); } return fileNames.filter((fileName) => /\.jsx?$/.test(fileName)); } /** * Heuristic to determine whether a .js file contains JSX. */ function jsFileContainsJsx(jsFileName) { const contents = fs_1.default.readFileSync(jsFileName, 'utf8'); return /(from ['"]react['"]|@jsx)/.test(contents) && /<[A-Za-z>]/.test(contents); } function updateProjectJson(rootDir) { const projectJsonFile = path_1.default.resolve(rootDir, 'project.json'); if (!fs_1.default.existsSync(projectJsonFile)) { return; } const projectJsonText = fs_1.default.readFileSync(projectJsonFile, 'utf-8'); const projectJson = json5_1.default.parse(projectJsonText); if (projectJson && projectJson.allowedImports) { projectJson.allowedImports = projectJson.allowedImports.map((allowedImport) => /.jsx?$/.test(allowedImport) ? allowedImport.replace(/\.js(x?)$/, '.ts$1') : allowedImport); } if (projectJson && projectJson.layout) { const { layout } = projectJson; projectJson.layout = /.jsx?$/.test(layout) ? layout.replace(/\.js(x?)$/, '.ts$1') : layout; } const writer = json5_writer_1.default.load(projectJsonText); writer.write(projectJson); fs_1.default.writeFileSync(projectJsonFile, writer.toSource({ quote: 'double' }), 'utf-8'); updatable_log_1.default.info(`Updated allowedImports in ${projectJsonFile}`); } //# sourceMappingURL=rename.js.map