UNPKG

dipend

Version:

This library implements a dependency injection (DI) system in JavaScript/TypeScript, making it easier to manage dependencies in modular applications.

218 lines (216 loc) 9.01 kB
/* * Copyright 2025 Saulo V. Alvarenga. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.InitCommand = void 0; const tslib_1 = require("tslib"); const fs_1 = tslib_1.__importDefault(require("fs")); const path_1 = tslib_1.__importDefault(require("path")); const jsonc_parser_1 = require("jsonc-parser"); class InitCommand { command = "init [tsConfigPath]"; description = "Adds Dipend configurations to tsconfig.json"; recommendInstall = false; builder = (yargs) => { return yargs .option("ts-config", { alias: "ts", describe: "Path to the tsconfig.json file", type: "string", default: "tsconfig.json", }) .option("package-json", { alias: "p", describe: "Path to the package.json file", type: "string", default: "package.json", }); }; readTsConfig(tsConfigPath) { if (!fs_1.default.existsSync(tsConfigPath)) { throw new Error("Missing tsconfig.json"); } const content = fs_1.default.readFileSync(tsConfigPath, "utf-8"); const parsed = (0, jsonc_parser_1.parse)(content); if (!parsed || typeof parsed !== "object") { throw new Error("Invalid tsconfig.json format"); } return parsed; } readPackageJson(packageJsonPath) { let packageJson = {}; if (fs_1.default.existsSync(packageJsonPath)) { packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, "utf-8")); } if (Object.keys(packageJson).length === 0) { throw new Error("Missing package.json"); } return packageJson; } addTsNodeConfigs(tsConfig) { if (tsConfig?.["ts-node"]?.compiler === "ts-patch/compiler") { console.log(`tsconfig.json: ts-patch already setted as ts-node compiler`); return tsConfig; } return { ...tsConfig, "ts-node": { ...(tsConfig?.["ts-node"] ?? {}), compiler: "ts-patch/compiler", }, }; } addLibs(tsConfig) { if (tsConfig?.compilerOptions?.lib?.includes("esnext.decorators")) { console.log(`tsconfig.json: esnext.decorators already exists in libs`); return tsConfig; } return { ...tsConfig, compilerOptions: { ...(tsConfig.compilerOptions ?? {}), lib: [...(tsConfig?.compilerOptions?.lib ?? []), "esnext.decorators"], }, }; } addPlugins(tsConfig) { if (tsConfig.compilerOptions?.plugins?.find((plugin) => plugin.transform === "dipend/tsc-plugin" && plugin.transformProgram === true) !== undefined) { console.log(`tsconfig.json: Dipend already exists in plugins`); return tsConfig; } const misconfiguredPluginIndex = tsConfig.compilerOptions?.plugins?.findIndex((plugin) => plugin.transform === "dipend/tsc-plugin"); if (misconfiguredPluginIndex !== undefined && misconfiguredPluginIndex !== -1) { tsConfig.compilerOptions?.plugins?.splice(misconfiguredPluginIndex, 1); } return { ...tsConfig, compilerOptions: { ...tsConfig.compilerOptions, plugins: [ ...(tsConfig.compilerOptions?.plugins ?? []), { transform: "dipend/tsc-plugin", transformProgram: true, }, ], }, }; } mergeTsConfig(tsConfig) { const newTsConfig = [this.addTsNodeConfigs.bind(this), this.addLibs.bind(this), this.addPlugins.bind(this)].reduce((mergedTsConfig, method) => method(mergedTsConfig), tsConfig); return newTsConfig; } addDipendCliTool(packageJson) { if (packageJson.scripts) { for (const [scriptName, scriptCmd] of Object.entries(packageJson.scripts)) { if (typeof scriptCmd === "string") { if (/\bdipend\s+(ts-node|tsc)\b/.test(scriptCmd)) { continue; } const updatedCmd = scriptCmd.replace(/(^|\s)(ts-node|tsc)(\s|$)/g, "$1dipend $2$3"); packageJson.scripts[scriptName] = updatedCmd; } } } return packageJson; } addTsPatch(packageJson) { if (packageJson.devDependencies?.["ts-patch"]) { console.log(`package.json: ts-patch already exists in devDependencies`); return packageJson; } this.recommendInstall = true; return { ...packageJson, devDependencies: { ...(packageJson.devDependencies ?? {}), "ts-patch": "3.3.0", }, }; } getDipendVersion() { const packageJsonPath = path_1.default.join(__dirname, "..", "..", "package.json"); const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, "utf8")); return packageJson.version; } addDipend(packageJson) { if (packageJson.dependencies?.["dipend"]) { console.log(`package.json: dipend already exists in dependencies`); return packageJson; } this.recommendInstall = true; return { ...packageJson, dependencies: { ...(packageJson.dependencies ?? {}), dipend: this.getDipendVersion(), }, }; } mergePackageJson(packageJson) { const newPackageJson = [ this.addDipendCliTool.bind(this), this.addTsPatch.bind(this), this.addDipend.bind(this), ].reduce((mergedPackageJson, method) => method(mergedPackageJson), packageJson); return newPackageJson; } applyChangesAndKeepComments(originalTsConfigAsString, mergedTsConfig) { const formattingOptions = { insertSpaces: true, tabSize: 2 }; let result = originalTsConfigAsString; if (mergedTsConfig["ts-node"]?.compiler) { const edit = (0, jsonc_parser_1.modify)(result, ["ts-node", "compiler"], mergedTsConfig["ts-node"].compiler, { formattingOptions, }); result = (0, jsonc_parser_1.applyEdits)(result, edit); } if (mergedTsConfig.compilerOptions?.lib) { const edit = (0, jsonc_parser_1.modify)(result, ["compilerOptions", "lib"], mergedTsConfig.compilerOptions.lib, { formattingOptions, }); result = (0, jsonc_parser_1.applyEdits)(result, edit); } if (mergedTsConfig.compilerOptions?.plugins) { const edit = (0, jsonc_parser_1.modify)(result, ["compilerOptions", "plugins"], mergedTsConfig.compilerOptions.plugins, { formattingOptions, }); result = (0, jsonc_parser_1.applyEdits)(result, edit); } return result; } handler = async (args) => { try { const tsConfigPath = path_1.default.resolve(args.tsConfig); const packageJsonPath = path_1.default.resolve(args.packageJson); const tsConfig = this.readTsConfig(tsConfigPath); const originalTsConfigAsString = fs_1.default.readFileSync(tsConfigPath, "utf-8"); const packageJson = this.readPackageJson(packageJsonPath); const mergedTsConfig = this.mergeTsConfig(tsConfig); console.log(`Dipend configurations successfully added to tsconfig.json`); const mergedPackageJson = this.mergePackageJson(packageJson); console.log(`Dipend configurations successfully added to package.json`); if (this.recommendInstall) console.log("Dipend: Please, run npm install again"); const newTsConfig = this.applyChangesAndKeepComments(originalTsConfigAsString, mergedTsConfig); fs_1.default.writeFileSync(tsConfigPath, newTsConfig, "utf-8"); fs_1.default.writeFileSync(packageJsonPath, JSON.stringify(mergedPackageJson, null, 2)); } catch (error) { console.error("Error updating tsconfig.json or package.json:", error); } }; } exports.InitCommand = InitCommand;