UNPKG

ts2typebox

Version:

Creates TypeBox code from Typescript code

182 lines (170 loc) 7.58 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.addCommentThatCodeIsGenerated = exports.getHelpText = exports.ts2typebox = void 0; const prettier = __importStar(require("prettier")); const cosmiconfig_1 = require("cosmiconfig"); const package_json_1 = __importDefault(require("../package.json")); const codeOptions_cjs_1 = __importDefault(require("./codeOptions.cjs")); const codegen = __importStar(require("@sinclair/typebox-codegen")); /** * Use this function for programmatic usage of ts2typebox. The options are typed * and commented. * * @returns The generated types as string if (outputStdout was set) or undefined * otherwise. * * @throws Error **/ const ts2typebox = async ({ input, disableAutogenComment, skipTypeCreation, }) => { const generatedTs = codegen.TypeScriptToTypeBox.Generate(input); // post-processing // 1. transformations const ts2typeboxCodeOptions = await (0, cosmiconfig_1.cosmiconfig)("ts2typebox").search(); // TODO: perhaps validate with typebox that these are indeed valid codeOption // configs (ts2typebox options) const usedCodeOptions = ts2typeboxCodeOptions === null ? codeOptions_cjs_1.default : ts2typeboxCodeOptions.config; const transformedTs = transformValuesAndTypes(generatedTs, usedCodeOptions); // 2. formatting const explorer = (0, cosmiconfig_1.cosmiconfig)("prettier"); const searchResult = await explorer.search(); // TODO: perhaps validate with typebox that these are indeed valid prettier configs const prettierConfig = searchResult === null ? {} : searchResult.config; const resultFormatted = prettier.format(transformedTs, { parser: "typescript", ...prettierConfig, }); const resultFiltered = skipTypeCreation === undefined ? resultFormatted : filterTypes(resultFormatted); const result = disableAutogenComment === undefined ? exports.addCommentThatCodeIsGenerated.run(resultFiltered) : resultFiltered; return result; }; exports.ts2typebox = ts2typebox; /** * Post-processing after successful code generation. * Transforms all values and types based on given functions. */ const transformValuesAndTypes = (generatedTypes, transformFns) => { const tsWithTransformedTypes = generatedTypes.replace(/(type)\s(\w+)/gm, (_match, group1, group2) => { return group1 + " " + transformFns.transformTypeName(group2); }); const result = tsWithTransformedTypes.replace(/(typeof|const)\s(\w+)/gm, (_match, group1, group2) => { return group1 + " " + transformFns.transformValueName(group2); }); return result; }; /** * Post-processing after successful code generation. * Removes each line starting with "export type" or "type". */ const filterTypes = (input) => { const result = input.replace(/^(export\s+)?type.*(\r?\n|$)/gm, ""); // Now we still have to adapt the import line since we would otherwise get // "unused imports". For now, we simply remove the first line and append the // correct one. return ('import { Type } from "@sinclair/typebox";\n' + result.split("\n").slice(1).join("\n")); }; /** * Declaring this as function in order to make it better testable. * Using an object to be able to mock it and track its usage. */ exports.getHelpText = { run: () => { return ` ts2typebox is a cli tool to generate typebox JSON schemas based on given typescript types. The generated output is formatted based on the prettier config inside your repo (or the default one, if you don't have one). Version: ${package_json_1.default.version} Usage: ts2typebox [ARGUMENTS] Arguments: -h, --help Displays this menu. -i, --input Specifies the relative path to the file containing the typescript types that will be used to generated typebox types. Defaults to "types.ts". -o, --output Specifies the relative path to generated file that will contain the typebox types. Defaults to "generated-types.ts". --output-stdout Does not generate an output file and prints the generated code to stdout instead. Has precedence over -o/--output. --disable-autogen-comment When used, it does not add the comment at the beginning of the generated file which is stating that the code was automatically generated. --skip-type-creation When used, strips all types from the generated code. This can be helpful if you want to use your Typescript types inside your input file (which probably contains comments) as source of truth and still use the generated JSON schema validators (typebox values) to validate data based on these types. When using this option you probably want to also provide a custom transformValue function since two same symbols can't be imported from two different files. For an example take a look inside the repo under ./examples/skip-type-creation. Additional: You can adapt the names of the generated types (as well as the names of the generated values) using custom transformation functions which take a string as an input and return a string as their output. These will run on each of the generated types and values, respectively. Please take a look inside the repo under ./examples/transform-value-transform-type for an example of this. `; }, }; /** * Declaring this as an object with a function in order to make it better * testable with mocks. Allows for tracking the call count. */ exports.addCommentThatCodeIsGenerated = { run: (code) => { return `/** * ATTENTION. This code was AUTO GENERATED by ts2typebox. While I don't know * your use case, there is a high chance that direct changes to this file get * lost. Consider making changes to the underlying Typescript code you use to * generate this file instead. The default file is called "types.ts", perhaps * have a look there! :] */ ${code}`; }, }; //# sourceMappingURL=programmatic-usage.js.map