Skip to content

Commit 49162fd

Browse files
John ButeJohn Bute
authored andcommitted
precised contract between templates and swiftpm + future directions
1 parent 0cde810 commit 49162fd

File tree

1 file changed

+117
-0
lines changed

1 file changed

+117
-0
lines changed

proposals/NNNN-package-manager-templates.md

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,98 @@ Build of product 'ServerTemplate' complete! (0.42s)
372372

373373
For more examples on ways to write a template's executable, refer to the template-example-repository.
374374

375+
### Contract Between Templates and SwiftPM
376+
377+
SwiftPM communicates with templates through a defined contract. This ensures that SwiftPM can discover, prompt for, and pass arguments to template generators in a consistent and automated way.
378+
379+
When a template package is first discovered, SwiftPM invokes its executable using the `experimental-dump-help` flag.
380+
381+
This flag allows the template generator to output all of its command-line interface help information as JSON to standard output. SwiftPM then parses this JSON to learn:
382+
383+
* The subcommands the template provides
384+
* What arguments, options, and flags are supported by the template
385+
* Which inputs are required or optional
386+
* How each argument should be parsed and displayed to the user
387+
388+
This allows for SwiftPM, IDEs and other higher-level tools to utilize the JSON metadata to generate interactive prompts and validate user input when creating projects from templates. The format can also be transmitted over wire protocols and published for broader integration.
389+
390+
suggestion: It's not SwiftPM that can use this metadata, but also higher-level tools too, such as IDE's. The format is sendable over wire protocols and publishable too.
391+
392+
Any argument parser wishing to support SwiftPM templates must implement the `--experimental-dump-help` flag alongside the following schema:
393+
394+
#### Top-Level Structure
395+
396+
|Property |Type |Description |IsRequired |
397+
|--- |--- |--- |--- |
398+
|serializationVersion |`Integer` |The version number of the JSON schema ||
399+
|command |`CommandInfoV0` |Command Information | |
400+
401+
#### CommandInformationV0
402+
403+
|Property |Type |Description |IsRequired |
404+
|--- |--- |--- |--- |
405+
|commandName |`String` |Name used to invoke the command ||
406+
|superCommands |`[String]?` |Array of parent command names in hierarchy | |
407+
|shouldDisplay |`Bool` |Whether the command appears in help ||
408+
|abstract |`String` |Short description of command functionality | |
409+
|discussion |`String?` |Extended description of command functionality | |
410+
|defaultSubcommand |`String?` |Name of default subcommand | |
411+
|subcommands |`[CommandInfoV0]?` |Array of nested subcommands | |
412+
|arguments |`[ArgumentInfoV0?]` |Array of supported arguments/options/flags | |
413+
414+
#### Argument Information (ArgumentInfoV0)
415+
416+
|Property |Type |Description |IsRequired |
417+
|--- |--- |--- |--- |
418+
|kind |`KindV0` |"positional", "option", or "flag ||
419+
|shouldDisplay |`Bool` |Whether argument appears in help ||
420+
|sectionTitle |`String?` |Custom section name for grouping | |
421+
|isOptional |`Bool` |Whether argument can be omitted ||
422+
|isRepeating |`Bool` |Whether argument can be specified multiple times ||
423+
|parsingStrategy |`String` |How the argument is parsed ||
424+
|names |`[NameInfoV0]?` |All names/flags for the argument | |
425+
|preferredName |`NameInfoV0` |Best name for help displays | |
426+
|valueName |`String?` |Name of argument's value in help | |
427+
|defaultValue |`String?` |Default value if none specified | |
428+
|allValues |`[String]?` |List of all valid values (for enums) | |
429+
|allValuesDescriptions |`{String: String}?` |Mapping of values to descriptions | |
430+
|completionKind |`CompletionKindV0?` |Type of shell completion | |
431+
|abstract |`String?` |Short description of argument | |
432+
|discussion |`String?` |Extended description of argument | |
433+
434+
#### Name Information (NameInfoV0)
435+
436+
|Property |Type |Description |IsRequired |
437+
|--- |--- |--- |--- |
438+
|Kind |`KindV0` |"long", which is a multi-character name preceded by two dashes, "short" which is a single character name preceded by a single dash, or "longWithSingleDash" which is a multi-character name preceded by a single dash. ||
439+
|Name |`String` |Single or multi-character name of the argument. ||
440+
441+
#### Parsing Strategy Values
442+
443+
```
444+
- "default" - Expect next element to be a value
445+
- "scanningForValue" - Parse next value element
446+
- "unconditional" - Parse next element regardless of type
447+
- "upToNextOption" - Parse multiple values until next option
448+
- "allRemainingInput" - Parse all remaining elements
449+
- "postTerminator" - Collect elements after --
450+
- "allUnrecognized" - Collect unused inputs
451+
```
452+
453+
454+
Once SwiftPM ingests the JSON representation, it prompts the user for any required inputs, before forming a full command-line invocation from those responses.
455+
456+
```
457+
my-template generate --name AnExample --host *8080*
458+
```
459+
460+
SwiftPM passes this command line
461+
462+
Swift Argument Parser implements all of the above, and is the recommended and supported way for template generators to integrate with SwiftPM.
463+
464+
465+
>Note: Further details regarding the long-term vision for stabilizing the interface between SwiftPM, IDEs, and template generators are discussed in Future Directions
466+
375467
### Workflow of initializing a package based off a template
376468

377469
When a user executes `swift package init` with template options, SwiftPM follows this workflow:
@@ -521,4 +613,29 @@ This is an additive feature. Existing packages will not be affected by this chan
521613
* Transform `--experimental-dump-help` into a stable equivalent flag. Learn more about it here: ([pitch](https://forums.swift.org/t/dropping-the-experimental-from-dump-help/82099)) ([PR](https://github.com/apple/swift-argument-parser/pull/817))
522614
* Support and actively contribute to the [OpenCLI](https://opencli.org/) initiative, prompting a standardize JSON format for broader parser interoperability.
523615

616+
### Stablization and Evolution of Template Interface
617+
618+
A big part of templates is the contract shared between packages containing templates and SwiftPM.
619+
620+
Currently, SwiftPM utilize the `--experimental-dump-help` flag alongside Swift Argument Parser’s `ToolInfoV0` JSON schema to input consumers about the arguments and subcommands required by templates.
621+
622+
The use of an experimental flag and the dependency on Swift Argument Parser’s internal schema are not ideal for long-term stability. However, there are several active directions to address these issues:
623+
624+
625+
* **Stabilization of the tool info interface**: Transform `--experimental-dump-help` into a stable equivalent flag, paired with a stable JSON schema (`ToolInfoV1`) that formally describes an executable’s command tree. Learn more about this work in [[Pitch](https://forums.swift.org/t/dropping-the-experimental-from-dump-help/82099)/[PR](https://github.com/apple/swift-argument-parser/pull/817)].
626+
* **Broader parser interoperability**: Support and contribute to the OpenCLI initiative, which aims to define a standardized JSON representation for command-line tool metadata across ecosystems. To support and contribute the OpenCLI initiative, please visit [OpenCLI](https://opencli.org/).
627+
628+
#### ToolInfo Versions and Future evolution
629+
630+
At present, there are two versions of the ToolInfo schema in play:
631+
632+
* `ToolInfoV0`, the experimental version used by —experimental-dump-help
633+
* `ToolInfoV1`, the stable successor used by the new —help-dump-tool-info-v1 flag
634+
635+
Functionally, these two versions are identical excpet for the declared serailization version, ensuring backward compatibility and providing the base for a stable interface. This alignment allows existing template generators to continue operating without modification, while offering a clear migration path to the stable `v1` API.
636+
637+
To support multiple tool info versions over time, SwiftPM will implement a negotiation mechanism when invoking templates, relying on special flags or options that indicate the desired ToolInfo version.
638+
639+
For example, SwiftPM may first attempt `--help-dump-tool-info-v2`. If the executable does not recognize the flag or fails to respond with a valid JSON schema, SwiftPM will gracefully fall back to an earlier version such as `--help-dump-tool-info-v1`, then `--experimental-dump-help`. SwiftPM will iterate through its list of known versions, starting from the newest until it receives a valid JSON schema. This ensures forward compatibility with future schema revisions and allows template executables to adopt new versions at their own pace while maintaining interoperability with older SwiftPM releases.
524640

641+
Looking forward, there is also the possibility of integrating an OpenCLI-compliant version. This would extend beyond Swift-specific tooling, allowing parsers to describe a language-agnostic CLI interface. The goal is to reduce dependency on Swift Argument internals and make template discovery interoperable across different argument parsers.

0 commit comments

Comments
 (0)