Skip to content

CommandLine

Canonical source: protos/lib/cli/CommandLine.protos at locked revision e99b712ecf658a527b1fe82c8beba2c1286d8dc9.

// THE LICENSED WORK IS PROVIDED UNDER THE TERMS OF THE ADAPTIVE PUBLIC LICENSE
// ("LICENSE") AS FIRST COMPLETED BY: Guillermo Adrián Molina. ANY USE, PUBLIC
// DISPLAY, PUBLIC PERFORMANCE, REPRODUCTION OR DISTRIBUTION OF, OR PREPARATION OF
// DERIVATIVE WORKS BASED ON, THE LICENSED WORK CONSTITUTES RECIPIENT'S ACCEPTANCE
// OF THIS LICENSE AND ITS TERMS, WHETHER OR NOT SUCH RECIPIENT READS THE TERMS OF
// THE LICENSE. "LICENSED WORK" AND "RECIPIENT" ARE DEFINED IN THE LICENSE. A COPY
// OF THE LICENSE IS LOCATED IN THE TEXT FILE ENTITLED "LICENSE.TXT" ACCOMPANYING
// THE CONTENTS OF THIS FILE. IF A COPY OF THE LICENSE DOES NOT ACCOMPANY THIS
// FILE, A COPY OF THE LICENSE MAY ALSO BE OBTAINED AT THE FOLLOWING WEB SITE:
// https://github.com/guillermomolina/protos
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
// the specific language governing rights and limitations under the License.
//! Canonical inert command-line specification records.
/// Canonicalizes one option descriptor into a fresh frozen OptionSpec record.
option: (descriptor) => {
required: (name) => {
descriptor.hasSlot(name).ifFalse(() => {
fail()
})
descriptor.slotValue(name)
}
validateString: (value) => {
String.recognizes(value).ifFalse(() => {
fail()
})
value
}
validateNonEmptyString: (value) => {
validateString(value)
(value == "").ifTrue(() => {
fail()
})
value
}
validateOptionalString: (value) => {
(value === null).ifFalse(() => {
validateString(value)
})
value
}
isAlpha: (octet) => {
((octet >= 65) && (octet <= 90)) ||
((octet >= 97) && (octet <= 122))
}
isDigit: (octet) => {
(octet >= 48) && (octet <= 57)
}
validateLongName: (value) => {
validateString(value)
source: Encoding.UTF8.encode(value)
(source.size() == 0).ifTrue(() => {
fail()
})
isAlpha(source[0]).ifFalse(() => {
fail()
})
index: 1
(() => index < source.size()).whileTrue() {
octet: source[index]
allowed: isAlpha(octet) || isDigit(octet) || (octet == 45)
allowed.ifFalse(() => {
fail()
})
index = index + 1
}
value
}
validateShortName: (value) => {
validateString(value)
source: Encoding.UTF8.encode(value)
(source.size() == 1).ifFalse(() => {
fail()
})
(isAlpha(source[0]) || isDigit(source[0])).ifFalse(() => {
fail()
})
value
}
validateInteger: (value) => {
Integer.recognizes(value).ifFalse(() => {
fail()
})
value
}
keyValue: validateNonEmptyString(required("key"))
longValue: required("long")
shortValue: required("short")
minValuesValue: validateInteger(required("minValues"))
maxValuesValue: validateInteger(required("maxValues"))
minOccurrencesValue: validateInteger(required("minOccurrences"))
maxOccurrencesValue: required("maxOccurrences")
valueNameValue: validateOptionalString(required("valueName"))
helpValue: validateOptionalString(required("help"))
(longValue === null).ifFalse(() => {
validateLongName(longValue)
})
(shortValue === null).ifFalse(() => {
validateShortName(shortValue)
})
((longValue === null) && (shortValue === null)).ifTrue(() => {
fail()
})
validValueCardinality: ((minValuesValue == 0) && (maxValuesValue == 0)) ||
((minValuesValue == 1) && (maxValuesValue == 1))
validValueCardinality.ifFalse(() => {
fail()
})
(maxValuesValue == 0).ifTrue(() => {
(valueNameValue === null).ifFalse(() => {
fail()
})
})
(maxValuesValue == 1).ifTrue(() => {
(valueNameValue === null).ifTrue(() => {
fail()
})
validateNonEmptyString(valueNameValue)
})
((minOccurrencesValue == 0) || (minOccurrencesValue == 1)).ifFalse(() => {
fail()
})
(maxOccurrencesValue === null).ifFalse(() => {
validateInteger(maxOccurrencesValue)
(maxOccurrencesValue == 1).ifFalse(() => {
fail()
})
})
canonical: {
kind: "option"
key: keyValue
long: longValue
short: shortValue
minValues: minValuesValue
maxValues: maxValuesValue
minOccurrences: minOccurrencesValue
maxOccurrences: maxOccurrencesValue
valueName: valueNameValue
help: helpValue
}
canonical.freeze()
}
/// Canonicalizes one positional descriptor into a fresh frozen PositionalSpec record.
positional: (descriptor) => {
required: (name) => {
descriptor.hasSlot(name).ifFalse(() => {
fail()
})
descriptor.slotValue(name)
}
validateString: (value) => {
String.recognizes(value).ifFalse(() => {
fail()
})
value
}
validateNonEmptyString: (value) => {
validateString(value)
(value == "").ifTrue(() => {
fail()
})
value
}
validateOptionalString: (value) => {
(value === null).ifFalse(() => {
validateString(value)
})
value
}
validateInteger: (value) => {
Integer.recognizes(value).ifFalse(() => {
fail()
})
value
}
keyValue: validateNonEmptyString(required("key"))
minOccurrencesValue: validateInteger(required("minOccurrences"))
maxOccurrencesValue: required("maxOccurrences")
valueNameValue: validateNonEmptyString(required("valueName"))
helpValue: validateOptionalString(required("help"))
((minOccurrencesValue == 0) || (minOccurrencesValue == 1)).ifFalse(() => {
fail()
})
(maxOccurrencesValue === null).ifFalse(() => {
validateInteger(maxOccurrencesValue)
(maxOccurrencesValue == 1).ifFalse(() => {
fail()
})
})
canonical: {
kind: "positional"
key: keyValue
minOccurrences: minOccurrencesValue
maxOccurrences: maxOccurrencesValue
valueName: valueNameValue
help: helpValue
}
canonical.freeze()
}
/// Canonicalizes one command descriptor and its complete nested specification graph.
command: (descriptor) => {
validateString: (value) => {
String.recognizes(value).ifFalse(() => {
fail()
})
value
}
validateOptionalString: (value) => {
(value === null).ifFalse(() => {
validateString(value)
})
value
}
isAlpha: (octet) => {
((octet >= 65) && (octet <= 90)) ||
((octet >= 97) && (octet <= 122))
}
isDigit: (octet) => {
(octet >= 48) && (octet <= 57)
}
validateCommandName: (value) => {
validateString(value)
source: Encoding.UTF8.encode(value)
(source.size() == 0).ifTrue(() => {
fail()
})
isAlpha(source[0]).ifFalse(() => {
fail()
})
index: 1
(() => index < source.size()).whileTrue() {
octet: source[index]
allowed: isAlpha(octet) || isDigit(octet) || (octet == 45)
allowed.ifFalse(() => {
fail()
})
index = index + 1
}
value
}
validateArray: (value) => {
Array.recognizes(value).ifFalse(() => {
fail()
})
value
}
// Active-path identities only: a descriptor leaves `visiting` when its own
// canonicalization completes, so completed shared descriptors are reused.
visiting: IdentityMap()
// Validates one command descriptor and canonicalizes its options and
// positionals, returning an explicit heap frame suspended before its children.
enterCommand: (candidate, parentFrame) => {
visiting.containsKey(candidate).ifTrue(() => {
fail()
})
visiting[candidate] = true
required: (name) => {
candidate.hasSlot(name).ifFalse(() => {
fail()
})
candidate.slotValue(name)
}
nameValue: validateCommandName(required("name"))
helpValue: validateOptionalString(required("help"))
optionDescriptors: validateArray(required("options"))
positionalDescriptors: validateArray(required("positionals"))
subcommandDescriptors: validateArray(required("subcommands"))
canonicalOptions: Array(...optionDescriptors)
optionKeys: Map()
longNames: Map()
shortNames: Map()
optionIndex: 0
optionDescriptors.each((entry) => {
spec: option(entry)
optionKeys.containsKey(spec.key).ifTrue(() => {
fail()
})
optionKeys[spec.key] = true
(spec.long === null).ifFalse(() => {
longNames.containsKey(spec.long).ifTrue(() => {
fail()
})
longNames[spec.long] = true
})
(spec.short === null).ifFalse(() => {
shortNames.containsKey(spec.short).ifTrue(() => {
fail()
})
shortNames[spec.short] = true
})
canonicalOptions[optionIndex] = spec
optionIndex = optionIndex + 1
})
canonicalOptions.freeze()
canonicalPositionals: Array(...positionalDescriptors)
positionalKeys: Map()
positionalIndex: 0
positionalDescriptors.each((entry) => {
spec: positional(entry)
positionalKeys.containsKey(spec.key).ifTrue(() => {
fail()
})
positionalKeys[spec.key] = true
(spec.maxOccurrences === null).ifTrue(() => {
((positionalIndex + 1) == positionalDescriptors.size()).ifFalse(() => {
fail()
})
})
canonicalPositionals[positionalIndex] = spec
positionalIndex = positionalIndex + 1
})
canonicalPositionals.freeze()
suspended: {
parent: parentFrame
candidate: candidate
name: nameValue
help: helpValue
options: canonicalOptions
positionals: canonicalPositionals
subcommandDescriptors: subcommandDescriptors
subcommands: Array(...subcommandDescriptors)
subcommandNames: Map()
childIndex: 0
}
suspended
}
// Completes a frame whose children are all canonicalized.
exitCommand: (frame) => {
frame.subcommands.freeze()
visiting.remove(frame.candidate)
canonical: {
kind: "command"
name: frame.name
help: frame.help
options: frame.options
positionals: frame.positionals
subcommands: frame.subcommands
}
canonical.freeze()
}
// Depth-first traversal over explicit linked frames keeps execution-stack
// depth independent of command depth. Each child is canonicalized completely
// before its parent's duplicate-name check, registration and storage.
frame: enterCommand(descriptor, null)
result: null
(() => result === null).whileTrue() {
(frame.childIndex < frame.subcommandDescriptors.size()).ifTrueIfFalse(
() => {
frame = enterCommand(frame.subcommandDescriptors[frame.childIndex], frame)
},
() => {
spec: exitCommand(frame)
parentFrame: frame.parent
(parentFrame === null).ifTrueIfFalse(
() => {
result = spec
},
() => {
parentFrame.subcommandNames.containsKey(spec.name).ifTrue(() => {
fail()
})
parentFrame.subcommandNames[spec.name] = true
parentFrame.subcommands[parentFrame.childIndex] = spec
parentFrame.childIndex = parentFrame.childIndex + 1
frame = parentFrame
}
)
}
)
}
result
}
/// Parses a canonical CommandSpec tree into a fresh frozen lossless result.
///
/// Traversal follows D115 Candidate C-prime: the earliest feasible exact-child
/// boundary, parent-minimum reservation, current-scope `--` escape and
/// irreversible child scope transfer.
parse: ((arrayBuilderFactory) => {
(specification, suppliedArguments) => {
validateArray: (value) => {
Array.recognizes(value).ifFalse(() => {
fail()
})
value
}
validateString: (value) => {
String.recognizes(value).ifFalse(() => {
fail()
})
value
}
specification.hasSlot("kind").ifFalse(() => {
fail()
})
(specification.slotValue("kind") == "command").ifFalse(() => {
fail()
})
spec: specification
validateArray(suppliedArguments)
suppliedArguments.each((entry) => {
validateString(entry)
})
arguments: Array(...suppliedArguments)
arguments.freeze()
newBuilder: () => {
arrayBuilderFactory()
}
appendBuilt: (builder, value) => {
builder.append(value)
}
finishBuilder: (builder) => {
builder.finish()
}
decodeRange: (source, start, end) => {
buffer: Encoding.UTF8.encode("")
cursor: start
(() => cursor < end).whileTrue() {
buffer.add(source[cursor])
cursor = cursor + 1
}
Encoding.UTF8.decode(buffer)
}
isAsciiLetter: (octet) => {
((octet >= 65) && (octet <= 90)) ||
((octet >= 97) && (octet <= 122))
}
isAsciiDigit: (octet) => {
(octet >= 48) && (octet <= 57)
}
isShortOctet: (octet) => {
isAsciiLetter(octet) || isAsciiDigit(octet)
}
allocatePositionals: (scopeSpec, rawPositionals) => {
requiredPositionals: 0
scopeSpec.positionals.each((positionalSpec) => {
requiredPositionals =
requiredPositionals + positionalSpec.minOccurrences
})
(rawPositionals.size() < requiredPositionals).ifTrue(() => {
fail()
})
positionalBuilder: newBuilder()
rawIndex: 0
laterMinimum: requiredPositionals
scopeSpec.positionals.each((positionalSpec) => {
laterMinimum =
laterMinimum - positionalSpec.minOccurrences
remaining: rawPositionals.size() - rawIndex
consume: 0
(positionalSpec.maxOccurrences === null).ifTrue(() => {
consume = remaining
})
(positionalSpec.maxOccurrences === null).ifFalse(() => {
(positionalSpec.minOccurrences == 1).ifTrue(() => {
consume = 1
})
(positionalSpec.minOccurrences == 0).ifTrue(() => {
(remaining > laterMinimum).ifTrue(() => {
consume = 1
})
})
})
(consume < positionalSpec.minOccurrences).ifTrue(() => {
fail()
})
consumed: 0
(() => consumed < consume).whileTrue() {
raw: rawPositionals[rawIndex]
occurrence: {
kind: "positionalOccurrence"
key: positionalSpec.key
value: raw.value
tokenIndex: raw.tokenIndex
}
occurrence.freeze()
appendBuilt(positionalBuilder, occurrence)
rawIndex = rawIndex + 1
consumed = consumed + 1
}
})
(rawIndex == rawPositionals.size()).ifFalse(() => {
fail()
})
result: finishBuilder(positionalBuilder)
result.freeze()
}
parseScope: null
parseScope = (scopeSpec, startIndex, commandTokenIndex) => {
scopeSpec.hasSlot("kind").ifFalse(() => {
fail()
})
(scopeSpec.slotValue("kind") == "command").ifFalse(() => {
fail()
})
validateArray(scopeSpec.options)
validateArray(scopeSpec.positionals)
validateArray(scopeSpec.subcommands)
longOptions: Map()
shortOptions: Map()
occurrenceCounts: Map()
scopeSpec.options.each((optionSpec) => {
occurrenceCounts[optionSpec.key] = 0
(optionSpec.long === null).ifFalse(() => {
longOptions[optionSpec.long] = optionSpec
})
(optionSpec.short === null).ifFalse(() => {
shortOptions[optionSpec.short] = optionSpec
})
})
childSpecs: Map()
scopeSpec.subcommands.each((childSpec) => {
childSpecs[childSpec.name] = childSpec
})
requiredPositionals: 0
boundedMaximumPositionals: 0
unboundedPositionals: false
scopeSpec.positionals.each((positionalSpec) => {
requiredPositionals =
requiredPositionals + positionalSpec.minOccurrences
(positionalSpec.maxOccurrences === null).ifTrue(() => {
unboundedPositionals = true
})
(positionalSpec.maxOccurrences === null).ifFalse(() => {
boundedMaximumPositionals =
boundedMaximumPositionals +
positionalSpec.maxOccurrences
})
})
optionBuilder: newBuilder()
rawPositionalBuilder: newBuilder()
rawPositionalCount: 0
recordOption: (
optionSpec,
spelling,
tokenIndex,
value,
valueTokenIndex
) => {
count: occurrenceCounts[optionSpec.key]
(optionSpec.maxOccurrences === null).ifFalse(() => {
(count >= optionSpec.maxOccurrences).ifTrue(() => {
fail()
})
})
occurrenceCounts[optionSpec.key] = count + 1
occurrence: {
kind: "optionOccurrence"
key: optionSpec.key
spelling: spelling
tokenIndex: tokenIndex
value: value
valueTokenIndex: valueTokenIndex
}
occurrence.freeze()
appendBuilt(optionBuilder, occurrence)
}
recordRawPositional: (value, tokenIndex) => {
appendBuilt(
rawPositionalBuilder,
{
value: value
tokenIndex: tokenIndex
}
)
rawPositionalCount = rawPositionalCount + 1
}
positionalPrefixFeasible: () => {
feasible: rawPositionalCount >= requiredPositionals
((feasible) && (unboundedPositionals == false)).ifTrue(() => {
(rawPositionalCount > boundedMaximumPositionals).ifTrue(() => {
feasible = false
})
})
feasible
}
scanIndex: startIndex
optionsEnabled: true
endOfOptionsIndex: null
selectedChild: null
selectedChildIndex: null
(() =>
(scanIndex < arguments.size()) &&
(selectedChild === null)
).whileTrue() {
token: arguments[scanIndex]
source: Encoding.UTF8.encode(token)
advance: 1
handled: false
optionsEnabled.ifTrue(() => {
(token == "--").ifTrue(() => {
endOfOptionsIndex = scanIndex
optionsEnabled = false
handled = true
})
handled.ifFalse(() => {
optionLike: false
(source.size() > 0).ifTrue(() => {
(source[0] == 45).ifTrue(() => {
optionLike = true
})
})
optionLike.ifTrue(() => {
(source.size() == 1).ifTrue(() => {
fail()
})
longForm: source[1] == 45
longForm.ifTrue(() => {
equalsIndex: -1
cursor: 2
(() => cursor < source.size()).whileTrue() {
(
(equalsIndex < 0) &&
(source[cursor] == 61)
).ifTrue(() => {
equalsIndex = cursor
})
cursor = cursor + 1
}
nameEnd: source.size()
(equalsIndex >= 0).ifTrue(() => {
nameEnd = equalsIndex
})
longName: decodeRange(source, 2, nameEnd)
longOptions.containsKey(longName).ifFalse(() => {
fail()
})
optionSpec: longOptions[longName]
spelling: "--" + optionSpec.long
(equalsIndex >= 0).ifTrue(() => {
(optionSpec.maxValues == 1).ifFalse(() => {
fail()
})
value: decodeRange(
source,
equalsIndex + 1,
source.size()
)
recordOption(
optionSpec,
spelling,
scanIndex,
value,
scanIndex
)
})
(equalsIndex >= 0).ifFalse(() => {
(optionSpec.maxValues == 1).ifTrue(() => {
(
(scanIndex + 1) >= arguments.size()
).ifTrue(() => {
fail()
})
recordOption(
optionSpec,
spelling,
scanIndex,
arguments[scanIndex + 1],
scanIndex + 1
)
advance = 2
})
(optionSpec.maxValues == 1).ifFalse(() => {
recordOption(
optionSpec,
spelling,
scanIndex,
null,
null
)
})
})
handled = true
})
longForm.ifFalse(() => {
memberCount: source.size() - 1
cursor: 1
(() => cursor < source.size()).whileTrue() {
octet: source[cursor]
isShortOctet(octet).ifFalse(() => {
fail()
})
shortName: decodeRange(
source,
cursor,
cursor + 1
)
shortOptions.containsKey(shortName).ifFalse(() => {
fail()
})
optionSpec: shortOptions[shortName]
spelling: "-" + optionSpec.short
(memberCount > 1).ifTrue(() => {
(optionSpec.maxValues == 0).ifFalse(() => {
fail()
})
recordOption(
optionSpec,
spelling,
scanIndex,
null,
null
)
})
(memberCount == 1).ifTrue(() => {
(optionSpec.maxValues == 1).ifTrue(() => {
(
(scanIndex + 1) >= arguments.size()
).ifTrue(() => {
fail()
})
recordOption(
optionSpec,
spelling,
scanIndex,
arguments[scanIndex + 1],
scanIndex + 1
)
advance = 2
})
(optionSpec.maxValues == 1).ifFalse(() => {
recordOption(
optionSpec,
spelling,
scanIndex,
null,
null
)
})
})
cursor = cursor + 1
}
handled = true
})
})
optionLike.ifFalse(() => {
childSpecs.containsKey(token).ifTrue(() => {
positionalPrefixFeasible().ifTrue(() => {
selectedChild = childSpecs[token]
selectedChildIndex = scanIndex
handled = true
})
})
})
})
})
handled.ifFalse(() => {
recordRawPositional(token, scanIndex)
})
scanIndex = scanIndex + advance
}
scopeSpec.options.each((optionSpec) => {
(
occurrenceCounts[optionSpec.key] <
optionSpec.minOccurrences
).ifTrue(() => {
fail()
})
})
rawPositionals: finishBuilder(rawPositionalBuilder)
positionalOccurrences:
allocatePositionals(scopeSpec, rawPositionals)
optionOccurrences: finishBuilder(optionBuilder)
optionOccurrences.freeze()
childResult: null
(selectedChild === null).ifFalse(() => {
childResult = parseScope(
selectedChild,
scanIndex,
selectedChildIndex
)
})
commandResult: {
kind: "commandResult"
name: scopeSpec.name
tokenIndex: commandTokenIndex
endOfOptionsIndex: endOfOptionsIndex
options: optionOccurrences
positionals: positionalOccurrences
subcommand: childResult
}
commandResult.freeze()
}
commandResult: parseScope(spec, 0, null)
result: {
kind: "parseResult"
arguments: arguments
command: commandResult
}
result.freeze()
}
})(_commandLineArrayBuilderFactory)
// The runtime-provisioned factory is captured privately above; it is not module surface.
context.removeSlot("_commandLineArrayBuilderFactory")
/// Renders canonical pure help for one exact command path.
///
/// D118 Candidate F-prime fixes deterministic unwrapped plain text with explicit
/// path context and no terminal/output authority. D119 Candidate A-prime ensures
/// every value-bearing canonical specification already carries a non-empty
/// presentation valueName.
renderHelp: (rootSpec, commandPath) => {
validateArray: (value) => {
Array.recognizes(value).ifFalse(() => {
fail()
})
value
}
validateString: (value) => {
String.recognizes(value).ifFalse(() => {
fail()
})
value
}
rootSpec.hasSlot("kind").ifFalse(() => {
fail()
})
(rootSpec.slotValue("kind") == "command").ifFalse(() => {
fail()
})
validateArray(commandPath)
selectedSpec: rootSpec
commandPath.each((segment) => {
validateString(segment)
selectedChild: null
selectedSpec.subcommands.each((childSpec) => {
(
(selectedChild === null) &&
(childSpec.name == segment)
).ifTrue(() => {
selectedChild = childSpec
})
})
(selectedChild === null).ifTrue(() => {
fail()
})
selectedSpec = selectedChild
})
output: Encoding.UTF8.encode("")
appendText: (text) => {
source: Encoding.UTF8.encode(text)
index: 0
(() => index < source.size()).whileTrue() {
output.add(source[index])
index = index + 1
}
}
optionUsageTerm: (optionSpec) => {
spelling: ""
(optionSpec.long === null).ifFalse(() => {
spelling = "--" + optionSpec.long
})
(optionSpec.long === null).ifTrue(() => {
spelling = "-" + optionSpec.short
})
(optionSpec.maxValues == 1).ifTrue(() => {
spelling = spelling + " " + optionSpec.valueName
})
spelling
}
positionalTerm: (positionalSpec) => {
rendered: positionalSpec.valueName
(
(positionalSpec.minOccurrences == 0) &&
(positionalSpec.maxOccurrences == 1)
).ifTrue(() => {
rendered = "[" + positionalSpec.valueName + "]"
})
(
(positionalSpec.minOccurrences == 0) &&
(positionalSpec.maxOccurrences === null)
).ifTrue(() => {
rendered = "[" + positionalSpec.valueName + "]..."
})
(
(positionalSpec.minOccurrences == 1) &&
(positionalSpec.maxOccurrences === null)
).ifTrue(() => {
rendered =
positionalSpec.valueName +
" [" + positionalSpec.valueName + "]..."
})
rendered
}
optionEntry: (optionSpec) => {
rendered: ""
(optionSpec.short === null).ifFalse(() => {
rendered = "-" + optionSpec.short
})
(optionSpec.long === null).ifFalse(() => {
(rendered == "").ifFalse(() => {
rendered = rendered + ", "
})
rendered = rendered + "--" + optionSpec.long
})
(optionSpec.maxValues == 1).ifTrue(() => {
rendered = rendered + " " + optionSpec.valueName
})
(
(optionSpec.minOccurrences == 1) &&
(optionSpec.maxOccurrences == 1)
).ifTrue(() => {
rendered = rendered + " (required)"
})
(
(optionSpec.minOccurrences == 0) &&
(optionSpec.maxOccurrences === null)
).ifTrue(() => {
rendered = rendered + " (repeatable)"
})
(
(optionSpec.minOccurrences == 1) &&
(optionSpec.maxOccurrences === null)
).ifTrue(() => {
rendered = rendered + " (required, repeatable)"
})
rendered
}
appendDescription: (helpText) => {
(helpText === null).ifFalse(() => {
appendText("\n ")
appendText(helpText)
})
}
appendText("Usage: ")
appendText(rootSpec.name)
commandPath.each((segment) => {
appendText(" ")
appendText(segment)
})
hasOptionalOptions: false
selectedSpec.options.each((optionSpec) => {
(optionSpec.minOccurrences == 0).ifTrue(() => {
hasOptionalOptions = true
})
(optionSpec.minOccurrences == 1).ifTrue(() => {
term: optionUsageTerm(optionSpec)
appendText(" ")
appendText(term)
(optionSpec.maxOccurrences === null).ifTrue(() => {
appendText(" [")
appendText(term)
appendText("]...")
})
})
})
hasOptionalOptions.ifTrue(() => {
appendText(" [OPTIONS]")
})
selectedSpec.positionals.each((positionalSpec) => {
appendText(" ")
appendText(positionalTerm(positionalSpec))
})
(selectedSpec.subcommands.size() > 0).ifTrue(() => {
appendText(" [COMMAND]")
})
(selectedSpec.help === null).ifFalse(() => {
appendText("\n\n")
appendText(selectedSpec.help)
})
(selectedSpec.positionals.size() > 0).ifTrue(() => {
appendText("\n\nArguments:")
selectedSpec.positionals.each((positionalSpec) => {
appendText("\n ")
appendText(positionalTerm(positionalSpec))
appendDescription(positionalSpec.help)
})
})
(selectedSpec.options.size() > 0).ifTrue(() => {
appendText("\n\nOptions:")
selectedSpec.options.each((optionSpec) => {
appendText("\n ")
appendText(optionEntry(optionSpec))
appendDescription(optionSpec.help)
})
})
(selectedSpec.subcommands.size() > 0).ifTrue(() => {
appendText("\n\nCommands:")
selectedSpec.subcommands.each((childSpec) => {
appendText("\n ")
appendText(childSpec.name)
appendDescription(childSpec.help)
})
})
Encoding.UTF8.decode(output)
}

← cli family · Standard-library source