-
Notifications
You must be signed in to change notification settings - Fork 10
add cli-to-js/plugin — automatic editor types via TS language-service #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
b5b652c
8d9e980
7c06775
ae5cb0d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| import type { server } from "typescript"; | ||
| declare const pluginInit: server.PluginModuleFactory; | ||
| export = pluginInit; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| module.exports = require("../dist/plugin/index.cjs"); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| { | ||
| "type": "commonjs", | ||
| "main": "./index.js", | ||
| "types": "./index.d.ts" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| import type { CliSchema, ParsedFlag } from "../parse-help-text.js"; | ||
| import { kebabToCamel } from "../utils/kebab-to-camel.js"; | ||
|
|
||
| export interface EmitInput { | ||
| binaryName: string; | ||
| schema: CliSchema | null; | ||
| error: string | null; | ||
| } | ||
|
|
||
| const escapeStringLiteral = (value: string): string => `"${value.replace(/["\\]/g, "\\$&")}"`; | ||
|
|
||
| const propertyKey = (name: string): string => { | ||
| if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name)) return name; | ||
| return escapeStringLiteral(name); | ||
| }; | ||
|
Comment on lines
+10
to
+15
|
||
|
|
||
| const flagTypeString = (flag: ParsedFlag): string => { | ||
| if (!flag.takesValue) return "boolean"; | ||
| if (flag.choices && flag.choices.length > 0) { | ||
| return flag.choices.map(escapeStringLiteral).join(" | "); | ||
| } | ||
| return "string"; | ||
| }; | ||
|
|
||
| const emitOptionsInline = (flags: ParsedFlag[]): string => { | ||
| if (flags.length === 0) return "Record<string, unknown>"; | ||
| const properties = flags.map((flag) => { | ||
| const propertyName = kebabToCamel(flag.longName); | ||
| const optionalMarker = flag.isRequired ? "" : "?"; | ||
| return `${propertyKey(propertyName)}${optionalMarker}: ${flagTypeString(flag)}`; | ||
| }); | ||
| return `{ ${properties.join("; ")} }`; | ||
| }; | ||
|
|
||
| const emitSubcommandMap = (schema: CliSchema): string => { | ||
| if (schema.command.subcommands.length === 0) return "{}"; | ||
| const entries = schema.command.subcommands.map((subcommand) => { | ||
| const optionsType = emitOptionsInline(subcommand.flags ?? []); | ||
| return `${propertyKey(subcommand.name)}: ${optionsType}`; | ||
| }); | ||
| return `{ ${entries.join("; ")} }`; | ||
| }; | ||
|
|
||
| export const emitAugmentation = (inputs: EmitInput[]): string => { | ||
| const preamble = [ | ||
| "// Generated by cli-to-js/plugin — do not edit.", | ||
| "// Refreshes automatically when the editor rescans source files.", | ||
| ]; | ||
|
|
||
| const readyInputs = inputs.filter((input) => input.schema !== null); | ||
| if (readyInputs.length === 0) { | ||
| return `${preamble.join("\n")}\nexport {};\n`; | ||
| } | ||
|
|
||
| const mapEntries = readyInputs | ||
| .map((input) => { | ||
| const shape = emitSubcommandMap(input.schema as CliSchema); | ||
| return ` ${propertyKey(input.binaryName)}: ${shape};`; | ||
| }) | ||
| .join("\n"); | ||
|
|
||
| return `${preamble.join("\n")} | ||
| declare module "cli-to-js" { | ||
| interface KnownCliOptions { | ||
| ${mapEntries} | ||
| } | ||
| } | ||
| export {}; | ||
| `; | ||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The README claims the plugin “rejects unknown keys error”, but the public types currently allow arbitrary option keys via an index signature (
[key: string]: unknown) inSubcommandFn/SpawnFn, so unknown properties won’t be a type error (you’ll still get autocomplete for known flags). Either adjust the wording here to avoid promising unknown-key rejection, or tighten the option types to remove the permissive index signature when usingKnownCliOptions.