UNPKG

@hi18n/cli

Version:

Message internationalization meets immutability and type-safety - command line tool

191 lines 6.54 kB
import path from "node:path"; import { cosmiconfig } from "cosmiconfig"; import { TSESLint, TSESTree, } from "@typescript-eslint/utils"; import resolve from "resolve"; import * as jsonMfConnector from "./json-mf-connector.js"; const explorer = cosmiconfig("hi18n"); const DEFAULT_EXTENSIONS = [ ".js", ".cjs", ".mjs", ".ts", ".cts", ".mts", ".jsx", ".tsx", ]; const DEFAULT_EXTENSIONS_TO_REMOVE = [".js", ".cjs", ".mjs"]; const DEFAULT_PARSER_OPTIONS = { ecmaVersion: "latest", sourceType: "module", }; const configKeys = [ "include", "exclude", "parser", "parserOptions", "extensions", "extensionsToRemove", "baseUrl", "paths", "connector", "connectorOptions", ]; export async function loadConfig(cwd) { const cosmiconfigResult = (await explorer.search(cwd)) ?? { config: {}, filepath: path.join(cwd, ".hi18nrc.json"), isEmpty: true, }; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const { config, filepath } = cosmiconfigResult; if (!isObject(config)) { throw new Error("config: not an object"); } if (!optional(isArrayOf(isString))(config["include"])) { throw new Error("config.include: not an array of strings"); } if (!optional(isArrayOf(isString))(config["exclude"])) { throw new Error("config.exclude: not an array of strings"); } if (!optional(oneof(isString, isLooseParserModule))(config["parser"])) { throw new Error("config.parser: not a string nor a parser object"); } if (!optional(isObject)(config["parserOptions"])) { throw new Error("config.parserOptions: not an object"); } if (!optional(isArrayOf(isString))(config["extensions"])) { throw new Error("config.extensions: not an array of strings"); } if (!optional(isArrayOf(isString))(config["extensionsToRemove"])) { throw new Error("config.extensionsToRemove: not an array of strings"); } if (!optional(isString)(config["baseUrl"])) { throw new Error("config.baseUrl: not a string"); } if (!optional(isRecordOf(isArrayOf(isString)))(config["paths"])) { throw new Error("config.paths: not a record of arrays of strings"); } if (!optional(oneof(isString, isConnectorDependency))(config["connector"])) { throw new Error("config.connector: not a string nor a parser object"); } if (!optional(isObject)(config["connectorOptions"])) { throw new Error("config.connectorOptions: not an object"); } for (const key of Object.keys(config)) { if (!configKeys.includes(key)) { throw new Error(`Unrecognized config: ${key}`); } } const include = config["include"]; const exclude = config["exclude"]; const parser = resolveParser(config["parser"], filepath); const parserOptions = config["parserOptions"] ?? DEFAULT_PARSER_OPTIONS; const extensions = expandExtensions(config["extensions"]); const extensionsToRemove = expandExtensionsToRemove(config["extensionsToRemove"]); const baseUrl = expandBaseUrl(config["baseUrl"], filepath); const paths = config["paths"]; if (paths && !baseUrl) { throw new Error("baseUrl must be specified"); } const connector = resolveConnector(config["connector"], filepath); const connectorOptions = config["connectorOptions"] ?? {}; return { configPath: filepath, include, exclude, parser, parserOptions, extensions, extensionsToRemove, baseUrl, paths, connector, connectorOptions, }; } function resolveParser(parser, filepath) { if (typeof parser === "string") { const parserPath = resolve.sync(parser, { basedir: path.dirname(filepath), }); // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-return return require(parserPath); } else if (typeof parser === "object" && parser != null) { return parser; } // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-return return require("@typescript-eslint/parser"); } function resolveConnector(connector, filepath) { if (connector === "@hi18n/cli/json-mf-connector") { return jsonMfConnector; } else if (typeof connector === "string") { const connectorPath = resolve.sync(connector, { basedir: path.dirname(filepath), }); // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-return return require(connectorPath); } else if (typeof connector === "object") { return connector; } return undefined; } function expandExtensions(extensions) { if (extensions === undefined) return DEFAULT_EXTENSIONS; return extensions.flatMap((ext) => ext === "..." ? DEFAULT_EXTENSIONS : [ext]); } function expandExtensionsToRemove(extensionsToRemove) { if (extensionsToRemove === undefined) return DEFAULT_EXTENSIONS_TO_REMOVE; return extensionsToRemove.flatMap((ext) => ext === "..." ? DEFAULT_EXTENSIONS_TO_REMOVE : [ext]); } function expandBaseUrl(baseUrl, filepath) { if (baseUrl === undefined) return undefined; return path.resolve(path.dirname(filepath), baseUrl); } function isObject(x) { return typeof x === "object"; } function isString(x) { return typeof x === "string"; } // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type function isFunction(x) { return typeof x === "function"; } function isArrayOf(pred) { return function isArrayOf(x) { return Array.isArray(x) && x.every((value) => pred(value)); }; } function isRecordOf(pred) { return function isRecordOf(x) { return isObject(x) && Object.values(x).every((value) => pred(value)); }; } function optional(pred) { return function optional(x) { return x === undefined || pred(x); }; } // eslint-disable-next-line @typescript-eslint/no-explicit-any function oneof(...preds) { return function oneof(x) { return preds.some((pred) => pred(x)); }; } function isLooseParserModule(x) { const xx = x; return (typeof xx.parseForESLint === "function" || typeof xx.parse === "function"); } function isConnectorDependency(x) { return isObject(x) && isFunction(x["connector"]); } //# sourceMappingURL=config.js.map