diff --git a/.eslintrc b/.eslintrc index 2f278186..0ee08119 100644 --- a/.eslintrc +++ b/.eslintrc @@ -23,9 +23,6 @@ // This enables the use of a lint rule to reject use of @deprecated functions. // https://github.com/gund/eslint-plugin-deprecation "deprecation", - // Import sorting integrated into ESLint. - // https://github.com/lydell/eslint-plugin-simple-import-sort - "simple-import-sort", // https://github.com/microsoft/tsdoc/tree/master/eslint-plugin "tsdoc" ], @@ -33,8 +30,7 @@ "eslint:recommended", "plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/recommended", - "plugin:@typescript-eslint/recommended-requiring-type-checking", - "prettier" + "plugin:@typescript-eslint/recommended-requiring-type-checking" ], "overrides": [], "rules": { @@ -48,13 +44,6 @@ "quotes": "off", "@typescript-eslint/quotes": ["warn", "backtick"], "tsdoc/syntax": "warn", - "simple-import-sort/imports": [ - "warn", - { - "groups": [] - } - ], - "simple-import-sort/exports": "warn", "deprecation/deprecation": "warn", "prefer-arrow/prefer-arrow-functions": "warn", // TypeScript makes these safe & effective diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 04d24f0e..70511452 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -10,6 +10,7 @@ jobs: steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 - uses: ./.github/actions/setup + - run: pnpm --workspace-root add dprint - run: pnpm format:check test: runs-on: ubuntu-latest diff --git a/.prettierrc.cjs b/.prettierrc.cjs deleted file mode 100644 index 1b4844ed..00000000 --- a/.prettierrc.cjs +++ /dev/null @@ -1,6 +0,0 @@ -/** - * @see https://prettier.io/docs/en/configuration.html - */ -module.exports = { - ...require('@prisma-labs/prettier-config'), -} diff --git a/.vscode/extensions.json b/.vscode/extensions.json index d7df89c9..ceb811df 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,3 +1,3 @@ { - "recommendations": ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint"] + "recommendations": ["dprint.dprint", "dbaeumer.vscode-eslint"] } diff --git a/.vscode/settings.json b/.vscode/settings.json index aac8086b..b017778b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,6 +12,5 @@ "source.fixAll.eslint": true, // Disable this because it will conflict with ESLint based import organizing. "source.organizeImports": false - }, - "vitest.commandLine": "" + } } diff --git a/README.md b/README.md index 60c26d09..3c94d328 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ A set of packages related to building CLIs. Each package has its own docs. -| 📛 | Package | Description | Use Case | Alternatives | -| --- | ----------------------------------------------------------------------- | -------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | -| 🌲 | `molt`
[packages/molt](./packages/molt/) | Batteries included CLI framework. Builds on top of the `@molt/*` packages. | Building a CLI with multiple commands, sub-commands, etc. | [OClif](https://oclif.io) [Commander](https://github.com/tj/commander.js/) [Yargs](https://github.com/yargs/yargs) | -| 🌱 | `@molt/command`
[packages/@molt/command](./packages/@molt/command/) | Type-safe CLI command definition and execution. | Just want to setup a quick and dirty script, build a small one-command CLI, etc. | [Arg](https://github.com/vercel/arg) | -| ⛑ | `@molt/types`
[packages/@molt/types](./packages/@molt/types/) | Advanced Types for parsing flags & more. | Building your own CLI runtime, but looking for some TypeScript utility types for greater type safety. | Nothing | +| 📛 | Package | Description | Use Case | Alternatives | +| -- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | +| 🌲 | `molt`
[packages/molt](./packages/molt/) | Batteries included CLI framework. Builds on top of the `@molt/*` packages. | Building a CLI with multiple commands, sub-commands, etc. | [OClif](https://oclif.io) [Commander](https://github.com/tj/commander.js/) [Yargs](https://github.com/yargs/yargs) | +| 🌱 | `@molt/command`
[packages/@molt/command](./packages/@molt/command/) | Type-safe CLI command definition and execution. | Just want to setup a quick and dirty script, build a small one-command CLI, etc. | [Arg](https://github.com/vercel/arg) | +| ⛑ | `@molt/types`
[packages/@molt/types](./packages/@molt/types/) | Advanced Types for parsing flags & more. | Building your own CLI runtime, but looking for some TypeScript utility types for greater type safety. | Nothing | diff --git a/dprint.json b/dprint.json new file mode 100644 index 00000000..57953666 --- /dev/null +++ b/dprint.json @@ -0,0 +1,16 @@ +{ + "typescript": { + "quoteStyle": "preferSingle", + "semiColons": "asi" + }, + "json": {}, + "markdown": {}, + "toml": {}, + "excludes": ["**/node_modules", "**/*-lock.json"], + "plugins": [ + "https://plugins.dprint.dev/typescript-0.88.3.wasm", + "https://plugins.dprint.dev/json-0.19.0.wasm", + "https://plugins.dprint.dev/markdown-0.16.2.wasm", + "https://plugins.dprint.dev/toml-0.5.4.wasm" + ] +} diff --git a/package.json b/package.json index 6ff4f79c..8208cfff 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,8 @@ "license": "MIT", "type": "module", "scripts": { - "format": "prettier --write .", - "format:check": "prettier --check .", + "format": "dprint fmt", + "format:check": "dprint check", "lint": "eslint . --ext .ts,.tsx --fix", "check:lint": "eslint . --ext .ts,.tsx --max-warnings 0", "check:types": "tsc --noEmit", @@ -18,7 +18,6 @@ }, "devDependencies": { "@octokit/core": "^5.0.1", - "@prisma-labs/prettier-config": "0.1.0", "@swc/core": "1.3.94", "@tsconfig/node14": "14.1.0", "@tsconfig/node16": "16.1.1", @@ -28,18 +27,15 @@ "@typescript-eslint/eslint-plugin": "6.7.5", "@typescript-eslint/parser": "6.7.5", "eslint": "8.52.0", - "eslint-config-prettier": "9.0.0", "eslint-plugin-deprecation": "2.0.0", "eslint-plugin-only-warn": "1.1.0", "eslint-plugin-prefer-arrow": "1.2.3", - "eslint-plugin-simple-import-sort": "10.0.0", "eslint-plugin-tsdoc": "0.2.17", "execa": "8.0.1", "fast-glob": "3.3.1", "fs-jetpack": "5.1.0", "markdown-toc": "^1.2.0", "nodemon": "^3.0.1", - "prettier": "3.0.3", "semver": "^7.5.4", "semver-regex": "4.0.5", "tsx": "^4.0.0", diff --git a/packages/@molt/command/README.md b/packages/@molt/command/README.md index 8f2e986e..8e34be05 100644 --- a/packages/@molt/command/README.md +++ b/packages/@molt/command/README.md @@ -76,21 +76,30 @@ import { z } from 'zod' const args = Command.create() .use(Zod) .parameter(`filePath`, z.string().describe(`Path to the file to convert.`)) - .parameter(`to`, z.enum([`json`, `yaml`, `toml`]).describe(`Format to convert to.`)) + .parameter( + `to`, + z.enum([`json`, `yaml`, `toml`]).describe(`Format to convert to.`), + ) .parameter( `from`, z .enum([`json`, `yaml`, `toml`]) .optional() - .describe(`Format to convert from. By default inferred from the file extension.`), + .describe( + `Format to convert from. By default inferred from the file extension.`, + ), ) .parameter( `verbose v`, - z.boolean().default(false).describe(`Log detailed progress as conversion executes.`), + z.boolean().default(false).describe( + `Log detailed progress as conversion executes.`, + ), ) .parameter( `move m`, - z.boolean().default(false).describe(`Delete the original file after it has been converted.`), + z.boolean().default(false).describe( + `Delete the original file after it has been converted.`, + ), ) .parse() ``` @@ -139,7 +148,10 @@ $ mybin --help - Default values: ```ts - const args = Command.create().parameter('--path', z.string().default('./a/b/c')).parse() + const args = Command.create().parameter( + '--path', + z.string().default('./a/b/c'), + ).parse() args.path === './a/b/c/' // $ mybin args.path === '/over/ride' // $ mybin --path /over/ride ``` @@ -223,7 +235,6 @@ const args = command.parameter('charlie', z.number()) You can define parameters using dash prefixes (flag syntax). ```ts -// prettier-ignore const args = Command.create() .parameter('--foo -f', z.string()) .parameter('qux q', z.string()) @@ -348,7 +359,8 @@ This section covers the different kinds of built-in types and how they affect ar Examples: ```ts -const args = Command.create().parameter('f force forcefully', z.boolean()).parse() +const args = Command.create().parameter('f force forcefully', z.boolean()) + .parse() // $ CLI_PARAM_NO_F='true' mybin // $ CLI_PARAM_NO_FORCE='true' mybin // $ CLI_PARAM_NO_FORCEFULLY='true' mybin @@ -418,7 +430,7 @@ args.force === true - `min` - The minimum allowed number. - `max` - the maximum allowed number. -- `multipleOf` - The multiple that the given number must be of. For example `20, 15, 10,5 ` would all be allowed if `multipleOf` was `5` since all those numbers are divisible by `5`. +- `multipleOf` - The multiple that the given number must be of. For example `20, 15, 10,5` would all be allowed if `multipleOf` was `5` since all those numbers are divisible by `5`. - `int` #### Enum @@ -454,7 +466,10 @@ args.force === true - By default help rendering will render something like so: ```ts - Command.create().parameter('xee', z.union([z.string(), z.number()]).description('Blah blah blah.')) + Command.create().parameter( + 'xee', + z.union([z.string(), z.number()]).description('Blah blah blah.'), + ) ``` ``` @@ -558,7 +573,6 @@ $ mybin --filePath ./a/b/c.yaml ``` 1/3 level ❯ high | medium | low - ``` - string @@ -684,7 +698,10 @@ const args = await Command.create() .parameter(`to`, { schema: z.enum([`json`, `yaml`, `toml`]), prompt: { - when: [Command.EventPatterns.rejectedMissingOrInvalid, Command.EventPatterns.omittedWithoutDefault], + when: [ + Command.EventPatterns.rejectedMissingOrInvalid, + Command.EventPatterns.omittedWithoutDefault, + ], }, }) .parse() @@ -921,7 +938,12 @@ const args = Command.create() .parameter('--foo', z.string().default('not_from_env')) .parameter('--bar', z.string().default('not_from_env')) .parameter('--qux', z.string().default('not_from_env')) - .settings({ environment: { $default: { enabled: true, prefix: 'MOO' }, bar: { prefix: true } } }) + .settings({ + environment: { + $default: { enabled: true, prefix: 'MOO' }, + bar: { prefix: true }, + }, + }) .parse() // $ MOO_FOO='foo' CLI_PARAM_BAR='bar' MOO_QUX='qux' mybin @@ -968,7 +990,12 @@ const args = Command.create() .parameter('--foo', z.string().default('not_from_env')) .parameter('--bar', z.string().default('not_from_env')) .parameter('--qux', z.string().default('not_from_env')) - .settings({ environment: { $default: { enabled: true, prefix: false }, bar: { prefix: true } } }) + .settings({ + environment: { + $default: { enabled: true, prefix: false }, + bar: { prefix: true }, + }, + }) .parse() // $ FOO='foo' CLI_PARAM_BAR='bar' QUX='qux' mybin @@ -1018,11 +1045,12 @@ With the chaining API you can declaratively state that two or more parameters ar Here is an example where you might want this feature. You are building a CLI for publishing software packages that allows the user to specify the version to publish either by [semver](https://semver.org) level to bump by OR an exact version. ```ts -// prettier-ignore const args = Command.create() - .parametersExclusive(`method`, (_) => - _.parameter(`v version`, z.string().regex(semverRegex())) - .parameter(`b bump`, z.enum([`major`, `minor`, `patch`])) + .parametersExclusive( + `method`, + (_) => + _.parameter(`v version`, z.string().regex(semverRegex())) + .parameter(`b bump`, z.enum([`major`, `minor`, `patch`])), ) ``` @@ -1037,10 +1065,9 @@ There are three key benefits to this method: In the above example `args` will end up with a `method` property whose type is: ```ts -// prettier-ignore type Method = - | { _tag: 'version', value: string } - | { _tag: 'bump', value: 'major' | 'minor' | 'patch' } + | { _tag: 'version'; value: string } + | { _tag: 'bump'; value: 'major' | 'minor' | 'patch' } ``` You automatically get a proper TypeScript-ready discriminant property based on the canonical names of your parameters. This helps you to write type-safe code. Also, it pairs well with [Alge 🌱](https://github.com/jasonkuhrt/alge) :). In the following example `Semver.inc` expects a strongly typed semver bump level of `'major'|'minor'|'patch'`: @@ -1057,12 +1084,13 @@ const newVersion = Alge.match(args.method) By default, input for a group of mutually exclusive parameters is required. You can mark the group as being optional: ```ts -// prettier-ignore const args = Command.create() - .parametersExclusive(`method`, (_) => - _.parameter(`v version`, z.string().regex(semverRegex())) - .parameter(`b bump`, z.enum([`major`, `minor`, `patch`])) - .optional() + .parametersExclusive( + `method`, + (_) => + _.parameter(`v version`, z.string().regex(semverRegex())) + .parameter(`b bump`, z.enum([`major`, `minor`, `patch`])) + .optional(), ) ``` @@ -1071,13 +1099,14 @@ const args = Command.create() By default, input for a group of mutually exclusive parameters is required. You can mark the group as being optional for users via a default so that internally there is always a value: ```ts -// prettier-ignore const args = Command.create() - .parametersExclusive(`method`, (_) => - _.parameter(`v version`, z.string().regex(semverRegex())) - .parameter(`b bump`, z.enum([`major`, `minor`, `patch`])) - .optional() - .default('bump', 'patch') + .parametersExclusive( + `method`, + (_) => + _.parameter(`v version`, z.string().regex(semverRegex())) + .parameter(`b bump`, z.enum([`major`, `minor`, `patch`])) + .optional() + .default('bump', 'patch'), ) ``` @@ -1096,7 +1125,7 @@ const args = Command.create() .description( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.', ) - .parameter(/* ... */) + .parameter() /* ... */ ``` Descriptions will show up in the auto generated help. @@ -1169,7 +1198,10 @@ mybin --xee z <-- enable xee using z You could achieve this with the following parameter definition: ```ts -const args = Command.create().parameter('xee', z.union([z.boolean(), z.enum(['x', 'y', 'z'])]).default(false)) +const args = Command.create().parameter( + 'xee', + z.union([z.boolean(), z.enum(['x', 'y', 'z'])]).default(false), +) args.xee // type: false | true | 'x' | 'y' | 'z' ``` @@ -1192,5 +1224,4 @@ Molt Command is composed from multiple distinct layers that execute in a flow: 1. Prompt/Up Front Arguments Merger (prompt overrides up front) ``` - ``` diff --git a/packages/@molt/command/examples/intro.ts b/packages/@molt/command/examples/intro.ts index 749e17eb..e2c7e43b 100644 --- a/packages/@molt/command/examples/intro.ts +++ b/packages/@molt/command/examples/intro.ts @@ -1,6 +1,6 @@ +import { z } from 'zod' import { Command } from '../src/_entrypoints/default.js' import { Zod } from '../src/_entrypoints/extensions.js' -import { z } from 'zod' const args = await Command.create() .use(Zod) diff --git a/packages/@molt/command/examples/kitchen-sink.ts b/packages/@molt/command/examples/kitchen-sink.ts index 264a843a..2340ba93 100644 --- a/packages/@molt/command/examples/kitchen-sink.ts +++ b/packages/@molt/command/examples/kitchen-sink.ts @@ -1,6 +1,6 @@ +import { z } from 'zod' import { Command } from '../src/_entrypoints/default.js' import { Zod } from '../src/_entrypoints/extensions.js' -import { z } from 'zod' const args = Command.create() .use(Zod) @@ -71,8 +71,7 @@ const args = Command.create() z .enum([`apple`, `banana`, `orange`]) .describe(`A sustainable snack for everyday happiness and delight!`), - ), - ) + )) .settings({ parameters: { environment: { diff --git a/packages/@molt/command/examples/prompt.ts b/packages/@molt/command/examples/prompt.ts index 4c8824bb..29ce8206 100644 --- a/packages/@molt/command/examples/prompt.ts +++ b/packages/@molt/command/examples/prompt.ts @@ -1,6 +1,6 @@ +import { z } from 'zod' import { Command } from '../src/_entrypoints/default.js' import { Zod } from '../src/_entrypoints/extensions.js' -import { z } from 'zod' const args = await Command.create() .use(Zod) diff --git a/packages/@molt/command/examples/publish.ts b/packages/@molt/command/examples/publish.ts index 55e4013a..ebbe0a71 100644 --- a/packages/@molt/command/examples/publish.ts +++ b/packages/@molt/command/examples/publish.ts @@ -1,7 +1,7 @@ -import { Command } from '../src/_entrypoints/default.js' -import { Zod } from '../src/_entrypoints/extensions.js' import semverRegex from 'semver-regex' import { z } from 'zod' +import { Command } from '../src/_entrypoints/default.js' +import { Zod } from '../src/_entrypoints/extensions.js' const args = Command.create() .use(Zod) @@ -10,10 +10,8 @@ const args = Command.create() .parameter(`githubRelease`, z.boolean().default(true)) .parameter(`p package`, z.enum([`@molt/command`, `@molt/types`, `molt`])) .parametersExclusive(`method`, (__) => - // prettier-ignore __.parameter(`v version`, z.string().regex(semverRegex())) - .parameter(`b bump`, z.enum([`major`, `minor`, `patch`])), - ) + .parameter(`b bump`, z.enum([`major`, `minor`, `patch`]))) .settings({ parameters: { environment: { diff --git a/packages/@molt/command/package.json b/packages/@molt/command/package.json index 963795d1..fd7de130 100644 --- a/packages/@molt/command/package.json +++ b/packages/@molt/command/package.json @@ -11,7 +11,7 @@ "build": "pnpm clean && pnpm build:cjs && pnpm build:esm", "build:cjs": "tsc --project tsconfig.cjs.json && echo '{\"type\":\"commonjs\"}' > build/cjs/package.json", "build:esm": "tsc --project tsconfig.esm.json", - "build:toc": "markdown-toc README.md -i --maxdepth 4 && prettier --write README.md", + "build:toc": "markdown-toc README.md -i --maxdepth 4 && dprint fmt README.md", "prepublishOnly": "pnpm build", "examples:intro": "tsx examples/intro.ts", "examples:prompt": "tsx examples/prompt.ts", diff --git a/packages/@molt/command/src/CommandParameter/output.ts b/packages/@molt/command/src/CommandParameter/output.ts index dff29f5e..a9fdb0b5 100644 --- a/packages/@molt/command/src/CommandParameter/output.ts +++ b/packages/@molt/command/src/CommandParameter/output.ts @@ -11,7 +11,7 @@ // when: EventPatternsInput | null // } -// // prettier-ignore +// // type BasicOptionality = // | { _tag: 'required' } // | { _tag: 'optional' } diff --git a/packages/@molt/command/src/Errors/Errors.ts b/packages/@molt/command/src/Errors/Errors.ts index 56e303bb..d5e6950c 100644 --- a/packages/@molt/command/src/Errors/Errors.ts +++ b/packages/@molt/command/src/Errors/Errors.ts @@ -40,7 +40,8 @@ export class ErrorDuplicateEnvArg extends Error { parameter: Parameter instances: { value: string; name: string; prefix: string | null }[] }) { - const message = `The parameter "${params.parameter.name.canonical}" was passed an argument multiple times via different parameter aliases in the environment.` + const message = + `The parameter "${params.parameter.name.canonical}" was passed an argument multiple times via different parameter aliases in the environment.` super(message) this.parameter = params.parameter this.instances = params.instances @@ -68,14 +69,17 @@ export class ErrorMissingArgument extends Error { } export class ErrorMissingArgumentForMutuallyExclusiveParameters extends Error { - public override name: 'ErrorMissingArgumentForMutuallyExclusiveParameters' = `ErrorMissingArgumentForMutuallyExclusiveParameters` + public override name: 'ErrorMissingArgumentForMutuallyExclusiveParameters' = + `ErrorMissingArgumentForMutuallyExclusiveParameters` public group: ParameterExclusiveGroup constructor(params: { group: ParameterExclusiveGroup }) { - const message = `Missing argument for one of the following parameters: ${Object.values( - params.group.parameters, - ) - .map((_) => _.name.canonical) - .join(`, `)}` + const message = `Missing argument for one of the following parameters: ${ + Object.values( + params.group.parameters, + ) + .map((_) => _.name.canonical) + .join(`, `) + }` super(message) this.group = params.group } @@ -85,9 +89,11 @@ export class ErrorArgumentsToMutuallyExclusiveParameters extends Error { public override name: 'ErrorArgumentsToMutuallyExclusiveParameters' = `ErrorArgumentsToMutuallyExclusiveParameters` public group: ParameterExclusiveGroup constructor(params: { offenses: { spec: ParameterExclusive; arg: OpeningArgs.Argument }[] }) { - const message = `Arguments given to multiple mutually exclusive parameters: ${params.offenses - .map((_) => _.spec.name.canonical) - .join(`, `)}` + const message = `Arguments given to multiple mutually exclusive parameters: ${ + params.offenses + .map((_) => _.spec.name.canonical) + .join(`, `) + }` super(message) this.group = params.offenses[0]!.spec.group } diff --git a/packages/@molt/command/src/Help/Help.ts b/packages/@molt/command/src/Help/Help.ts index 5778df30..ffc91c51 100644 --- a/packages/@molt/command/src/Help/Help.ts +++ b/packages/@molt/command/src/Help/Help.ts @@ -1,12 +1,12 @@ +import chalk from 'chalk' +import camelCase from 'lodash.camelcase' +import snakeCase from 'lodash.snakecase' import { groupBy } from '../lib/prelude.js' import { Tex } from '../lib/Tex/index.js' import { Text } from '../lib/Text/index.js' import type { Parameter } from '../Parameter/types.js' import type { Settings } from '../Settings/index.js' import { Term } from '../term.js' -import chalk from 'chalk' -import camelCase from 'lodash.camelcase' -import snakeCase from 'lodash.snakecase' // TODO use interface RenderSettings { @@ -36,17 +36,16 @@ export const render = (parameters_: Parameter[], settings: Settings.Output, _set : -1 : _.type.optionality._tag === `optional` ? 1 - : -1, + : -1 ) const parametersBasicWithoutHelp = basicParameters .filter((_) => _.name.canonical !== `help`) .sort((_) => (_.type.optionality._tag === `optional` ? 1 : -1)) const isAcceptsAnyEnvironmentArgs = basicParameters.filter((_) => _.environment?.enabled).length > 0 - const isAcceptsAnyMutuallyExclusiveParameters = - (parametersByTag.Exclusive && parametersByTag.Exclusive.length > 0) || false - const isEnvironmentEnabled = - Object.values(settings.parameters.environment).filter((_) => _.enabled).length > 0 + const isAcceptsAnyMutuallyExclusiveParameters = (parametersByTag.Exclusive && parametersByTag.Exclusive.length > 0) + || false + const isEnvironmentEnabled = Object.values(settings.parameters.environment).filter((_) => _.enabled).length > 0 const columnTitles = { name: `Name`, @@ -82,68 +81,73 @@ export const render = (parameters_: Parameter[], settings: Settings.Output, _set ) }) .block({ padding: { top: 1, bottom: 1 } }, title(`PARAMETERS`)) - .block({ padding: { left: 2 } }, (__) => - __.table({ separators: { column: ` `, row: null } }, (__) => - __.header({ padding: { right: 2, bottom: 1 } }, chalk.underline(Term.colors.mute(columnTitles.name))) - .header( - { - minWidth: 8, - padding: { right: 5 }, - }, - chalk.underline(Term.colors.mute(columnTitles.typeDescription)), - ) - .header({ padding: { right: 4 } }, chalk.underline(Term.colors.mute(columnTitles.default))) - .header( - columnTitles.environment ? chalk.underline(Term.colors.mute(columnTitles.environment)) : null, - ) - .rows([ - ...parametersBasicWithoutHelp.map((parameter) => [ - parameterName(parameter), - Tex.block({ maxWidth: 40, padding: { right: 9, bottom: 1 } }, parameter.type.help(settings)), - Tex.block({ maxWidth: 24 }, parameterDefault(parameter)), - ...(isEnvironmentEnabled ? [parameterEnvironment(parameter, settings)] : []), - ]), - ...parametersExclusiveGroups.flatMap((parametersExclusive) => { - const default_ = - parametersExclusive.optionality._tag === `default` - ? `${parametersExclusive.optionality.tag}@${String( - parametersExclusive.optionality.getValue(), - )}` - : parametersExclusive.optionality._tag === `optional` - ? `undefined` - : labels.required - return [ - [ - Tex.block( - { border: { left: Term.colors.dim(`┌`) } }, - Term.colors.dim(`─${parametersExclusive.label} ${`(2)`}`), - ), - ``, - default_, - ], - ...Object.values(parametersExclusive.parameters).map((parameter) => [ + .block( + { padding: { left: 2 } }, + (__) => + __.table( + { separators: { column: ` `, row: null } }, + (__) => + __.header({ padding: { right: 2, bottom: 1 } }, chalk.underline(Term.colors.mute(columnTitles.name))) + .header( + { + minWidth: 8, + padding: { right: 5 }, + }, + chalk.underline(Term.colors.mute(columnTitles.typeDescription)), + ) + .header({ padding: { right: 4 } }, chalk.underline(Term.colors.mute(columnTitles.default))) + .header( + columnTitles.environment ? chalk.underline(Term.colors.mute(columnTitles.environment)) : null, + ) + .rows([ + ...parametersBasicWithoutHelp.map((parameter) => [ parameterName(parameter), - parameter.type.help(settings), - parameterDefault(parameter), + Tex.block({ maxWidth: 40, padding: { right: 9, bottom: 1 } }, parameter.type.help(settings)), + Tex.block({ maxWidth: 24 }, parameterDefault(parameter)), ...(isEnvironmentEnabled ? [parameterEnvironment(parameter, settings)] : []), ]), - [Tex.block({ border: { left: Term.colors.dim(`└`) } }, Term.colors.dim(`─`))], - ] - }), - ]), - ).block({ color: Term.colors.dim }, ($) => { - if (noteItems.length === 0) { - return null - } - return $.block({ padding: { top: 1 }, border: { bottom: `━` }, width: `100%` }, `NOTES`).list( - { - bullet: { - graphic: (index) => `(${index + 1})`, + ...parametersExclusiveGroups.flatMap((parametersExclusive) => { + const default_ = parametersExclusive.optionality._tag === `default` + ? `${parametersExclusive.optionality.tag}@${ + String( + parametersExclusive.optionality.getValue(), + ) + }` + : parametersExclusive.optionality._tag === `optional` + ? `undefined` + : labels.required + return [ + [ + Tex.block( + { border: { left: Term.colors.dim(`┌`) } }, + Term.colors.dim(`─${parametersExclusive.label} ${`(2)`}`), + ), + ``, + default_, + ], + ...Object.values(parametersExclusive.parameters).map((parameter) => [ + parameterName(parameter), + parameter.type.help(settings), + parameterDefault(parameter), + ...(isEnvironmentEnabled ? [parameterEnvironment(parameter, settings)] : []), + ]), + [Tex.block({ border: { left: Term.colors.dim(`└`) } }, Term.colors.dim(`─`))], + ] + }), + ]), + ).block({ color: Term.colors.dim }, ($) => { + if (noteItems.length === 0) { + return null + } + return $.block({ padding: { top: 1 }, border: { bottom: `━` }, width: `100%` }, `NOTES`).list( + { + bullet: { + graphic: (index) => `(${index + 1})`, + }, }, - }, - noteItems, - ) - }), + noteItems, + ) + }), ) .render() @@ -151,37 +155,39 @@ export const render = (parameters_: Parameter[], settings: Settings.Output, _set } const environmentNote = (parameters: Parameter[], settings: Settings.Output) => { - const isHasParametersWithCustomEnvironmentNamespace = - parameters - .filter((_) => _.environment?.enabled) - .filter( - (_) => - _.environment!.namespaces.filter((_) => - settings.parameters.environment.$default.prefix.map(camelCase).includes(_), - ).length !== _.environment!.namespaces.length, - ).length > 0 + const isHasParametersWithCustomEnvironmentNamespace = parameters + .filter((_) => _.environment?.enabled) + .filter( + (_) => + _.environment!.namespaces.filter((_) => + settings.parameters.environment.$default.prefix.map(camelCase).includes(_) + ).length !== _.environment!.namespaces.length, + ).length > 0 let content = `` - content += - (settings.parameters.environment.$default.enabled ? `Parameters` : `Some parameters (marked in docs)`) + - ` can be passed arguments via environment variables. Command line arguments take precedence. Environment variable names are snake cased versions of the parameter name (or its aliases), case insensitive. ` + content += (settings.parameters.environment.$default.enabled ? `Parameters` : `Some parameters (marked in docs)`) + + ` can be passed arguments via environment variables. Command line arguments take precedence. Environment variable names are snake cased versions of the parameter name (or its aliases), case insensitive. ` if (settings.parameters.environment.$default.prefix.length > 0) { if (isHasParametersWithCustomEnvironmentNamespace) { content += `By default they must be prefixed with` - content += ` ${Text.joinListEnglish( - settings.parameters.environment.$default.prefix.map((_) => - Term.colors.secondary(Text.toEnvarNameCase(_) + `_`), - ), - )} (case insensitive), though some parameters deviate (shown in docs). ` + content += ` ${ + Text.joinListEnglish( + settings.parameters.environment.$default.prefix.map((_) => + Term.colors.secondary(Text.toEnvarNameCase(_) + `_`) + ), + ) + } (case insensitive), though some parameters deviate (shown in docs). ` } else { content += `They must be prefixed with` - content += ` ${Text.joinListEnglish( - settings.parameters.environment.$default.prefix.map((_) => - Term.colors.secondary(Text.toEnvarNameCase(_) + `_`), - ), - )} (case insensitive). ` + content += ` ${ + Text.joinListEnglish( + settings.parameters.environment.$default.prefix.map((_) => + Term.colors.secondary(Text.toEnvarNameCase(_) + `_`) + ), + ) + } (case insensitive). ` } } else { content += isHasParametersWithCustomEnvironmentNamespace @@ -196,10 +202,12 @@ const environmentNote = (parameters: Parameter[], settings: Settings.Output) => .slice(0, 3) .map((_) => _.environment!.namespaces.length > 0 - ? `${Term.colors.secondary( + ? `${ + Term.colors.secondary( Text.toEnvarNameCase(_.environment!.namespaces[0]!) + `_`, - )}${Term.colors.positive(Text.toEnvarNameCase(_.name.canonical))}` - : Term.colors.positive(Text.toEnvarNameCase(_.name.canonical)), + ) + }${Term.colors.positive(Text.toEnvarNameCase(_.name.canonical))}` + : Term.colors.positive(Text.toEnvarNameCase(_.name.canonical)) ) .map((_) => `${_}="..."`) @@ -212,7 +220,7 @@ const environmentNote = (parameters: Parameter[], settings: Settings.Output) => }, }, examples, - ), + ) ) } @@ -242,25 +250,23 @@ const labels = { } const parameterName = (parameter: Parameter) => { - const isRequired = - (parameter._tag === `Basic` && parameter.type.optionality._tag === `required`) || - (parameter._tag === `Exclusive` && parameter.group.optionality._tag === `required`) + const isRequired = (parameter._tag === `Basic` && parameter.type.optionality._tag === `required`) + || (parameter._tag === `Exclusive` && parameter.group.optionality._tag === `required`) - const parameters: Tex.BlockParameters = - parameter._tag === `Exclusive` - ? { - border: { - left: (lineNumber) => - lineNumber === 0 - ? Term.colors.accent(`◒ `) - : Term.colors.dim(`${Text.chars.borders.vertical} `), - }, - } - : { - padding: { - bottom: 1, - }, - } + const parameters: Tex.BlockParameters = parameter._tag === `Exclusive` + ? { + border: { + left: (lineNumber) => + lineNumber === 0 + ? Term.colors.accent(`◒ `) + : Term.colors.dim(`${Text.chars.borders.vertical} `), + }, + } + : { + padding: { + bottom: 1, + }, + } return Tex.block(parameters, (__) => __.block( @@ -270,27 +276,26 @@ const parameterName = (parameter: Parameter) => { ) .block(Term.colors.dim(parameter.name.aliases.long.join(`, `)) || null) .block(Term.colors.dim(parameter.name.short ?? ``) || null) - .block(Term.colors.dim(parameter.name.aliases.long.join(`, `)) || null), - ) + .block(Term.colors.dim(parameter.name.aliases.long.join(`, `)) || null)) } const parameterEnvironment = (parameter: Parameter, settings: Settings.Output) => { return parameter.environment?.enabled - ? Term.colors.secondary(Text.chars.check) + - (parameter.environment.enabled && parameter.environment.namespaces.length === 0 - ? ` ` + Term.colors.dim(Text.toEnvarNameCase(parameter.name.canonical)) - : parameter.environment.enabled && - parameter.environment.namespaces.filter( - // TODO settings normalized should store prefix in camel case - (_) => !settings.parameters.environment.$default.prefix.includes(snakeCase(_)), - ).length > 0 - ? ` ` + - Term.colors.dim( - parameter.environment.namespaces - .map((_) => `${Text.toEnvarNameCase(_)}_${Text.toEnvarNameCase(parameter.name.canonical)}`) - .join(` ${Text.chars.pipe} `), - ) - : ``) + ? Term.colors.secondary(Text.chars.check) + + (parameter.environment.enabled && parameter.environment.namespaces.length === 0 + ? ` ` + Term.colors.dim(Text.toEnvarNameCase(parameter.name.canonical)) + : parameter.environment.enabled + && parameter.environment.namespaces.filter( + // TODO settings normalized should store prefix in camel case + (_) => !settings.parameters.environment.$default.prefix.includes(snakeCase(_)), + ).length > 0 + ? ` ` + + Term.colors.dim( + parameter.environment.namespaces + .map((_) => `${Text.toEnvarNameCase(_)}_${Text.toEnvarNameCase(parameter.name.canonical)}`) + .join(` ${Text.chars.pipe} `), + ) + : ``) : Term.colors.dim(Text.chars.x) } diff --git a/packages/@molt/command/src/OpeningArgs/Environment/Environment.ts b/packages/@molt/command/src/OpeningArgs/Environment/Environment.ts index 44ef5eb2..bab4503e 100644 --- a/packages/@molt/command/src/OpeningArgs/Environment/Environment.ts +++ b/packages/@molt/command/src/OpeningArgs/Environment/Environment.ts @@ -1,11 +1,11 @@ +import camelCase from 'lodash.camelcase' +import snakecase from 'lodash.snakecase' import { Errors } from '../../Errors/index.js' import type { Index, RequireField } from '../../lib/prelude.js' import { getNames } from '../../Parameter/helpers/CommandParameter.js' import type { Parameter } from '../../Parameter/types.js' import { parseSerializedValue } from '../helpers.js' import type { EnvironmentArgumentReport } from '../types.js' -import camelCase from 'lodash.camelcase' -import snakecase from 'lodash.snakecase' export const defaultParameterNamePrefixes = [`cli_parameter`, `cli_param`] @@ -86,11 +86,10 @@ export const lookupEnvironmentVariableArgument = ( parameterName: string, ): null | { name: string; value: string } => { const parameterNameSnakeCase = snakecase(parameterName) - const parameterNames = - prefixes.length === 0 - ? [parameterNameSnakeCase] - : // TODO add test coverage for the snake case conversion of a parameter name - prefixes.map((prefix) => `${prefix.toLowerCase()}_${parameterNameSnakeCase.toLowerCase()}`) + const parameterNames = prefixes.length === 0 + ? [parameterNameSnakeCase] + // TODO add test coverage for the snake case conversion of a parameter name + : prefixes.map((prefix) => `${prefix.toLowerCase()}_${parameterNameSnakeCase.toLowerCase()}`) const args = parameterNames .map((name) => ({ name, value: environment[name] })) @@ -98,10 +97,11 @@ export const lookupEnvironmentVariableArgument = ( if (args.length === 0) return null - if (args.length > 1) + if (args.length > 1) { throw new Error( `Multiple environment variables found for same parameter "${parameterName}": ${args.join(`, `)}`, ) + } // dump(prefixes, environment, parameterName) @@ -185,8 +185,7 @@ const parseNegated = (string: string) => { } } -const lowercaseFirst = (string: string) => - string.length === 0 ? string : string[0]!.toLowerCase() + string.slice(1) +const lowercaseFirst = (string: string) => string.length === 0 ? string : string[0]!.toLowerCase() + string.slice(1) interface Envar { name: { @@ -202,12 +201,12 @@ const normalizeEnvironment = (environment: RawInputs): Envar[] => { value === undefined ? value : { - value, - name: { - raw: name, - camel: camelCase(name), - }, + value, + name: { + raw: name, + camel: camelCase(name), }, + } ) .filter((envar): envar is Envar => envar !== undefined) } diff --git a/packages/@molt/command/src/OpeningArgs/Line/Line.ts b/packages/@molt/command/src/OpeningArgs/Line/Line.ts index 81450f99..315e1297 100644 --- a/packages/@molt/command/src/OpeningArgs/Line/Line.ts +++ b/packages/@molt/command/src/OpeningArgs/Line/Line.ts @@ -1,3 +1,4 @@ +import camelCase from 'lodash.camelcase' import { Errors } from '../../Errors/index.js' import { stripeNegatePrefixLoose } from '../../helpers.js' import type { Index } from '../../lib/prelude.js' @@ -5,7 +6,6 @@ import { findByName, isOrHasType } from '../../Parameter/helpers/CommandParamete import type { Parameter } from '../../Parameter/types.js' import { isNegated, parseSerializedValue, stripeDashPrefix } from '../helpers.js' import type { ArgumentReport } from '../types.js' -import camelCase from 'lodash.camelcase' export type RawInputs = string[] @@ -138,8 +138,7 @@ const isFlag = (lineInput: string) => isLongFlag(lineInput) || isShortFlag(lineI const isLongFlag = (lineInput: string) => lineInput.trim().startsWith(`--`) -const isShortFlag = (lineInput: string) => - lineInput.trim().startsWith(`-`) && !lineInput.trim().startsWith(`--`) +const isShortFlag = (lineInput: string) => lineInput.trim().startsWith(`-`) && !lineInput.trim().startsWith(`--`) const stripeShortFlagPrefixUnsafe = (lineInput: string) => lineInput.trim().slice(1) diff --git a/packages/@molt/command/src/OpeningArgs/OpeningArgs.ts b/packages/@molt/command/src/OpeningArgs/OpeningArgs.ts index c3053c0e..545fadc7 100644 --- a/packages/@molt/command/src/OpeningArgs/OpeningArgs.ts +++ b/packages/@molt/command/src/OpeningArgs/OpeningArgs.ts @@ -1,3 +1,4 @@ +import { Alge } from 'alge' import { Errors } from '../Errors/index.js' import { errorFromUnknown, groupBy } from '../lib/prelude.js' import type { ParameterExclusive } from '../Parameter/exclusive.js' @@ -5,7 +6,6 @@ import type { Parameter } from '../Parameter/types.js' import { Environment } from './Environment/index.js' import { Line } from './Line/index.js' import type { ArgumentReport, ParseResult } from './types.js' -import { Alge } from 'alge' export { Environment } from './Environment/index.js' export { Line } from './Line/index.js' export * from './types.js' @@ -51,8 +51,8 @@ export const parse = ({ */ // todo, a strict mode where errors are NOT ignored from env parsing when line is present - const argReport = - lineParseResult.reports[parameter.name.canonical] ?? envParseResult.reports[parameter.name.canonical] + const argReport = lineParseResult.reports[parameter.name.canonical] + ?? envParseResult.reports[parameter.name.canonical] /** * An opening argument was given. Process it. diff --git a/packages/@molt/command/src/OpeningArgs/helpers.ts b/packages/@molt/command/src/OpeningArgs/helpers.ts index 02792290..fd5b955f 100644 --- a/packages/@molt/command/src/OpeningArgs/helpers.ts +++ b/packages/@molt/command/src/OpeningArgs/helpers.ts @@ -1,14 +1,13 @@ +import { Either } from 'effect' +import camelCase from 'lodash.camelcase' import { negateNamePattern } from '../helpers.js' import type { Parameter } from '../Parameter/types.js' import type { Value } from './types.js' -import { Either } from 'effect' -import camelCase from 'lodash.camelcase' export const stripeDashPrefix = (flagNameInput: string): string => { return flagNameInput.replace(/^-+/, ``) } -// prettier-ignore export const parseSerializedValue = (name: string, serializedValue: string, spec: Parameter): Value => { const either = spec.type.deserialize(serializedValue) if (Either.isLeft(either)) { diff --git a/packages/@molt/command/src/OpeningArgs/types.ts b/packages/@molt/command/src/OpeningArgs/types.ts index 5d1ff23c..919bffaa 100644 --- a/packages/@molt/command/src/OpeningArgs/types.ts +++ b/packages/@molt/command/src/OpeningArgs/types.ts @@ -96,9 +96,9 @@ export type ParseResultExclusiveGroupError = { export type ParseResultExclusiveGroup = | ParseResultExclusiveGroupSupplied | { - _tag: 'omitted' - parameter: ParameterExclusiveGroup - } + _tag: 'omitted' + parameter: ParameterExclusiveGroup + } | ParseResultExclusiveGroupError export type ParseResult = { diff --git a/packages/@molt/command/src/Parameter/basic.ts b/packages/@molt/command/src/Parameter/basic.ts index dd0b6ca9..c441e5ca 100644 --- a/packages/@molt/command/src/Parameter/basic.ts +++ b/packages/@molt/command/src/Parameter/basic.ts @@ -1,3 +1,4 @@ +import { Name } from '@molt/types' import type { BuilderCommandState } from '../builders/command/state.js' import type { HKT } from '../helpers.js' import type { Pam } from '../lib/Pam/index.js' @@ -5,7 +6,6 @@ import type { Settings } from '../Settings/index.js' import type { Optionality } from '../Type/Type.js' import { processEnvironment } from './helpers/environment.js' import type { Environment, Prompt } from './helpers/types.js' -import { Name } from '@molt/types' export interface ParameterBasicInput< $State extends BuilderCommandState.Base = BuilderCommandState.BaseEmpty, @@ -29,8 +29,13 @@ export const parameterBasicCreate = ( const name = Name.parse(input.nameExpression) const environment = processEnvironment(settings, name) const prompt = input.prompt as boolean | null | { enabled?: boolean; when?: object } // eslint-disable-line - const promptEnabled = - prompt === true ? true : prompt === false ? false : prompt === null ? null : prompt.enabled ?? null + const promptEnabled = prompt === true + ? true + : prompt === false + ? false + : prompt === null + ? null + : prompt.enabled ?? null const promptEnabledWhen = prompt === null ? null : typeof prompt === `object` ? prompt.when ?? null : null return { _tag: `Basic`, diff --git a/packages/@molt/command/src/Parameter/exclusive.ts b/packages/@molt/command/src/Parameter/exclusive.ts index 9b69c5e6..dd9c18d5 100644 --- a/packages/@molt/command/src/Parameter/exclusive.ts +++ b/packages/@molt/command/src/Parameter/exclusive.ts @@ -1,12 +1,12 @@ +import type { Name as MoltName } from '@molt/types' +import { Name } from '@molt/types' +import { Alge } from 'alge' import type { BuilderCommandState } from '../builders/command/state.js' import type { Pam } from '../lib/Pam/index.js' import type { Settings } from '../Settings/index.js' import type { Type } from '../Type/index.js' import { processEnvironment } from './helpers/environment.js' import type { Environment } from './helpers/types.js' -import type { Name as MoltName } from '@molt/types' -import { Name } from '@molt/types' -import { Alge } from 'alge' export interface ParameterExclusiveInput< $State extends BuilderCommandState.Base = BuilderCommandState.BaseEmpty, diff --git a/packages/@molt/command/src/Parameter/helpers/CommandParameter.ts b/packages/@molt/command/src/Parameter/helpers/CommandParameter.ts index f0dbddaa..a9ad00f5 100644 --- a/packages/@molt/command/src/Parameter/helpers/CommandParameter.ts +++ b/packages/@molt/command/src/Parameter/helpers/CommandParameter.ts @@ -1,8 +1,8 @@ +import { Either } from 'effect' import { stripeNegatePrefix } from '../../helpers.js' import type { Type } from '../../Type/index.js' import type { ValidationResult } from '../../Type/Type.js' import type { Parameter } from '../types.js' -import { Either } from 'effect' export const validate = (parameter: Parameter, value: unknown): ValidationResult => { if (parameter.type.optionality._tag === `optional` && value === undefined) return Either.right(value as T) @@ -31,15 +31,15 @@ export const getNames = (parameter: Parameter): [string, ...string[]] => { type NameHit = | { - kind: 'long' | 'longAlias' - /** - * Was the given name in negated format? e.g. noFoo instead of foo - */ - negated: boolean - } + kind: 'long' | 'longAlias' + /** + * Was the given name in negated format? e.g. noFoo instead of foo + */ + negated: boolean + } | { - kind: 'short' | 'shortAlias' - } + kind: 'short' | 'shortAlias' + } /** * Is one of the parameter's names the given name? @@ -72,8 +72,8 @@ const parameterSpecHasNameDo = ( ? { kind: `long`, negated } : parameter.name.aliases.long.includes(name) ? { kind: `longAlias`, negated } - : // Short names cannot be negated currently so short circuit with the negated check. - parameter.name.short === name + // Short names cannot be negated currently so short circuit with the negated check. + : parameter.name.short === name ? { kind: `short` } : parameter.name.aliases.short.includes(name) ? { kind: `shortAlias` } diff --git a/packages/@molt/command/src/Parameter/helpers/environment.ts b/packages/@molt/command/src/Parameter/helpers/environment.ts index 12afbaa0..f4505c81 100644 --- a/packages/@molt/command/src/Parameter/helpers/environment.ts +++ b/packages/@molt/command/src/Parameter/helpers/environment.ts @@ -1,22 +1,21 @@ -import type { Settings } from '../../Settings/index.js' -import type { Environment } from './types.js' import type { Name } from '@molt/types' import camelCase from 'lodash.camelcase' +import type { Settings } from '../../Settings/index.js' +import type { Environment } from './types.js' /** * Parse the specification for a parameter's environment support. */ export const processEnvironment = (settings: Settings.Output, name: Name.Data.NameParsed): Environment => { - const hasEnvironment = - settings.parameters.environment[name.canonical]?.enabled ?? - settings.parameters.environment.$default.enabled + const hasEnvironment = settings.parameters.environment[name.canonical]?.enabled + ?? settings.parameters.environment.$default.enabled return hasEnvironment ? { - enabled: hasEnvironment, - namespaces: ( - settings.parameters.environment[name.canonical]?.prefix ?? - settings.parameters.environment.$default.prefix - ).map((_) => camelCase(_)), - } + enabled: hasEnvironment, + namespaces: ( + settings.parameters.environment[name.canonical]?.prefix + ?? settings.parameters.environment.$default.prefix + ).map((_) => camelCase(_)), + } : null } diff --git a/packages/@molt/command/src/Parameter/types.ts b/packages/@molt/command/src/Parameter/types.ts index 288c2f10..210368b3 100644 --- a/packages/@molt/command/src/Parameter/types.ts +++ b/packages/@molt/command/src/Parameter/types.ts @@ -9,6 +9,6 @@ export type Prompt = | null | boolean | { - enabled?: boolean - when?: EventPatternsInput - } + enabled?: boolean + when?: EventPatternsInput + } diff --git a/packages/@molt/command/src/Pattern/Pattern.ts b/packages/@molt/command/src/Pattern/Pattern.ts index 6ff00545..16ebb365 100644 --- a/packages/@molt/command/src/Pattern/Pattern.ts +++ b/packages/@molt/command/src/Pattern/Pattern.ts @@ -8,26 +8,25 @@ type SomeDataObject = object type SomeDataScalar = number | string | boolean | null -// prettier-ignore -export type Pattern = - Or< - Data extends SomeDataScalar ? Data : - PatternForObject, DiscriminantProperty> +export type Pattern = Or< + Data extends SomeDataScalar ? Data + : PatternForObject, DiscriminantProperty> > -export type PatternForValue = Data extends SomeDataScalar - ? Data +export type PatternForValue = Data extends SomeDataScalar ? Data : PatternForObject> -// prettier-ignore -export type PatternForObject = { - [K in Exclude]?:Simplify< - Data[K] extends Array ? Or[]> : - Data[K] extends SomeDataObject ? Or> : - Or> - } & ( +export type PatternForObject = + & { + [K in Exclude]?: Simplify< + Data[K] extends Array ? Or[]> + : Data[K] extends SomeDataObject ? Or> + : Or + > + } + & ( null extends DiscriminantProperty ? {} // eslint-disable-line - : { [K in Exclude]: Data[K] } + : { [K in Exclude]: Data[K] } ) type Or = T | T[] diff --git a/packages/@molt/command/src/Settings/settings.ts b/packages/@molt/command/src/Settings/settings.ts index 87b4b224..18690870 100644 --- a/packages/@molt/command/src/Settings/settings.ts +++ b/packages/@molt/command/src/Settings/settings.ts @@ -1,3 +1,4 @@ +import snakeCase from 'lodash.snakecase' import type { BuilderCommandState } from '../builders/command/state.js' import type { EventPatternsInput, EventPatternsInputAtLeastOne } from '../eventPatterns.js' import { eventPatterns } from '../eventPatterns.js' @@ -5,16 +6,15 @@ import type { Values } from '../helpers.js' import { parseEnvironmentVariableBooleanOrThrow } from '../helpers.js' import { defaultParameterNamePrefixes } from '../OpeningArgs/Environment/Environment.js' import type { Type } from '../Type/index.js' -import snakeCase from 'lodash.snakecase' export type OnErrorReaction = 'exit' | 'throw' export type PromptInput = | boolean | { - enabled?: boolean - when?: EventPatternsInputAtLeastOne - } + enabled?: boolean + when?: EventPatternsInputAtLeastOne + } // eslint-disable-next-line export interface Input<$State extends BuilderCommandState.Base = BuilderCommandState.BaseEmpty> { @@ -31,14 +31,19 @@ export interface Input<$State extends BuilderCommandState.Base = BuilderCommandS onOutput?: (output: string, defaultHandler: (output: string) => void) => void prompt?: PromptInput>> parameters?: { - // prettier-ignore environment?: | boolean - | ({ - [NameExpression in keyof $State['Parameters'] as $State['Parameters'][NameExpression]['NameParsed']['canonical']]?: boolean | SettingInputEnvironmentParameter - } & { + | ( + & { + [ + NameExpression + in keyof $State['Parameters'] as $State['Parameters'][NameExpression]['NameParsed']['canonical'] + ]?: boolean | SettingInputEnvironmentParameter + } + & { $default?: boolean | SettingInputEnvironmentParameter - }) + } + ) } } @@ -123,8 +128,8 @@ export const change = ( current.onOutput = input.onOutput ? (_) => { - input.onOutput!(_, process.stdout.write.bind(process.stdout)) - } + input.onOutput!(_, process.stdout.write.bind(process.stdout)) + } : current.onOutput if (input.parameters !== undefined) { @@ -146,10 +151,11 @@ export const change = ( } else { // As soon as the settings begin to specify explicit parameter settings // AND there is NO explicit default toggle setting, then we disable all the rest by default. - // prettier-ignore + if ( - input.parameters.environment.$default === undefined || - typeof input.parameters.environment.$default !== `boolean` && input.parameters.environment.$default.enabled === undefined + input.parameters.environment.$default === undefined + || typeof input.parameters.environment.$default !== `boolean` + && input.parameters.environment.$default.enabled === undefined ) { const parameterEnvironmentSpecs = Object.keys(input.parameters.environment).filter((k) => k !== `$default`) current.parameters.environment.$default.enabled = parameterEnvironmentSpecs.length === 0 @@ -194,18 +200,18 @@ export const change = ( const isEnvironmentEnabled = (lowercaseEnv: NodeJS.ProcessEnv) => { return lowercaseEnv[`cli_settings_read_arguments_from_environment`] - ? //eslint-disable-next-line - parseEnvironmentVariableBooleanOrThrow(lowercaseEnv[`cli_settings_read_arguments_from_environment`]!) - : // : processEnvLowerCase[`cli_environment_arguments`] - // ? //eslint-disable-next-line - // parseEnvironmentVariableBoolean(processEnvLowerCase[`cli_environment_arguments`]!) - // : processEnvLowerCase[`cli_env_args`] - // ? //eslint-disable-next-line - // parseEnvironmentVariableBoolean(processEnvLowerCase[`cli_env_args`]!) - // : processEnvLowerCase[`cli_env_arguments`] - // ? //eslint-disable-next-line - // parseEnvironmentVariableBoolean(processEnvLowerCase[`cli_env_arguments`]!) - true + // eslint-disable-next-line + ? parseEnvironmentVariableBooleanOrThrow(lowercaseEnv[`cli_settings_read_arguments_from_environment`]!) + // : processEnvLowerCase[`cli_environment_arguments`] + // ? //eslint-disable-next-line + // parseEnvironmentVariableBoolean(processEnvLowerCase[`cli_environment_arguments`]!) + // : processEnvLowerCase[`cli_env_args`] + // ? //eslint-disable-next-line + // parseEnvironmentVariableBoolean(processEnvLowerCase[`cli_env_args`]!) + // : processEnvLowerCase[`cli_env_arguments`] + // ? //eslint-disable-next-line + // parseEnvironmentVariableBoolean(processEnvLowerCase[`cli_env_arguments`]!) + : true } export const getDefaults = (lowercaseEnv: NodeJS.ProcessEnv): Output => { diff --git a/packages/@molt/command/src/Type/Type.ts b/packages/@molt/command/src/Type/Type.ts index 2e0d3772..46b35883 100644 --- a/packages/@molt/command/src/Type/Type.ts +++ b/packages/@molt/command/src/Type/Type.ts @@ -1,5 +1,5 @@ -import type { Type, TypeSymbol } from './helpers.js' import type { Either } from 'effect' +import type { Type, TypeSymbol } from './helpers.js' export * from './helpers.js' export { Scalar } from './types/Scalar.js' diff --git a/packages/@molt/command/src/Type/helpers.ts b/packages/@molt/command/src/Type/helpers.ts index c17dde2d..047e78fc 100644 --- a/packages/@molt/command/src/Type/helpers.ts +++ b/packages/@molt/command/src/Type/helpers.ts @@ -1,7 +1,7 @@ +import type { Effect, Either } from 'effect' import type { PromptEngine } from '../lib/PromptEngine/PromptEngine.js' import type { Tex } from '../lib/Tex/index.js' import type { ValidationResult } from './Type.js' -import type { Effect, Either } from 'effect' export const TypeSymbol = Symbol(`type`) diff --git a/packages/@molt/command/src/Type/types/Scalars/Boolean.ts b/packages/@molt/command/src/Type/types/Scalars/Boolean.ts index d6b3a3e2..bc300357 100644 --- a/packages/@molt/command/src/Type/types/Scalars/Boolean.ts +++ b/packages/@molt/command/src/Type/types/Scalars/Boolean.ts @@ -1,11 +1,11 @@ +import chalk from 'chalk' +import { Effect, Either } from 'effect' import { parseEnvironmentVariableBoolean } from '../../../helpers.js' import { PromptEngine } from '../../../lib/PromptEngine/PromptEngine.js' import { Tex } from '../../../lib/Tex/index.js' import { Term } from '../../../term.js' import type { Optionality, Type } from '../../helpers.js' import { runtimeIgnore, TypeSymbol } from '../../helpers.js' -import chalk from 'chalk' -import { Effect, Either } from 'effect' export interface Boolean extends Type { _tag: 'TypeBoolean' @@ -43,7 +43,7 @@ export const boolean = ({ return parseEnvironmentVariableBoolean(rawValue) }, prompt: (params) => { - return Effect.gen(function* (_) { + return Effect.gen(function*(_) { interface State { value: boolean } diff --git a/packages/@molt/command/src/Type/types/Scalars/Enumeration.ts b/packages/@molt/command/src/Type/types/Scalars/Enumeration.ts index 8c629381..f146f8ab 100644 --- a/packages/@molt/command/src/Type/types/Scalars/Enumeration.ts +++ b/packages/@molt/command/src/Type/types/Scalars/Enumeration.ts @@ -1,10 +1,10 @@ +import chalk from 'chalk' +import { Effect, Either } from 'effect' import { PromptEngine } from '../../../lib/PromptEngine/PromptEngine.js' import { Text } from '../../../lib/Text/index.js' import { Term } from '../../../term.js' import type { Optionality, Type } from '../../helpers.js' import { runtimeIgnore, TypeSymbol } from '../../helpers.js' -import chalk from 'chalk' -import { Effect, Either } from 'effect' export interface Enumeration<$Members extends Member[] = Member[]> extends Type<$Members[number]> { _tag: 'TypeEnum' @@ -51,7 +51,7 @@ export const enumeration = <$Members extends Member[]>({ }, help: () => type.displayExpanded(), prompt: (params) => { - return Effect.gen(function* (_) { + return Effect.gen(function*(_) { interface State { active: number } @@ -78,9 +78,9 @@ export const enumeration = <$Members extends Member[]>({ ], draw: (state) => { return ( - marginLeftSpace + - params.prompt + - members + marginLeftSpace + + params.prompt + + members .map((item, i) => (i === state.active ? `${chalk.green(chalk.bold(item))}` : item)) .join(chalk.dim(` | `)) ) @@ -91,8 +91,12 @@ export const enumeration = <$Members extends Member[]>({ if (state === null) return undefined const choice = members[state.active] - // prettier-ignore - if (!choice) throw new Error(`No choice selected. Enumeration must be empty. But enumerations should not be empty. This is a bug.`) + + if (!choice) { + throw new Error( + `No choice selected. Enumeration must be empty. But enumerations should not be empty. This is a bug.`, + ) + } return choice }) }, diff --git a/packages/@molt/command/src/Type/types/Scalars/Literal.ts b/packages/@molt/command/src/Type/types/Scalars/Literal.ts index f1f2f36b..9ea9a448 100644 --- a/packages/@molt/command/src/Type/types/Scalars/Literal.ts +++ b/packages/@molt/command/src/Type/types/Scalars/Literal.ts @@ -1,8 +1,8 @@ +import { Either } from 'effect' import { BooleanLookup, casesExhausted } from '../../../helpers.js' import { Term } from '../../../term.js' import type { Optionality, Type } from '../../helpers.js' import { runtimeIgnore, TypeSymbol } from '../../helpers.js' -import { Either } from 'effect' export interface Literal<$Value extends LiteralValue = LiteralValue> extends Type<$Value> { _tag: 'TypeLiteral' diff --git a/packages/@molt/command/src/Type/types/Scalars/Number.ts b/packages/@molt/command/src/Type/types/Scalars/Number.ts index bd396092..713aed8e 100644 --- a/packages/@molt/command/src/Type/types/Scalars/Number.ts +++ b/packages/@molt/command/src/Type/types/Scalars/Number.ts @@ -1,8 +1,8 @@ +import { Effect, Either } from 'effect' import { PromptEngine } from '../../../lib/PromptEngine/PromptEngine.js' import { Term } from '../../../term.js' import type { Optionality } from '../../helpers.js' import { runtimeIgnore, type Type, TypeSymbol } from '../../helpers.js' -import { Effect, Either } from 'effect' export interface Number extends Type { _tag: 'TypeNumber' @@ -84,7 +84,7 @@ export const number = ({ return Either.right(value) }, prompt: (params) => - Effect.gen(function* (_) { + Effect.gen(function*(_) { interface State { value: string } diff --git a/packages/@molt/command/src/Type/types/Scalars/String.ts b/packages/@molt/command/src/Type/types/Scalars/String.ts index ccf1c701..4770813c 100644 --- a/packages/@molt/command/src/Type/types/Scalars/String.ts +++ b/packages/@molt/command/src/Type/types/Scalars/String.ts @@ -1,3 +1,5 @@ +import { Alge } from 'alge' +import { Effect, Either } from 'effect' import { casesExhausted, entries } from '../../../helpers.js' import { Patterns } from '../../../lib/Patterns/index.js' import { PromptEngine } from '../../../lib/PromptEngine/PromptEngine.js' @@ -5,8 +7,6 @@ import { Tex } from '../../../lib/Tex/index.js' import { Term } from '../../../term.js' import type { Optionality } from '../../helpers.js' import { runtimeIgnore, type Type, TypeSymbol } from '../../helpers.js' -import { Alge } from 'alge' -import { Effect, Either } from 'effect' export interface String extends Type { _tag: 'TypeString' @@ -28,38 +28,38 @@ interface Refinements { length?: number pattern?: | { - type: 'email' - } + type: 'email' + } | { - type: 'url' - } + type: 'url' + } | { - type: 'uuid' - } + type: 'uuid' + } | { - type: 'cuid' - } + type: 'cuid' + } | { - type: 'cuid2' - } + type: 'cuid2' + } | { - type: 'ulid' - } + type: 'ulid' + } | { - type: 'emoji' - } + type: 'emoji' + } | { - type: 'ip' - /** - * If `null` then either IPv4 or IPv6 is allowed. - */ - version: 4 | 6 | null - } + type: 'ip' + /** + * If `null` then either IPv4 or IPv6 is allowed. + */ + version: 4 | 6 | null + } | { - type: 'dateTime' - offset: boolean - precision: null | number - } + type: 'dateTime' + offset: boolean + precision: null | number + } startsWith?: string endsWith?: string includes?: string @@ -94,8 +94,8 @@ export const string = ({ if (optionality._tag === `optional` && value === undefined) return Either.right(value) const errors: string[] = [] - if (typeof value !== `string`) return Either.left({ value, errors: [`Value is not a string.`] }) // prettier-ignore - if (!refinements) return Either.right(value) // prettier-ignore + if (typeof value !== `string`) return Either.left({ value, errors: [`Value is not a string.`] }) + if (!refinements) return Either.right(value) if (refinements.regex && !refinements.regex.test(value)) { errors.push(`Value does not conform to Regular Expression.`) @@ -213,7 +213,7 @@ export const string = ({ }, value) }, prompt: (params) => - Effect.gen(function* (_) { + Effect.gen(function*(_) { interface State { value: string } diff --git a/packages/@molt/command/src/Type/types/Union.ts b/packages/@molt/command/src/Type/types/Union.ts index 1e45409a..3497b1c6 100644 --- a/packages/@molt/command/src/Type/types/Union.ts +++ b/packages/@molt/command/src/Type/types/Union.ts @@ -1,14 +1,13 @@ +import chalk from 'chalk' +import { Effect, Either } from 'effect' import { PromptEngine } from '../../lib/PromptEngine/PromptEngine.js' import { Tex } from '../../lib/Tex/index.js' import { Text } from '../../lib/Text/index.js' import { Term } from '../../term.js' import type { Optionality } from '../helpers.js' import { runtimeIgnore, type Type, TypeSymbol } from '../helpers.js' -import chalk from 'chalk' -import { Effect, Either } from 'effect' -export interface Union - extends Type { +export interface Union extends Type { _tag: 'TypeUnion' members: Members } @@ -40,18 +39,18 @@ export const union = <$Members extends Member[]>({ [TypeSymbol]: runtimeIgnore, // eslint-disable-line deserialize: (serializedValue) => { return ( - members.map((m) => m.deserialize(serializedValue)).find((m) => Either.isRight(m)) ?? - Either.left(new Error(`No variant matched.`)) + members.map((m) => m.deserialize(serializedValue)).find((m) => Either.isRight(m)) + ?? Either.left(new Error(`No variant matched.`)) ) }, display: () => `union`, displayExpanded: () => `todo`, help: (settings) => { const hasAtLeastOneMemberDescription = members.filter((_) => _.description !== null).length > 0 - //prettier-ignore + const isExpandedMode = - (hasAtLeastOneMemberDescription && settings?.helpRendering?.union?.mode === `expandOnParameterDescription`) || // eslint-disable-line - settings?.helpRendering?.union?.mode === 'expandAlways' // eslint-disable-line + (hasAtLeastOneMemberDescription && settings?.helpRendering?.union?.mode === `expandOnParameterDescription`) // eslint-disable-line + || settings?.helpRendering?.union?.mode === 'expandAlways' // eslint-disable-line const unionMemberIcon = Term.colors.accent(`◒`) const isOneOrMoreMembersWithDescription = members.some((_) => _.description !== null) const isExpandedModeViaForceSetting = isExpandedMode && !isOneOrMoreMembersWithDescription @@ -61,8 +60,7 @@ export const union = <$Members extends Member[]>({ { padding: { bottomBetween: isExpandedModeViaForceSetting ? 0 : 1 }, border: { - left: (index) => - `${index === 0 ? unionMemberIcon : Term.colors.dim(Text.chars.borders.vertical)} `, + left: (index) => `${index === 0 ? unionMemberIcon : Term.colors.dim(Text.chars.borders.vertical)} `, }, }, (__) => __.block(m.displayExpanded()).block(m.description), @@ -78,7 +76,7 @@ export const union = <$Members extends Member[]>({ description ?? null, ) .block(types) - .block(Term.colors.dim(Text.chars.borders.leftBottom + Text.chars.borders.horizontal)), + .block(Term.colors.dim(Text.chars.borders.leftBottom + Text.chars.borders.horizontal)) ) as Tex.Block } else { const membersRendered = members.map((m) => m.displayExpanded()).join(` | `) @@ -92,7 +90,7 @@ export const union = <$Members extends Member[]>({ : Either.left({ value, errors: [`Value does not fit any member of the union.`] }) }, prompt: (params) => - Effect.gen(function* (_) { + Effect.gen(function*(_) { interface State { active: number } @@ -118,18 +116,17 @@ export const union = <$Members extends Member[]>({ ], draw: (state) => { const marginLeftSpace = ` `.repeat(params.marginLeft ?? 0) - // prettier-ignore - const intro = marginLeftSpace + `Different kinds of answers are accepted.` + Text.chars.newline + marginLeftSpace + `Which kind do you want to give?` - // prettier-ignore - const choices = - marginLeftSpace + - params.prompt + - members + const intro = marginLeftSpace + `Different kinds of answers are accepted.` + Text.chars.newline + + marginLeftSpace + `Which kind do you want to give?` + + const choices = marginLeftSpace + + params.prompt + + members .map((item, i) => i === state.active ? `${chalk.green(chalk.bold(item.display()))}` - : item.display(), + : item.display() ) .join(chalk.dim(` | `)) return Text.chars.newline + intro + Text.chars.newline + Text.chars.newline + choices @@ -141,8 +138,12 @@ export const union = <$Members extends Member[]>({ if (state === null) return undefined const choice = members[state.active] - // prettier-ignore - if (!choice) throw new Error(`No choice selected. Enumeration must be empty. But enumerations should not be empty. This is a bug.`) + + if (!choice) { + throw new Error( + `No choice selected. Enumeration must be empty. But enumerations should not be empty. This is a bug.`, + ) + } const res = (yield* _(choice.prompt(params))) as $Members[number] return res diff --git a/packages/@molt/command/src/TypeBuilder/TypeBuilder.ts b/packages/@molt/command/src/TypeBuilder/TypeBuilder.ts index 51cd7bf6..93586bc7 100644 --- a/packages/@molt/command/src/TypeBuilder/TypeBuilder.ts +++ b/packages/@molt/command/src/TypeBuilder/TypeBuilder.ts @@ -1,7 +1,7 @@ // import type { Type } from '../Type/helpers.js' // import type { Extension } from './extension.js' -// // prettier-ignore +// // type TypeBuilderBase<$Extensions extends Record> = $Extensions & { // $use: < // $Namespace extends string, diff --git a/packages/@molt/command/src/builders/command/constructor.ts b/packages/@molt/command/src/builders/command/constructor.ts index 2e8e4835..0e5ab9d0 100644 --- a/packages/@molt/command/src/builders/command/constructor.ts +++ b/packages/@molt/command/src/builders/command/constructor.ts @@ -42,7 +42,7 @@ const create_ = (state: BuilderCommandState): CommandBuilder => { return create_(newState) as any }, parameter: (nameExpression, typeOrConfiguration) => { - const configuration = `type` in typeOrConfiguration ? typeOrConfiguration : { type: typeOrConfiguration } // prettier-ignore + const configuration = `type` in typeOrConfiguration ? typeOrConfiguration : { type: typeOrConfiguration } const prompt = configuration.prompt ?? null const type = state.typeMapper(configuration.type) const parameter = { @@ -79,7 +79,7 @@ const create_ = (state: BuilderCommandState): CommandBuilder => { ...Settings.getDefaults(argInputsEnvironment), } state.newSettingsBuffer.forEach((newSettings) => - Settings.change(state.settings!, newSettings, argInputsEnvironment), + Settings.change(state.settings!, newSettings, argInputsEnvironment) ) state.settings.typeMapper = state.typeMapper return parse(state.settings, state.parameterInputs, argInputs) @@ -98,9 +98,8 @@ interface Parameter { (nameExpression: string, configuration: ParameterConfiguration): InternalRootBuilder } -// prettier-ignore interface InternalRootBuilder { - use: (extension:SomeExtension) => InternalRootBuilder + use: (extension: SomeExtension) => InternalRootBuilder description: (description: string) => InternalRootBuilder settings: (newSettings: Settings.Input) => InternalRootBuilder parameter: Parameter diff --git a/packages/@molt/command/src/builders/command/state.ts b/packages/@molt/command/src/builders/command/state.ts index 3c89346a..3e219702 100644 --- a/packages/@molt/command/src/builders/command/state.ts +++ b/packages/@molt/command/src/builders/command/state.ts @@ -1,3 +1,6 @@ +import type { Name } from '@molt/types' +import type { Objects, Pipe } from 'hotscript' +import type { Simplify } from 'type-fest' import type { Values } from '../../helpers.js' import type { HKT } from '../../helpers.js' import type { ParameterBasicInput } from '../../Parameter/basic.js' @@ -7,9 +10,6 @@ import type { Settings } from '../../Settings/index.js' import type { Type } from '../../Type/index.js' import type { ExclusiveParameterConfiguration } from '../exclusive/types.js' import type { IsPromptEnabledInParameterSettings, ParameterConfiguration } from './types.js' -import type { Name } from '@molt/types' -import type { Objects, Pipe } from 'hotscript' -import type { Simplify } from 'type-fest' export const createState = (): BuilderCommandState => { return { @@ -67,11 +67,10 @@ export namespace BuilderCommandState { type ReservedParameterNames = 'help' | 'h' - // prettier-ignore - export type ValidateNameExpression = - Name.Data.IsParseError; reservedNames: ReservedParameterNames }>> extends true - ? Name.Parse; reservedNames: ReservedParameterNames }> - : NameExpression + export type ValidateNameExpression = Name.Data.IsParseError< + Name.Parse; reservedNames: ReservedParameterNames }> + > extends true ? Name.Parse; reservedNames: ReservedParameterNames }> + : NameExpression export type GetUsedNames = Values['NameUnion'] @@ -83,22 +82,23 @@ export namespace BuilderCommandState { } > - // prettier-ignore export type SetExclusiveOptional< $State extends Base, Label extends string, Value extends boolean, - > = - Pipe<$State, [ - Objects.Update<'ParametersExclusive', - Objects.Assign<{ + > = Pipe<$State, [ + Objects.Update< + 'ParametersExclusive', + Objects.Assign< + { [_ in Label]: { - Optional: Value + Optional: Value Parameters: $State['ParametersExclusive'][_]['Parameters'] } - }> + } > - ]> + >, + ]> export type SetIsPromptEnabled<$State extends Base, value extends boolean> = Pipe< $State, @@ -114,9 +114,11 @@ export namespace BuilderCommandState { [ Objects.Update< 'Parameters', - Objects.Assign<{ - [_ in NameExpression]: CreateParameter<$State, NameExpression, Configuration> - }> + Objects.Assign< + { + [_ in NameExpression]: CreateParameter<$State, NameExpression, Configuration> + } + > >, Objects.Update< 'IsPromptEnabled', @@ -125,68 +127,73 @@ export namespace BuilderCommandState { ] > - // prettier-ignore export type AddExclusiveParameter< $State extends Base, Label extends string, NameExpression extends string, - Configuration extends ExclusiveParameterConfiguration<$State> - > = - Pipe<$State, [ - Objects.Update<'ParametersExclusive', - Objects.Assign<$State['ParametersExclusive'] & { + Configuration extends ExclusiveParameterConfiguration<$State>, + > = Pipe<$State, [ + Objects.Update< + 'ParametersExclusive', + Objects.Assign< + & $State['ParametersExclusive'] + & { [_ in Label]: { Optional: $State['ParametersExclusive'][_]['Optional'] Parameters: { [_ in NameExpression as Name.Data.GetCanonicalNameOrErrorFromParseResult>]: { Type: HKT.Call<$State['TypeMapper'], Configuration['type']> - NameParsed: Name.Parse; reservedNames: ReservedParameterNames }> - NameUnion: Name.Data.GetNamesFromParseResult; reservedNames: ReservedParameterNames }>> + NameParsed: Name.Parse< + NameExpression, + { usedNames: GetUsedNames<$State>; reservedNames: ReservedParameterNames } + > + NameUnion: Name.Data.GetNamesFromParseResult< + Name.Parse; reservedNames: ReservedParameterNames }> + > } - } } } - >>]> + > + >, + ]> - // prettier-ignore export type CreateParameter< - $State extends Base, - NameExpression extends string, - Configuration extends ParameterConfiguration<$State>, + $State extends Base, + NameExpression extends string, + Configuration extends ParameterConfiguration<$State>, > = { Type: HKT.Call<$State['TypeMapper'], Configuration['type']> NameParsed: Name.Parse; reservedNames: ReservedParameterNames }> - NameUnion: Name.Data.GetNamesFromParseResult; reservedNames: ReservedParameterNames }>> + NameUnion: Name.Data.GetNamesFromParseResult< + Name.Parse; reservedNames: ReservedParameterNames }> + > } - // prettier-ignore - export type ToArgs<$State extends Base> = - $State['IsPromptEnabled'] extends true - ? Promise> - : ToArgs_<$State> - - // prettier-ignore - type ToArgs_<$State extends Base> = - Simplify< - { - [Name in keyof $State['Parameters'] & string as $State['Parameters'][Name]['NameParsed']['canonical']]: - Type.Infer<$State['Parameters'][Name]['Type']> - } & - { - [Label in keyof $State['ParametersExclusive'] & string]: - | Simplify - } - }>> - | ($State['ParametersExclusive'][Label]['Optional'] extends true ? undefined : never) - } - > + export type ToArgs<$State extends Base> = $State['IsPromptEnabled'] extends true ? Promise> + : ToArgs_<$State> + + type ToArgs_<$State extends Base> = Simplify< + & { + [Name in keyof $State['Parameters'] & string as $State['Parameters'][Name]['NameParsed']['canonical']]: + Type.Infer<$State['Parameters'][Name]['Type']> + } + & { + [Label in keyof $State['ParametersExclusive'] & string]: + | Simplify< + Values< + { + [Name in keyof $State['ParametersExclusive'][Label]['Parameters']]: { + _tag: $State['ParametersExclusive'][Label]['Parameters'][Name]['NameParsed']['canonical'] + value: Type.Infer<$State['ParametersExclusive'][Label]['Parameters'][Name]['Type']> + } + } + > + > + | ($State['ParametersExclusive'][Label]['Optional'] extends true ? undefined : never) + } + > - // prettier-ignore export type ToTypes<$State extends BuilderCommandState.Base> = { [K in keyof $State['Parameters'] & string as $State['Parameters'][K]['NameParsed']['canonical']]: $State['Parameters'][K]['Type'] diff --git a/packages/@molt/command/src/builders/command/types.ts b/packages/@molt/command/src/builders/command/types.ts index d136523c..63d4669b 100644 --- a/packages/@molt/command/src/builders/command/types.ts +++ b/packages/@molt/command/src/builders/command/types.ts @@ -5,9 +5,9 @@ import type { OpeningArgs } from '../../OpeningArgs/index.js' import type { Prompt } from '../../Parameter/types.js' import type { Settings } from '../../Settings/index.js' import type { BuilderExclusiveInitial, SomeBuilderExclusive } from '../exclusive/types.js' +import type { BuilderCommandState } from './state.js' // todo // eslint-disable-next-line -import { BuilderCommandState } from './state.js' import type { Objects, Pipe } from 'hotscript' export interface ParameterConfiguration< @@ -19,46 +19,57 @@ export interface ParameterConfiguration< export type IsHasKey = Key extends keyof Obj ? true : false -// prettier-ignore -export type IsPromptEnabledInParameterSettings

> = - IsHasKey extends false ? false : - IsPromptEnabled -// prettier-ignore -export type IsPromptEnabledInCommandSettings

> = - IsHasKey extends false ? false : - IsPromptEnabled +export type IsPromptEnabledInParameterSettings

> = IsHasKey extends + false ? false + : IsPromptEnabled -// prettier-ignore -export type IsPromptEnabled

|undefined> = - P extends undefined ? false : - P extends false ? false : - P extends true ? true : - P extends null ? false : - Exclude['enabled'] extends false ? false : - true +export type IsPromptEnabledInCommandSettings

> = IsHasKey extends false + ? false + : IsPromptEnabled + +export type IsPromptEnabled

| undefined> = P extends undefined ? false + : P extends false ? false + : P extends true ? true + : P extends null ? false + : Exclude['enabled'] extends false ? false + : true -// prettier-ignore export interface CommandBuilder<$State extends BuilderCommandState.Base = BuilderCommandState.BaseEmpty> { - use<$Extension extends SomeExtension>(extension: $Extension): - CommandBuilder<{ - IsPromptEnabled: $State['IsPromptEnabled'], - Parameters: $State['Parameters'], - ParametersExclusive: $State['ParametersExclusive'], - Type: $Extension['types']['type'] - TypeMapper: $Extension['types']['typeMapper'] - }> - description (this:void, description:string): - CommandBuilder<$State> - parameter> (this:void, name:BuilderCommandState.ValidateNameExpression<$State,NameExpression>, configuration:Configuration): - CommandBuilder> - parameter (this:void, name:BuilderCommandState.ValidateNameExpression<$State,NameExpression>, type:$Type): - CommandBuilder> - parametersExclusive