145 std::vector<Token> tokens = Tokenize(usage);
148 if (index < tokens.size() && tokens[index].kind == TokenKind::kWord &&
149 tokens[index].text ==
"z3ed") {
152 if (index < tokens.size() && IsValueWord(tokens[index]) &&
153 tokens[index].text[0] !=
'<') {
157 std::vector<UsageParameter> parameters;
158 std::vector<bool> group_is_optional;
159 bool after_bar =
false;
164 std::none_of(group_is_optional.begin(), group_is_optional.end(),
165 [](
bool optional) { return optional; });
167 const bool duplicate = std::any_of(
168 parameters.begin(), parameters.end(), [&](
const UsageParameter& p) {
169 return p.name == parameter.name &&
170 p.positional == parameter.positional;
173 parameters.push_back(std::move(parameter));
177 for (; index < tokens.size(); ++index) {
178 const Token& token = tokens[index];
179 switch (token.kind) {
180 case TokenKind::kOpenOptional:
181 case TokenKind::kOpenGroup:
182 group_is_optional.push_back(token.kind == TokenKind::kOpenOptional);
184 case TokenKind::kClose:
185 if (!group_is_optional.empty()) {
186 group_is_optional.pop_back();
189 case TokenKind::kBar:
190 if (!parameters.empty()) {
191 parameters.back().required =
false;
195 case TokenKind::kWord: {
196 absl::string_view word = token.text;
197 if (IsFlagWord(word)) {
198 if (!absl::ConsumePrefix(&word,
"--")) {
199 absl::ConsumePrefix(&word,
"-");
202 const size_t equals = word.find(
'=');
203 if (
equals != absl::string_view::npos) {
206 word = word.substr(0,
equals);
207 }
else if (index + 1 < tokens.size() &&
208 IsValueWord(tokens[index + 1])) {
210 parameter.
value_hint = NormalizeHint(tokens[++index].text);
212 if (!IsValidName(word)) {
215 parameter.
name = std::string(word);
217 add(std::move(parameter));
218 }
else if (word.front() ==
'<') {
220 parameter.
name = PositionalName(word);
223 if (IsValidName(parameter.
name)) {
224 add(std::move(parameter));
235 const std::vector<UsageParameter>& parameters) {
236 nlohmann::ordered_json properties = nlohmann::ordered_json::object();
237 nlohmann::ordered_json required = nlohmann::ordered_json::array();
239 if (parameter.positional) {
242 nlohmann::ordered_json property;
243 property[
"type"] = parameter.takes_value ?
"string" :
"boolean";
244 if (!parameter.choices.empty()) {
245 property[
"enum"] = parameter.choices;
246 }
else if (!parameter.value_hint.empty()) {
247 property[
"description"] = parameter.value_hint;
249 properties[parameter.name] = std::move(property);
250 if (parameter.required) {
251 required.push_back(parameter.name);
255 nlohmann::ordered_json schema;
256 schema[
"type"] =
"object";
257 schema[
"properties"] = std::move(properties);
258 if (!required.empty()) {
259 schema[
"required"] = std::move(required);
bool equals(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, BinaryPredicate p)