@hyper-fetch/cli 7.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,104 @@
1
+ /* eslint-disable no-param-reassign */
2
+ import { Command } from "commander";
3
+ import { z } from "zod";
4
+ import path from "path";
5
+ import fs from "fs-extra";
6
+ import { input, select, confirm } from "@inquirer/prompts";
7
+
8
+ import { handleError } from "utils/handle-error";
9
+ import { preFlightGenerate } from "preflights/preflight-generate";
10
+ import { OpenapiRequestGenerator } from "codegen/openapi/generator";
11
+ import { spinner } from "utils/spinner";
12
+ import { logger } from "utils/logger";
13
+ import { showHelp } from "utils/show-help";
14
+
15
+ export const generateOptionsSchema = z.object({
16
+ template: z.enum(["openapi", "swagger"]).describe("API provider template to use"),
17
+ url: z.string().describe("The URL to generate the schema from"),
18
+ fileName: z.string().describe("The output file for the SDK."),
19
+ cwd: z.string().describe("The working directory. defaults to the current directory."),
20
+ overwrite: z.boolean().optional().describe("Overwrite existing files."),
21
+ });
22
+
23
+ export const generate = new Command()
24
+ .name("Generate")
25
+ .description("Generate SDK from a schema, url or service")
26
+ .option("-t, --template <template>", "API provider template to use")
27
+ .option("-u, --url <url>", "The URL to generate the schema from")
28
+ .option("-f, --fileName <fileName>", "The output file for the SDK.")
29
+ .option("-o, --overwrite", "overwrite existing files.")
30
+ .option("-c, --cwd <cwd>", "the working directory. defaults to the current directory.", process.cwd())
31
+ .option("-h, --help <help>", "display help for command")
32
+ .action(async (opts: z.infer<typeof generateOptionsSchema>) => {
33
+ try {
34
+ const help = process.argv.includes("--help") || process.argv.includes("-h");
35
+
36
+ if (help) {
37
+ return showHelp(generateOptionsSchema);
38
+ }
39
+ const { config } = await preFlightGenerate(opts);
40
+
41
+ if (!opts.template) {
42
+ opts.template = await select({
43
+ message: "What source we want to use?",
44
+ choices: [
45
+ { name: "OpenAPI (v3)", value: "openapi" },
46
+ { name: "Swagger", value: "swagger" },
47
+ ],
48
+ });
49
+ }
50
+
51
+ if (!opts.url) {
52
+ opts.url = await input({
53
+ message: "Enter the URL to generate the schema from:",
54
+ validate: (value) => {
55
+ const result = z.url("Please enter a valid URL.").safeParse(value);
56
+ if (result.success) return true;
57
+ return result.error.message;
58
+ },
59
+ });
60
+ }
61
+
62
+ if (!opts.fileName) {
63
+ opts.fileName = await input({
64
+ message: "Enter the file name for the SDK:",
65
+ default: `api-${opts.template}.sdk.ts`,
66
+ });
67
+ }
68
+
69
+ const fileExists = fs.existsSync(path.join(opts.cwd, opts.fileName));
70
+ if (opts.overwrite === undefined && fileExists) {
71
+ opts.overwrite = await confirm({ message: "Overwrite existing files?" });
72
+ }
73
+
74
+ if (opts.overwrite === false && fileExists) {
75
+ return logger.info(`File ${opts.fileName} already exists. Use --overwrite to overwrite.`);
76
+ }
77
+
78
+ const options = generateOptionsSchema.parse(opts);
79
+
80
+ const componentSpinner = spinner(`Writing ${options.fileName}...`).start();
81
+ switch (options.template) {
82
+ case "openapi": {
83
+ const openapiSchema = await OpenapiRequestGenerator.getSchemaFromUrl({ url: options.url!, config });
84
+ const generator = new OpenapiRequestGenerator(openapiSchema);
85
+ await generator.generateFile({ fileName: options.fileName, config });
86
+ componentSpinner.succeed();
87
+ return process.exit(0);
88
+ }
89
+ case "swagger": {
90
+ const openapiSchema = await OpenapiRequestGenerator.getSchemaFromUrl({ url: options.url!, config });
91
+ const generator = new OpenapiRequestGenerator(openapiSchema);
92
+ await generator.generateFile({ fileName: options.fileName, config });
93
+ componentSpinner.succeed();
94
+ return process.exit(0);
95
+ }
96
+ default: {
97
+ componentSpinner.fail();
98
+ throw new Error(`Invalid template: ${options.template}`);
99
+ }
100
+ }
101
+ } catch (err) {
102
+ handleError(err);
103
+ }
104
+ });
@@ -0,0 +1,191 @@
1
+ import { Command } from "commander";
2
+ import { input, select } from "@inquirer/prompts";
3
+ import { z } from "zod";
4
+ import path from "path";
5
+ import { existsSync, mkdir, readFileSync, writeFile } from "fs-extra";
6
+
7
+ import { handleError } from "../utils/handle-error";
8
+ import { spinner } from "../utils/spinner";
9
+ import { configSchema, Config } from "config/schema";
10
+ import { logger } from "utils/logger";
11
+ import { getTsConfigAliasPrefix } from "config/get-ts-alias";
12
+ import { showHelp } from "utils/show-help";
13
+
14
+ const initOptionsSchema = z.object({
15
+ yes: z.boolean().optional().describe("skip confirmation prompt."),
16
+ cwd: z.string().describe("the working directory. defaults to the current directory."),
17
+ });
18
+
19
+ type Step = {
20
+ name: string;
21
+ action: (config: Partial<Config>) => Promise<Partial<Config> | void>;
22
+ };
23
+
24
+ export const init = new Command()
25
+ .name("Init")
26
+ .description("Initialize HyperFetch Client configuration.")
27
+ .option("-y, --yes", "skip confirmation prompt.", false)
28
+ .option("-c, --cwd <cwd>", "the working directory. defaults to the current directory.", process.cwd())
29
+ .option("-h, --help <help>", "display help for command")
30
+ .action(async (opts) => {
31
+ try {
32
+ const help = process.argv.includes("--help") || process.argv.includes("-h");
33
+
34
+ if (help) {
35
+ return showHelp(initOptionsSchema);
36
+ }
37
+
38
+ const { cwd, yes } = initOptionsSchema.parse(opts);
39
+
40
+ let config: Partial<Config> = {};
41
+
42
+ let mainPath: string;
43
+ let apiDir: string;
44
+
45
+ if (yes) {
46
+ mainPath = "src";
47
+ apiDir = "api";
48
+ } else {
49
+ // 1. ask for the path to the main directory
50
+ mainPath = await select({
51
+ message: "Select the main directory for your project:",
52
+ choices: [
53
+ { name: "src", value: "src" },
54
+ { name: "app", value: "app" },
55
+ { name: "other", value: "other" },
56
+ ],
57
+ });
58
+
59
+ if (mainPath === "other") {
60
+ mainPath = await input({
61
+ message: "Enter the path to the main directory:",
62
+ validate: (value) => {
63
+ if (!value) return "Path cannot be empty.";
64
+ return true;
65
+ },
66
+ });
67
+ }
68
+
69
+ // 2. text field - asking for the directory of api
70
+ apiDir = await input({
71
+ message: "Enter the name of the API directory:",
72
+ default: "api",
73
+ validate: (value) => {
74
+ if (!value) return "Directory name cannot be empty.";
75
+ return true;
76
+ },
77
+ });
78
+ }
79
+
80
+ const fullPath = path.join(cwd, mainPath, apiDir);
81
+ const relativePath = path.join(mainPath, apiDir);
82
+ const configPath = path.join(cwd, "api.json");
83
+
84
+ const aliasPrefix = (await getTsConfigAliasPrefix(cwd)) || "";
85
+ const alias = aliasPrefix ? `${aliasPrefix}/` : "";
86
+
87
+ const defaultAliases: Config["aliases"] = {
88
+ api: `${alias}${apiDir}`,
89
+ hooks: `${alias}hooks`,
90
+ ui: `${alias}components/ui`,
91
+ components: `${alias}components`,
92
+ lib: `${alias}lib`,
93
+ };
94
+
95
+ const defaultConfig: Omit<Config, "resolvedPaths"> = {
96
+ tsx: true,
97
+ aliases: defaultAliases,
98
+ };
99
+
100
+ logger.break();
101
+
102
+ const steps: Step[] = [
103
+ {
104
+ name: `Initialize API directory at ${relativePath}`,
105
+ action: async () => {
106
+ if (!existsSync(fullPath)) {
107
+ await mkdir(fullPath, { recursive: true });
108
+ }
109
+ },
110
+ },
111
+ {
112
+ name: "Setup configuration",
113
+ action: async (currentConfig) => {
114
+ if (existsSync(configPath)) {
115
+ const existingConfig = JSON.parse(readFileSync(configPath, "utf8"));
116
+ const { success, error, data } = configSchema.omit({ resolvedPaths: true }).safeParse({
117
+ ...defaultConfig,
118
+ ...existingConfig,
119
+ aliases: {
120
+ ...defaultConfig.aliases,
121
+ ...existingConfig.aliases,
122
+ },
123
+ });
124
+
125
+ if (error) {
126
+ logger.break();
127
+ logger.error(`Invalid configuration found in ${configPath}.`);
128
+ handleError(error);
129
+ logger.break();
130
+ }
131
+
132
+ if (success) {
133
+ return data;
134
+ }
135
+ }
136
+ return currentConfig;
137
+ },
138
+ },
139
+ {
140
+ name: "Setup Aliases",
141
+ action: async (currentConfig) => {
142
+ if (currentConfig.aliases) {
143
+ return currentConfig;
144
+ }
145
+
146
+ return {
147
+ ...currentConfig,
148
+ aliases: defaultAliases,
149
+ };
150
+ },
151
+ },
152
+ {
153
+ name: `Create api.json configuration file`,
154
+ action: async (currentConfig) => {
155
+ const finalConfig = {
156
+ ...defaultConfig,
157
+ ...currentConfig,
158
+ aliases: {
159
+ ...defaultConfig.aliases,
160
+ ...currentConfig.aliases,
161
+ },
162
+ };
163
+
164
+ configSchema.omit({ resolvedPaths: true }).parse(finalConfig);
165
+
166
+ await writeFile(configPath, JSON.stringify(finalConfig, null, 2));
167
+ },
168
+ },
169
+ ];
170
+
171
+ logger.break();
172
+ logger.info("Starting HyperFetch CLI initialization...");
173
+
174
+ // eslint-disable-next-line no-restricted-syntax
175
+ for (const step of steps) {
176
+ const s = spinner(step.name).start();
177
+ // eslint-disable-next-line no-await-in-loop
178
+ const result = await step.action(config);
179
+ if (result) {
180
+ config = result;
181
+ }
182
+ s.succeed();
183
+ }
184
+
185
+ logger.break();
186
+ logger.info("Configuration has been generated successfully! 🎉");
187
+ logger.info(`You can now find your configuration at ${configPath}`);
188
+ } catch (err) {
189
+ handleError(err);
190
+ }
191
+ });
@@ -0,0 +1,59 @@
1
+ import path from "path";
2
+ import fs from "fs-extra";
3
+ import { loadConfig } from "tsconfig-paths";
4
+
5
+ import { highlighter } from "utils/highlighter";
6
+ import { resolveImport } from "utils/resolve-import";
7
+ import { logger } from "../utils/logger";
8
+ import { handleError } from "../utils/handle-error";
9
+ import { configSchema, Config } from "config/schema";
10
+
11
+ export async function resolveConfigPaths(cwd: string, config: Omit<Config, "resolvedPaths">): Promise<Config> {
12
+ // Read tsconfig.json.
13
+ const tsConfig = await loadConfig(cwd);
14
+
15
+ if (tsConfig.resultType === "failed") {
16
+ throw new Error(`Failed to load ${config.tsx ? "tsconfig" : "jsconfig"}.json. ${tsConfig.message ?? ""}`.trim());
17
+ }
18
+
19
+ return configSchema.parse({
20
+ ...config,
21
+ resolvedPaths: {
22
+ cwd,
23
+ api: await resolveImport(config.aliases.api, tsConfig),
24
+ components: await resolveImport(config.aliases.components, tsConfig),
25
+ lib: await resolveImport(config.aliases.lib, tsConfig),
26
+ hooks: await resolveImport(config.aliases.hooks, tsConfig),
27
+ ui: await resolveImport(config.aliases.ui, tsConfig),
28
+ },
29
+ });
30
+ }
31
+
32
+ export async function getConfig(cwd: string): Promise<Config | null> {
33
+ // Check for existing api.json file.
34
+ if (!fs.existsSync(path.resolve(cwd, "api.json"))) {
35
+ logger.break();
36
+ logger.error(
37
+ `An invalid ${highlighter.info("api.json")} file was found at ${highlighter.info(
38
+ cwd,
39
+ )}.\nBefore you can add or generate SDKs, you must create a valid ${highlighter.info(
40
+ "api.json",
41
+ )} file by running the ${highlighter.info("init")} command.`,
42
+ );
43
+ logger.break();
44
+ process.exit(1);
45
+ }
46
+ const { data, error } = await configSchema
47
+ .omit({ resolvedPaths: true }) // We enrich it later
48
+ .safeParseAsync(JSON.parse(fs.readFileSync(path.resolve(cwd, "api.json"), "utf8")));
49
+
50
+ if (error) {
51
+ handleError(error);
52
+ }
53
+
54
+ if (!data) {
55
+ throw new Error(`Invalid configuration found in ${highlighter.info(cwd)}.`);
56
+ }
57
+
58
+ return resolveConfigPaths(cwd, data);
59
+ }
@@ -0,0 +1,25 @@
1
+ import { loadConfig } from "tsconfig-paths";
2
+
3
+ export async function getTsConfigAliasPrefix(cwd: string) {
4
+ const tsConfig = await loadConfig(cwd);
5
+
6
+ if (tsConfig?.resultType === "failed" || !Object.entries(tsConfig?.paths).length) {
7
+ return null;
8
+ }
9
+
10
+ // This assume that the first alias is the prefix.
11
+ // eslint-disable-next-line no-restricted-syntax
12
+ for (const [alias, paths] of Object.entries(tsConfig.paths)) {
13
+ if (
14
+ paths.includes("./*") ||
15
+ paths.includes("./src/*") ||
16
+ paths.includes("./app/*") ||
17
+ paths.includes("./resources/js/*") // Laravel.
18
+ ) {
19
+ return alias.replace(/\/\*$/, "") ?? null;
20
+ }
21
+ }
22
+
23
+ // Use the first alias as the prefix.
24
+ return Object.keys(tsConfig?.paths)?.[0].replace(/\/\*$/, "") ?? null;
25
+ }
@@ -0,0 +1,22 @@
1
+ import { z } from "zod";
2
+
3
+ export const configSchema = z.object({
4
+ tsx: z.boolean(),
5
+ aliases: z.object({
6
+ api: z.string(),
7
+ hooks: z.string(),
8
+ ui: z.string(),
9
+ components: z.string(),
10
+ lib: z.string(),
11
+ }),
12
+ resolvedPaths: z.object({
13
+ cwd: z.string(),
14
+ api: z.string(),
15
+ hooks: z.string(),
16
+ ui: z.string(),
17
+ components: z.string(),
18
+ lib: z.string(),
19
+ }),
20
+ });
21
+
22
+ export type Config = z.infer<typeof configSchema>;
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "codegen";
@@ -0,0 +1,43 @@
1
+ import path from "path";
2
+ import fs from "fs-extra";
3
+ import { z } from "zod";
4
+
5
+ import { addOptionsSchema } from "commands/add";
6
+ import * as ERRORS from "utils/errors";
7
+ import { getConfig } from "config/get-config";
8
+ import { highlighter } from "utils/highlighter";
9
+ import { logger } from "utils/logger";
10
+
11
+ export async function preFlightAdd(options: z.infer<typeof addOptionsSchema>) {
12
+ const errors: Record<string, boolean> = {};
13
+
14
+ // Ensure target directory exists.
15
+ // Check for empty project. We assume if no package.json exists, the project is empty.
16
+ if (!fs.existsSync(options.cwd) || !fs.existsSync(path.resolve(options.cwd, "package.json"))) {
17
+ errors[ERRORS.MISSING_DIR_OR_EMPTY_PROJECT] = true;
18
+ return {
19
+ errors,
20
+ config: null,
21
+ };
22
+ }
23
+
24
+ try {
25
+ const config = await getConfig(options.cwd);
26
+
27
+ return {
28
+ errors,
29
+ config: config!,
30
+ };
31
+ } catch (error) {
32
+ logger.break();
33
+ logger.error(
34
+ `An invalid ${highlighter.info("api.json")} file was found at ${highlighter.info(
35
+ options.cwd,
36
+ )}.\nBefore you can add SDKs, you must create a valid ${highlighter.info(
37
+ "api.json",
38
+ )} file by running the ${highlighter.info("init")} command.`,
39
+ );
40
+ logger.break();
41
+ process.exit(1);
42
+ }
43
+ }
@@ -0,0 +1,46 @@
1
+ import path from "path";
2
+ import fs from "fs-extra";
3
+ import { z } from "zod";
4
+
5
+ import { generateOptionsSchema } from "commands/generate";
6
+ import * as ERRORS from "utils/errors";
7
+ import { getConfig } from "config/get-config";
8
+ import { Config } from "config/schema";
9
+ import { highlighter } from "utils/highlighter";
10
+ import { logger } from "utils/logger";
11
+ import { handleError } from "utils/handle-error";
12
+
13
+ export async function preFlightGenerate(options: z.infer<typeof generateOptionsSchema>): Promise<{
14
+ errors: Record<string, boolean>;
15
+ config: Config;
16
+ }> {
17
+ const errors: Record<string, boolean> = {};
18
+
19
+ // Ensure target directory exists.
20
+ // Check for empty project. We assume if no package.json exists, the project is empty.
21
+ if (!fs.existsSync(options.cwd) || !fs.existsSync(path.resolve(options.cwd, "package.json"))) {
22
+ errors[ERRORS.MISSING_DIR_OR_EMPTY_PROJECT] = true;
23
+
24
+ handleError(errors);
25
+ }
26
+
27
+ try {
28
+ const config = await getConfig(options.cwd);
29
+
30
+ return {
31
+ errors,
32
+ config: config!,
33
+ };
34
+ } catch (error) {
35
+ logger.break();
36
+ logger.error(
37
+ `An invalid ${highlighter.info("api.json")} file was found at ${highlighter.info(
38
+ options.cwd,
39
+ )}.\nBefore you can add SDKs, you must create a valid ${highlighter.info(
40
+ "api.json",
41
+ )} file by running the ${highlighter.info("init")} command.`,
42
+ );
43
+ logger.break();
44
+ process.exit(1);
45
+ }
46
+ }
@@ -0,0 +1,13 @@
1
+ export const MISSING_DIR_OR_EMPTY_PROJECT = "1";
2
+ export const EXISTING_CONFIG = "2";
3
+ export const MISSING_CONFIG = "3";
4
+ export const FAILED_CONFIG_READ = "4";
5
+ export const TAILWIND_NOT_CONFIGURED = "5";
6
+ export const IMPORT_ALIAS_MISSING = "6";
7
+ export const UNSUPPORTED_FRAMEWORK = "7";
8
+ export const COMPONENT_URL_NOT_FOUND = "8";
9
+ export const COMPONENT_URL_UNAUTHORIZED = "9";
10
+ export const COMPONENT_URL_FORBIDDEN = "10";
11
+ export const COMPONENT_URL_BAD_REQUEST = "11";
12
+ export const COMPONENT_URL_INTERNAL_SERVER_ERROR = "12";
13
+ export const BUILD_MISSING_REGISTRY_FILE = "13";
@@ -0,0 +1,35 @@
1
+ import chalk from "chalk";
2
+ import { z } from "zod";
3
+
4
+ import { logger } from "utils/logger";
5
+
6
+ export function handleError(error: unknown) {
7
+ logger.break();
8
+ logger.error(`Something went wrong. Please check the error below for more details.`);
9
+ logger.error(`If the problem persists, please open an issue on GitHub.`);
10
+ logger.error("");
11
+ if (typeof error === "string") {
12
+ logger.error(error);
13
+ logger.break();
14
+ process.exit(1);
15
+ }
16
+
17
+ if (error instanceof z.ZodError) {
18
+ logger.error("Validation failed:");
19
+ // eslint-disable-next-line no-restricted-syntax
20
+ for (const [key, value] of Object.entries(error.flatten().fieldErrors)) {
21
+ logger.error(`- ${chalk.cyan(key)}: ${value}`);
22
+ }
23
+ logger.break();
24
+ process.exit(1);
25
+ }
26
+
27
+ if (error instanceof Error) {
28
+ logger.error(error.message);
29
+ logger.break();
30
+ process.exit(1);
31
+ }
32
+
33
+ logger.break();
34
+ process.exit(1);
35
+ }
@@ -0,0 +1,8 @@
1
+ import { cyan, green, red, yellow } from "kleur/colors";
2
+
3
+ export const highlighter = {
4
+ error: red,
5
+ warn: yellow,
6
+ info: cyan,
7
+ success: green,
8
+ };
@@ -0,0 +1,20 @@
1
+ /* eslint-disable no-console */
2
+ import chalk from "chalk";
3
+
4
+ export const logger = {
5
+ info(...args: unknown[]) {
6
+ console.log(chalk.cyan("ℹ"), chalk.blue.bold("info"), ...args);
7
+ },
8
+ warn(...args: unknown[]) {
9
+ console.log(chalk.yellow("⚠"), chalk.yellow.bold("warn"), ...args);
10
+ },
11
+ error(...args: unknown[]) {
12
+ console.log(chalk.red("✖"), chalk.red.bold("error"), ...args);
13
+ },
14
+ success(...args: unknown[]) {
15
+ console.log(chalk.green("✔"), chalk.green.bold("success"), ...args);
16
+ },
17
+ break() {
18
+ console.log("");
19
+ },
20
+ };
@@ -0,0 +1,14 @@
1
+ import { createMatchPath, type ConfigLoaderSuccessResult } from "tsconfig-paths";
2
+
3
+ export async function resolveImport(
4
+ importPath: string,
5
+ config: Pick<ConfigLoaderSuccessResult, "absoluteBaseUrl" | "paths">,
6
+ ) {
7
+ return createMatchPath(config.absoluteBaseUrl, config.paths)(importPath, undefined, () => true, [
8
+ ".ts",
9
+ ".tsx",
10
+ ".jsx",
11
+ ".js",
12
+ ".css",
13
+ ]);
14
+ }
@@ -0,0 +1,37 @@
1
+ import { z } from "zod";
2
+ import Table from "cli-table3";
3
+
4
+ import { zodToTable } from "./zod-to-table";
5
+
6
+ export const showHelp = (schema: z.ZodType) => {
7
+ const rows = zodToTable(schema).map(({ name, description }) => [`--${name}`, description || ""]);
8
+
9
+ const maxOptionLength = rows.reduce((max, row) => Math.max(max, row[0].length), 0);
10
+ const terminalWidth = process.stdout.columns;
11
+
12
+ const tableOptions: Table.TableConstructorOptions = {
13
+ head: ["Option", "Description"],
14
+ style: {
15
+ head: ["blue"],
16
+ },
17
+ wordWrap: true,
18
+ };
19
+
20
+ if (terminalWidth) {
21
+ // Accounting for borders and padding.
22
+ const tableOverhead = 7;
23
+ const optionColWidth = maxOptionLength + 2;
24
+ const descriptionColWidth = terminalWidth - optionColWidth - tableOverhead;
25
+
26
+ if (descriptionColWidth > 10) {
27
+ tableOptions.colWidths = [optionColWidth, descriptionColWidth];
28
+ }
29
+ }
30
+
31
+ const table = new Table(tableOptions);
32
+
33
+ table.push(...rows);
34
+
35
+ // eslint-disable-next-line no-console
36
+ console.log(table.toString());
37
+ };
@@ -0,0 +1,13 @@
1
+ import ora, { type Options } from "ora";
2
+
3
+ export function spinner(
4
+ text: Options["text"],
5
+ options?: {
6
+ silent?: boolean;
7
+ },
8
+ ) {
9
+ return ora({
10
+ text,
11
+ isSilent: options?.silent,
12
+ });
13
+ }
@@ -0,0 +1,16 @@
1
+ import { z } from "zod";
2
+
3
+ export const zodToTable = (schema: z.ZodType): { name: string; description: string | undefined }[] => {
4
+ if (schema instanceof z.ZodObject) {
5
+ const { shape } = schema;
6
+ return Object.keys(shape).map((key) => {
7
+ const fieldSchema = shape[key];
8
+
9
+ return {
10
+ name: key,
11
+ description: fieldSchema.description,
12
+ };
13
+ });
14
+ }
15
+ return [];
16
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "strict": true,
5
+ "baseUrl": "./src",
6
+ "jsx": "react-jsx"
7
+ },
8
+ "exclude": ["node_modules", "dist", "jest.config.ts", "__tests__"]
9
+ }