UNPKG

@ts-dev-tools/core

Version:
179 lines (172 loc) 7.92 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.up = void 0; const node_fs_1 = require("node:fs"); const node_path_1 = require("node:path"); const CmdService_1 = require("../../services/CmdService"); const FileService_1 = require("../../services/FileService"); const GitService_1 = require("../../services/GitService"); const PackageJson_1 = require("../../services/PackageJson"); const BIOME_CONFIG_FILE_NAME = "biome.json"; const ESLINT_CONFIG_FILE_NAME = "eslint.config.mjs"; const PRE_COMMIT_HOOK_NAME = "pre-commit"; const BIOME_INIT_COMMAND = "npx @biomejs/biome init"; const OLD_PRE_COMMIT_COMMAND = "npx --no-install lint-staged && npx --no-install pretty-quick --staged"; const NEW_PRE_COMMIT_COMMAND = "npx --no-install biome check --error-on-warnings --staged --write"; const MANAGED_ESLINT_MARKERS = [ "tsDevToolsCore", "tsDevToolsReact", "export default tsDevTools", ]; const VITE_VANILLA_APP_ELEMENT_PATTERN = "document.querySelector<HTMLDivElement>('#app')!.innerHTML = `"; const VITE_VANILLA_APP_ELEMENT_REPLACEMENT = `const appElement = document.querySelector<HTMLDivElement>("#app"); if (!appElement) { throw new Error("Could not find #app element"); } appElement.innerHTML = \``; const VITE_VANILLA_COUNTER_PATTERN = "setupCounter(document.querySelector<HTMLButtonElement>('#counter')!)"; const VITE_VANILLA_COUNTER_REPLACEMENT = `const counterElement = document.querySelector<HTMLButtonElement>("#counter"); if (!counterElement) { throw new Error("Could not find #counter element"); } setupCounter(counterElement)`; const VITE_REACT_ROOT_PATTERN = "createRoot(document.getElementById('root')!).render("; const VITE_REACT_ROOT_REPLACEMENT = `const rootElement = document.getElementById("root"); if (!rootElement) { throw new Error("Could not find #root element"); } createRoot(rootElement).render(`; const VITE_REACT_BUTTON_PATTERN = "<button onClick={"; const VITE_REACT_BUTTON_REPLACEMENT = '<button type="button" onClick={'; const up = async (absoluteProjectDir) => { const packageJson = PackageJson_1.PackageJson.fromDirPath(absoluteProjectDir); const packageJsonContent = packageJson.getContent(); const hasManagedEslintConfigFile = projectHasManagedEslintConfigFile(absoluteProjectDir); const hasBiomeConfig = projectHasBiomeConfig(absoluteProjectDir); if (!hasBiomeConfig) { await runBiomeInit(absoluteProjectDir); } delete packageJsonContent.eslintConfig; delete packageJsonContent.prettier; delete packageJsonContent.importSort; delete packageJsonContent["lint-staged"]; packageJsonContent.scripts = { ...packageJsonContent.scripts, format: "biome format --write .", lint: "biome lint --error-on-warnings .", check: "biome check --error-on-warnings --write .", }; packageJson.setContent(packageJsonContent); enableBiomeVcsIntegration(absoluteProjectDir); migrateCommonViteStarterFiles(absoluteProjectDir); deleteManagedEslintConfig(absoluteProjectDir, hasManagedEslintConfigFile); updateManagedPreCommitHook(absoluteProjectDir); }; exports.up = up; async function runBiomeInit(absoluteProjectDir) { await CmdService_1.CmdService.execCmd(BIOME_INIT_COMMAND, absoluteProjectDir, true); } function enableBiomeVcsIntegration(absoluteProjectDir) { const biomeConfigFilePath = (0, node_path_1.join)(absoluteProjectDir, BIOME_CONFIG_FILE_NAME); if (!FileService_1.FileService.fileExists(biomeConfigFilePath)) { return; } let biomeConfigContent; try { biomeConfigContent = JSON.parse(FileService_1.FileService.getFileContent(biomeConfigFilePath)); } catch { console.warn('Skipping Biome VCS integration because "biome.json" contains invalid JSON.'); return; } const existingVcs = biomeConfigContent.vcs ?? {}; const vcsRoot = getBiomeVcsRoot(absoluteProjectDir); biomeConfigContent.vcs = { ...existingVcs, clientKind: existingVcs.clientKind ?? "git", enabled: true, ...(vcsRoot ? { root: vcsRoot } : {}), useIgnoreFile: true, }; FileService_1.FileService.putFileContent(biomeConfigFilePath, `${JSON.stringify(biomeConfigContent, null, 2)} `); } function getBiomeVcsRoot(absoluteProjectDir) { const vcsRootPath = getEnclosingVcsRootPath(absoluteProjectDir); if (!vcsRootPath || vcsRootPath === absoluteProjectDir) { return undefined; } return (0, node_path_1.relative)(absoluteProjectDir, vcsRootPath) || undefined; } function getEnclosingVcsRootPath(absoluteProjectDir) { let currentDir = absoluteProjectDir; while (true) { if ((0, node_fs_1.existsSync)((0, node_path_1.join)(currentDir, ".git"))) { return currentDir; } const parentDir = (0, node_path_1.dirname)(currentDir); if (parentDir === currentDir) { return undefined; } currentDir = parentDir; } } function migrateCommonViteStarterFiles(absoluteProjectDir) { updateFileContent((0, node_path_1.join)(absoluteProjectDir, "src", "main.ts"), migrateViteVanillaTsMainFile); updateFileContent((0, node_path_1.join)(absoluteProjectDir, "src", "main.tsx"), migrateViteReactTsMainFile); updateFileContent((0, node_path_1.join)(absoluteProjectDir, "src", "App.tsx"), migrateViteReactTsAppFile); } function updateFileContent(filePath, updateContent) { if (!FileService_1.FileService.fileExists(filePath)) { return; } const content = FileService_1.FileService.getFileContent(filePath); const updatedContent = updateContent(content); if (updatedContent === content) { return; } FileService_1.FileService.putFileContent(filePath, updatedContent); } function migrateViteVanillaTsMainFile(content) { return replaceExactPattern(replaceExactPattern(content, VITE_VANILLA_APP_ELEMENT_PATTERN, VITE_VANILLA_APP_ELEMENT_REPLACEMENT), VITE_VANILLA_COUNTER_PATTERN, VITE_VANILLA_COUNTER_REPLACEMENT); } function migrateViteReactTsMainFile(content) { return replaceExactPattern(content, VITE_REACT_ROOT_PATTERN, VITE_REACT_ROOT_REPLACEMENT); } function migrateViteReactTsAppFile(content) { return replaceExactPattern(addRelNoopenerToBlankTargetLinks(content), VITE_REACT_BUTTON_PATTERN, VITE_REACT_BUTTON_REPLACEMENT); } function addRelNoopenerToBlankTargetLinks(content) { return content.replaceAll(/target="_blank"(?![^>]*\srel=)/g, 'target="_blank" rel="noopener"'); } function replaceExactPattern(content, pattern, replacement) { return content.includes(pattern) ? content.replace(pattern, replacement) : content; } function projectHasBiomeConfig(absoluteProjectDir) { return FileService_1.FileService.fileExists((0, node_path_1.join)(absoluteProjectDir, BIOME_CONFIG_FILE_NAME)); } function projectHasManagedEslintConfigFile(absoluteProjectDir) { const eslintConfigFilePath = (0, node_path_1.join)(absoluteProjectDir, ESLINT_CONFIG_FILE_NAME); if (!(0, node_fs_1.existsSync)(eslintConfigFilePath)) { return false; } return isManagedEslintConfig((0, node_fs_1.readFileSync)(eslintConfigFilePath, "utf-8")); } function isManagedEslintConfig(eslintConfigContent) { return MANAGED_ESLINT_MARKERS.some((managedMarker) => eslintConfigContent.includes(managedMarker)); } function deleteManagedEslintConfig(absoluteProjectDir, hasManagedEslintConfig) { if (!hasManagedEslintConfig) { return; } const eslintConfigFilePath = (0, node_path_1.join)(absoluteProjectDir, ESLINT_CONFIG_FILE_NAME); if (!(0, node_fs_1.existsSync)(eslintConfigFilePath)) { return; } (0, node_fs_1.unlinkSync)(eslintConfigFilePath); } function updateManagedPreCommitHook(absoluteProjectDir) { GitService_1.GitService.updateGitHook(absoluteProjectDir, PRE_COMMIT_HOOK_NAME, OLD_PRE_COMMIT_COMMAND, NEW_PRE_COMMIT_COMMAND); }