-
|
I am trying to differentiate options passed explicitly vs option pass with > optique
> optique [options]
> optique <command>
> optique <command> [options]Here is my setup // Values
const help = option("-h", "--help")
const version = option("-v", "--version")
const cwd = option("-c", "--cwd", path())
// Options called from the root
// > optique --help
// > optique --version"
const rootOptions = object({
loc: constant("root"),
version: optional(version),
help: optional(help),
})
// Global options merged with all commands
const globalOptions = object("Global options", {
help: optional(help),
cwd: optional(cwd),
})
// Command options
const devOptions = object({
loc: constant("dev"),
key: optional(key),
env: optional(env),
})
// ...
// Commands
const devCmd = merge(devOptions, globalOptions)
const buildCmd = merge(buildOptions, globalOptions)
// ...
const commands = or(devCmd, buildCmd, ...<other commands>)
// Root parser
export const parser = or(rootOptions, commands)Now here are the use cases // optique --help
// I test for help: true to print the global hep
{
success: true,
value: { loc: 'root', version: undefined, help: true }
}
// optique dev --help
// I test for loc: dev and hep: true to print the dev help
{
success: true,
value: {
loc: 'dev',
key: undefined,
env: undefined,
help: true,
cwd: undefined
}
}
// optique dev
// Here I can test all options to be undefined to conclude that no options have been passed to the dev command
// Then chose that no option passed to the command is equivalent to --help and print the dev help
{
success: true,
value: {
loc: 'dev',
key: undefined,
env: undefined,
help: undefined,
cwd: undefined
}
}The problem is when I introduce export const cwd = withDefault(option("-c", "--cwd", path()), process.cwd())// optique dev
{
success: true,
value: {
loc: 'dev',
key: undefined
env: undefined
help: undefined,
cwd: '/path/to/current/working/directory'
}
}
But currently the response is the same |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 9 replies
-
|
Hi! You can use The difference
Exampleimport { object } from "@optique/core/constructs";
import { optional } from "@optique/core/modifiers";
import { parse } from "@optique/core/parser";
import { option } from "@optique/core/primitives";
import { string } from "@optique/core/valueparser";
const parser = object({
cwd: optional(option("--cwd", string()))
});
const result = parse(parser, args);
if (result.success) {
if (result.value.cwd === undefined) {
// No options provided → show help
console.log("Please provide --cwd option");
showHelp();
} else {
// User explicitly provided a value → use it
runCommand(result.value.cwd);
}
}The See the documentation for more details: |
Beta Was this translation helpful? Give feedback.
-
|
@eakl @rj-elias The import { longestMatch, object } from "@optique/core/constructs";
import { nonEmpty, optional, withDefault } from "@optique/core/modifiers";
import { constant, option } from "@optique/core/primitives";
import { string } from "@optique/core/valueparser";
// This parser requires at least one token to be consumed
const activeParser = nonEmpty(object({
mode: constant("active" as const),
cwd: withDefault(
option("--cwd", string()),
"./",
),
key: optional(option("--key", string())),
}));
// Falls back to help mode when no options are provided
const helpParser = object({
mode: constant("help" as const),
});
const parser = longestMatch(activeParser, helpParser);
// cli → helpParser wins (activeParser fails due to nonEmpty)
// cli --key foo → activeParser wins (consumes tokens)
// cli --cwd . → activeParser wins (consumes tokens)Without See #79 and #80 for more details on the implementation. This will be available in version 0.10.0. If you'd like to try it out now, you can use the pre-release version 0.10.0-dev.319. |
Beta Was this translation helpful? Give feedback.
-
|
The parser doesn't seem to work inside a command const parser = command("dev", longestMatch(activeParser, helpParser))
// => cli dev
// {
// success: false,
// error: [
// {
// type: 'text',
// text: 'No matching option, command, or argument found.'
// }
// ]
// } |
Beta Was this translation helpful? Give feedback.
-
|
Thanks dahlia, it works! Though I have an interesting case that doesn't work and I don't think this is an issue but how the parser works. My goal
This is my structure The root parser export const emptyOptions = object({
help: constant(true),
})
export const rootOptions = object({
loc: constant("root"),
version: optional(version),
help: optional(help),
})
export const rootParser = longestMatch(
nonEmpty(rootOptions),
merge(object({ loc: constant("root") }), emptyOptions)
)
// cli => { success: true, value: { loc: 'root', help: true } }
// cli -h => { success: true, value: { loc: 'root', version: undefined, help: true } }The command parsers const globalOptions = object({
help: optional(help),
cwd: withDefault(optional(cwd), process.cwd()),
})
const devOptions = object({
loc: constant("dev"),
key: optional(option("--key", string())),
env: optional(option("--key", string())),
})
const devOptionsFull = merge(devOptions, globalOptions)
const devCmd = command(
"dev",
longestMatch(nonEmpty(devOptionsFull), merge(object({ loc: constant("dev") }), emptyOptions))
)
// cli dev => { success: true, value: { loc: 'dev', help: true } }
// cli dev --key hello --cwd ./ => { success: true, value: { loc: 'dev', key: 'hello', help: undefined, cwd: './' } }The CLI const cmdParser = or(devCmd, buildCmd)
const parser = or(rootParser, cmdParser) // THIS BREAKS
// cli => { success: false, error: [ { type: 'text', text: 'No matching command found.' } ] }
// cli -h => { success: true, value: { loc: 'root', version: undefined, help: true } }
// cli dev => { success: true, value: { loc: 'dev', help: true } }
// cli dev --key hello --cwd ./ => { success: true, value: { loc: 'dev', key: 'hello', help: undefined, cwd: './' } }As you can see, The docs states
Shouldn't |
Beta Was this translation helpful? Give feedback.
@eakl @rj-elias The
nonEmpty()modifier has been implemented and can solve your use case. Here's how you can combine it withlongestMatch()andwithDefault():