Skip to content

Commit

Permalink
feat(@molt/command): hide private property on exclusive builder (#262)
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonkuhrt authored Nov 21, 2023
1 parent 09b340c commit 2832cb6
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 64 deletions.
53 changes: 42 additions & 11 deletions packages/@molt/command/examples/kitchen-sink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,23 @@ const args = Command.create()
)
.parameter(
`badDefault`,
z.string().default(() => {
throw new Error(`whoops`)
}),
z
.string()
.default(() => {
throw new Error(`whoops`)
}),
)
.parameter(
`one`,
z
.enum([`apple`]),
)
.parameter(
`figbar`,
z
.enum([`zebra`, `monkey`, `giraffe`])
.default(`monkey`),
)
.parameter(`one`, z.enum([`apple`]))
.parameter(`figbar`, z.enum([`zebra`, `monkey`, `giraffe`]).default(`monkey`))
.parameter(
`big`,
z
Expand All @@ -37,14 +48,28 @@ const args = Command.create()
`i install`,
z
.union([
z.boolean().describe(`Use the system-detected package manager.`),
z.enum([`yarn`, `npm`, `pnpm`]).describe(`Force use of a specific package manager.`),
z
.boolean()
.describe(`Use the system-detected package manager.`),
z
.enum([`yarn`, `npm`, `pnpm`])
.describe(`Force use of a specific package manager.`),
])
.describe(`Run dependency install after setup.`)
.default(false),
)
.parameter(`filePath`, z.string().describe(`Path to the file to convert.`))
.parameter(`to`, z.enum([`json`, `yaml`, `toml`]).describe(`Format to convert to.`))
.parameter(
`filePath`,
z
.string()
.describe(`Path to the file to convert.`),
)
.parameter(
`to`,
z
.enum([`json`, `yaml`, `toml`])
.describe(`Format to convert to.`),
)
.parameter(
`from`,
z
Expand All @@ -54,11 +79,17 @@ const args = Command.create()
)
.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.`),
)
.parametersExclusive(`desert`, (_) =>
_.parameter(
Expand Down
5 changes: 3 additions & 2 deletions packages/@molt/command/src/builders/command/constructor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { ParameterBasicInput } from '../../Parameter/basic.js'
import { Settings } from '../../Settings/index.js'
import type { Type } from '../../Type/index.js'
import * as ExclusiveBuilder from '../exclusive/constructor.js'
import { ExclusiveBuilderStateSymbol } from '../exclusive/state.js'
import type { BuilderCommandState } from './state.js'
import { createState } from './state.js'
import type { CommandBuilder, ParameterConfiguration, RawArgInputs } from './types.js'
Expand Down Expand Up @@ -61,12 +62,12 @@ const create_ = (state: BuilderCommandState): CommandBuilder => {
return create_(newState) as any
},
parametersExclusive: (label, builderContainer) => {
const input = builderContainer(ExclusiveBuilder.create(label, state))._.input // eslint-disable-line
const exclusiveBuilderState = builderContainer(ExclusiveBuilder.create(label, state))[ExclusiveBuilderStateSymbol] // eslint-disable-line
const newState = {
...state,
parameterInputs: {
...state.parameterInputs,
[label]: input, // eslint-disable-line
[label]: exclusiveBuilderState, // eslint-disable-line
},
}
return create_(newState) as any
Expand Down
9 changes: 5 additions & 4 deletions packages/@molt/command/src/builders/command/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import type { Prompter } from '../../lib/Prompter/Prompter.js'
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 { ExclusiveBuilderStateSymbol } from '../exclusive/state.js'
import type { BuilderExclusive, BuilderExclusiveInitial } from '../exclusive/types.js'
import type { BuilderCommandState } from './state.js'
// todo
// eslint-disable-next-line
Expand Down Expand Up @@ -53,11 +54,11 @@ export interface CommandBuilder<$State extends BuilderCommandState.Base = Builde
name: BuilderCommandState.ValidateNameExpression<$State, NameExpression>,
type: $Type,
): CommandBuilder<BuilderCommandState.AddParameter<$State, NameExpression, { type: $Type }>>
parametersExclusive<Label extends string, BuilderExclusive extends SomeBuilderExclusive<$State>>(
parametersExclusive<Label extends string, $BuilderExclusive extends BuilderExclusive<$State>>(
this: void,
label: Label,
ExclusiveBuilderContainer: (builder: BuilderExclusiveInitial<$State, Label>) => BuilderExclusive,
): CommandBuilder<BuilderExclusive['_']['typeState']>
ExclusiveBuilderContainer: (builder: BuilderExclusiveInitial<$State, Label>) => $BuilderExclusive,
): CommandBuilder<$BuilderExclusive[ExclusiveBuilderStateSymbol]['commandBuilderState']>
settings<S extends Settings.Input<$State>>(
this: void,
newSettings: S,
Expand Down
33 changes: 12 additions & 21 deletions packages/@molt/command/src/builders/exclusive/constructor.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Pam } from '../../lib/Pam/index.js'
import type { BuilderCommandState } from '../command/state.js'
import type { BuilderParameterExclusiveState } from './state.js'
import { createState } from './state.js'
import { createState, ExclusiveBuilderStateSymbol } from './state.js'
import type { SomeBuilderExclusiveInitial } from './types.js'

export const create = (label: string, commandState: BuilderCommandState): SomeBuilderExclusiveInitial => {
Expand All @@ -13,45 +13,36 @@ const create_ = (
state: BuilderParameterExclusiveState,
): SomeBuilderExclusiveInitial => {
const builder: SomeBuilderExclusiveInitial = {
[ExclusiveBuilderStateSymbol]: state,
parameter: (nameExpression: string, typeOrConfiguration) => {
const configuration = `type` in typeOrConfiguration ? typeOrConfiguration : { type: typeOrConfiguration } // prettier-ignore
const newState = {
...state,
input: {
...state.input,
parameters: [
...state.input.parameters,
{
nameExpression,
type: commandState.typeMapper(configuration.type),
},
],
},
parameters: [
...state.parameters,
{
nameExpression,
type: commandState.typeMapper(configuration.type),
},
],
}
return create_(commandState, newState)
},

optional: () => {
const newState = {
...state,
input: {
...state.input,
optionality: { _tag: `optional` as const },
},
optionality: { _tag: `optional` as const },
}
return create_(commandState, newState)
},
default: (tag: string, value: Pam.Value) => {
const newState = {
...state,
input: {
...state.input,
optionality: { _tag: `default` as const, tag, value },
},
optionality: { _tag: `default` as const, tag, value },
}
return create_(commandState, newState)
},
_: state,
// _: state,
}

return builder
Expand Down
28 changes: 10 additions & 18 deletions packages/@molt/command/src/builders/exclusive/state.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,19 @@
import type { ParameterExclusiveInput } from '../../Parameter/exclusive.js'
import type { BuilderCommandState } from '../command/state.js'

export const ExclusiveBuilderStateSymbol = Symbol(`ExclusiveBuilderState`)
export type ExclusiveBuilderStateSymbol = typeof ExclusiveBuilderStateSymbol

export type BuilderParameterExclusiveState<
$State extends BuilderCommandState.Base = BuilderCommandState.Base,
> = {
/**
* Used for build time. Type inference functionality.
*/
typeState: $State
/**
* Used for runtime.
*/
input: ParameterExclusiveInput<$State>
}
$State extends BuilderCommandState.Base = BuilderCommandState.BaseEmpty,
> = ParameterExclusiveInput<$State> & { commandBuilderState: $State }

export const createState = (label: string): BuilderParameterExclusiveState => {
return {
typeState: undefined as any, // eslint-disable-line
input: {
label,
_tag: `Exclusive`,
optionality: { _tag: `required` },
parameters: [],
} satisfies ParameterExclusiveInput,
label,
_tag: `Exclusive`,
optionality: { _tag: `required` },
parameters: [],
commandBuilderState: undefined as any, // eslint-disable-line
}
}
16 changes: 8 additions & 8 deletions packages/@molt/command/src/builders/exclusive/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Type } from '../../Type/index.js'
import type { BuilderCommandState } from '../command/state.js'
import type { BuilderParameterExclusiveState } from './state.js'
import type { BuilderParameterExclusiveState, ExclusiveBuilderStateSymbol } from './state.js'

export interface ExclusiveParameterConfiguration<$State extends BuilderCommandState.Base> {
type: $State['Type']
Expand All @@ -26,7 +26,7 @@ interface Parameter<$State extends BuilderCommandState.Base, Label extends strin
}

export interface BuilderExclusiveInitial<$State extends BuilderCommandState.Base, Label extends string> {
_: BuilderParameterExclusiveState<$State>
[ExclusiveBuilderStateSymbol]: BuilderParameterExclusiveState<$State>
parameter: Parameter<$State, Label>
optional: () => BuilderExclusiveAfterOptional<BuilderCommandState.SetExclusiveOptional<$State, Label, true>>
default: <Tag extends keyof $State['ParametersExclusive'][Label]['Parameters']>(
Expand All @@ -36,11 +36,11 @@ export interface BuilderExclusiveInitial<$State extends BuilderCommandState.Base
}

export type BuilderExclusiveAfterOptional<$State extends BuilderCommandState.Base> = {
_: BuilderParameterExclusiveState<$State>
[ExclusiveBuilderStateSymbol]: BuilderParameterExclusiveState<$State>
}

export type BuilderExclusiveAfterDefault<$State extends BuilderCommandState.Base> = {
_: BuilderParameterExclusiveState<$State>
[ExclusiveBuilderStateSymbol]: BuilderParameterExclusiveState<$State>
}

export interface SomeParameter<$State extends BuilderCommandState.Base> {
Expand All @@ -51,15 +51,15 @@ export interface SomeParameter<$State extends BuilderCommandState.Base> {
export type SomeBuilderExclusiveInitial<
$State extends BuilderCommandState.Base = BuilderCommandState.BaseEmpty,
> = {
_: any // eslint-disable-line
[ExclusiveBuilderStateSymbol]: BuilderParameterExclusiveState<$State>
parameter: SomeParameter<$State>
optional: any // eslint-disable-line
default: (tag: any, value: any) => any // eslint-disable-line
}

export type SomeBuilderMutuallyExclusiveAfterOptional<$State extends BuilderCommandState.Base> =
export type BuilderMutuallyExclusiveAfterOptional<$State extends BuilderCommandState.Base> =
BuilderExclusiveAfterOptional<$State>

export type SomeBuilderExclusive<$State extends BuilderCommandState.Base> =
export type BuilderExclusive<$State extends BuilderCommandState.Base> =
| SomeBuilderExclusiveInitial<$State>
| SomeBuilderMutuallyExclusiveAfterOptional<$State>
| BuilderMutuallyExclusiveAfterOptional<$State>

0 comments on commit 2832cb6

Please sign in to comment.