@utilix-tech/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +199 -0
  3. package/dist/api-8aZtWhSj.d.cts +308 -0
  4. package/dist/api-8aZtWhSj.d.ts +308 -0
  5. package/dist/chunk-2CJSLYWI.js +520 -0
  6. package/dist/chunk-3BAHSW4C.js +1385 -0
  7. package/dist/chunk-6YPV2AB5.js +1246 -0
  8. package/dist/chunk-BPVAB4P2.js +1126 -0
  9. package/dist/chunk-FL53T24A.js +257 -0
  10. package/dist/chunk-L6KCTHUW.js +1086 -0
  11. package/dist/chunk-MLKGABMK.js +7 -0
  12. package/dist/chunk-ROTPLW7T.js +265 -0
  13. package/dist/chunk-TSAGO3XP.js +1253 -0
  14. package/dist/chunk-UC656APA.js +1080 -0
  15. package/dist/chunk-W4UBLYFU.js +1219 -0
  16. package/dist/chunk-XST6X3HT.js +896 -0
  17. package/dist/chunk-XXYZLLHI.js +2227 -0
  18. package/dist/chunk-ZKL2VX2G.js +2215 -0
  19. package/dist/chunk-ZPQZEIXP.js +685 -0
  20. package/dist/code-QNrdLIR3.d.cts +327 -0
  21. package/dist/code-QNrdLIR3.d.ts +327 -0
  22. package/dist/color-tPwZCr9H.d.cts +229 -0
  23. package/dist/color-tPwZCr9H.d.ts +229 -0
  24. package/dist/css-Cf7AMGM-.d.cts +318 -0
  25. package/dist/css-Cf7AMGM-.d.ts +318 -0
  26. package/dist/data-rMjWNiOJ.d.cts +215 -0
  27. package/dist/data-rMjWNiOJ.d.ts +215 -0
  28. package/dist/encoding-7gmq-vkV.d.cts +108 -0
  29. package/dist/encoding-7gmq-vkV.d.ts +108 -0
  30. package/dist/generators-BGtRGpJZ.d.cts +118 -0
  31. package/dist/generators-BGtRGpJZ.d.ts +118 -0
  32. package/dist/hashing-CnetQFD_.d.cts +76 -0
  33. package/dist/hashing-CnetQFD_.d.ts +76 -0
  34. package/dist/index.cjs +15466 -0
  35. package/dist/index.d.cts +18 -0
  36. package/dist/index.d.ts +18 -0
  37. package/dist/index.js +20 -0
  38. package/dist/json-BjSoIS1h.d.cts +198 -0
  39. package/dist/json-BjSoIS1h.d.ts +198 -0
  40. package/dist/misc-DcVBManm.d.cts +201 -0
  41. package/dist/misc-DcVBManm.d.ts +201 -0
  42. package/dist/network-CNtmrDeN.d.cts +170 -0
  43. package/dist/network-CNtmrDeN.d.ts +170 -0
  44. package/dist/text-DqAjPtQ0.d.cts +319 -0
  45. package/dist/text-DqAjPtQ0.d.ts +319 -0
  46. package/dist/time-DbT8fjaF.d.cts +145 -0
  47. package/dist/time-DbT8fjaF.d.ts +145 -0
  48. package/dist/tools/api.cjs +1216 -0
  49. package/dist/tools/api.d.cts +1 -0
  50. package/dist/tools/api.d.ts +1 -0
  51. package/dist/tools/api.js +2 -0
  52. package/dist/tools/code.cjs +2212 -0
  53. package/dist/tools/code.d.cts +1 -0
  54. package/dist/tools/code.d.ts +1 -0
  55. package/dist/tools/code.js +2 -0
  56. package/dist/tools/color.cjs +1122 -0
  57. package/dist/tools/color.d.cts +1 -0
  58. package/dist/tools/color.d.ts +1 -0
  59. package/dist/tools/color.js +2 -0
  60. package/dist/tools/css.cjs +1242 -0
  61. package/dist/tools/css.d.cts +1 -0
  62. package/dist/tools/css.d.ts +1 -0
  63. package/dist/tools/css.js +2 -0
  64. package/dist/tools/data.cjs +1097 -0
  65. package/dist/tools/data.d.cts +1 -0
  66. package/dist/tools/data.d.ts +1 -0
  67. package/dist/tools/data.js +2 -0
  68. package/dist/tools/encoding.cjs +261 -0
  69. package/dist/tools/encoding.d.cts +1 -0
  70. package/dist/tools/encoding.d.ts +1 -0
  71. package/dist/tools/encoding.js +2 -0
  72. package/dist/tools/generators.cjs +521 -0
  73. package/dist/tools/generators.d.cts +1 -0
  74. package/dist/tools/generators.d.ts +1 -0
  75. package/dist/tools/generators.js +2 -0
  76. package/dist/tools/hashing.cjs +259 -0
  77. package/dist/tools/hashing.d.cts +1 -0
  78. package/dist/tools/hashing.d.ts +1 -0
  79. package/dist/tools/hashing.js +2 -0
  80. package/dist/tools/json.cjs +1270 -0
  81. package/dist/tools/json.d.cts +1 -0
  82. package/dist/tools/json.d.ts +1 -0
  83. package/dist/tools/json.js +2 -0
  84. package/dist/tools/misc.cjs +1082 -0
  85. package/dist/tools/misc.d.cts +1 -0
  86. package/dist/tools/misc.d.ts +1 -0
  87. package/dist/tools/misc.js +2 -0
  88. package/dist/tools/network.cjs +1381 -0
  89. package/dist/tools/network.d.cts +1 -0
  90. package/dist/tools/network.d.ts +1 -0
  91. package/dist/tools/network.js +2 -0
  92. package/dist/tools/text.cjs +2224 -0
  93. package/dist/tools/text.d.cts +1 -0
  94. package/dist/tools/text.d.ts +1 -0
  95. package/dist/tools/text.js +2 -0
  96. package/dist/tools/time.cjs +681 -0
  97. package/dist/tools/time.d.cts +1 -0
  98. package/dist/tools/time.d.ts +1 -0
  99. package/dist/tools/time.js +2 -0
  100. package/dist/tools/units.cjs +892 -0
  101. package/dist/tools/units.d.cts +1 -0
  102. package/dist/tools/units.d.ts +1 -0
  103. package/dist/tools/units.js +2 -0
  104. package/dist/units-6lwDYBvX.d.cts +302 -0
  105. package/dist/units-6lwDYBvX.d.ts +302 -0
  106. package/package.json +148 -0
@@ -0,0 +1,2215 @@
1
+ import { __export } from './chunk-MLKGABMK.js';
2
+ import { load } from 'js-yaml';
3
+
4
+ // src/tools/code.ts
5
+ var code_exports = {};
6
+ __export(code_exports, {
7
+ ALL_FLAGS: () => ALL_FLAGS,
8
+ CHEATSHEET: () => CHEATSHEET,
9
+ OPERATIONS: () => OPERATIONS,
10
+ SQL_DEFAULT_OPTIONS: () => SQL_DEFAULT_OPTIONS,
11
+ buildDockerPull: () => buildDockerPull,
12
+ buildDockerRun: () => buildDockerRun,
13
+ buildGitCommand: () => buildGitCommand,
14
+ collapseHtmlWhitespace: () => collapseHtmlWhitespace,
15
+ collapseJsWhitespace: () => collapseJsWhitespace,
16
+ detectDialect: () => detectDialect,
17
+ detectOperationType: () => detectOperationType,
18
+ envToExport: () => envToExport,
19
+ envToJson: () => envToJson,
20
+ formatGql: () => formatGql,
21
+ formatHtml: () => formatHtml,
22
+ formatSql: () => formatSql,
23
+ getEndpointsByTag: () => getEndpointsByTag,
24
+ getHtmlStats: () => getHtmlStats,
25
+ getJsStats: () => getJsStats,
26
+ getMethodColor: () => getMethodColor,
27
+ isValidTag: () => isValidTag,
28
+ minifyGql: () => minifyGql,
29
+ minifyHtml: () => minifyHtml,
30
+ minifyJs: () => minifyJs,
31
+ minifySql: () => minifySql,
32
+ normalizeRef: () => normalizeRef,
33
+ parseDockerImage: () => parseDockerImage,
34
+ parseEnv: () => parseEnv,
35
+ parseGitCommand: () => parseGitCommand,
36
+ parseSpec: () => parseSpec,
37
+ removeConsoleCalls: () => removeConsoleCalls,
38
+ removeEmptyAttributes: () => removeEmptyAttributes,
39
+ removeHtmlComments: () => removeHtmlComments,
40
+ removeJsComments: () => removeJsComments,
41
+ removeRedundantAttributes: () => removeRedundantAttributes,
42
+ searchCheatsheet: () => searchCheatsheet,
43
+ searchEndpoints: () => searchEndpoints,
44
+ splitStatements: () => splitStatements,
45
+ testPattern: () => testPattern,
46
+ testRegex: () => testRegex,
47
+ validateEnvKey: () => validateEnvKey
48
+ });
49
+ var ALL_FLAGS = ["g", "i", "m", "s", "u"];
50
+ function testRegex(pattern, flags, input) {
51
+ if (!pattern) {
52
+ return {
53
+ ok: true,
54
+ matches: [],
55
+ matchCount: 0,
56
+ segments: input ? [{ text: input, matched: false, matchIndex: -1 }] : []
57
+ };
58
+ }
59
+ const flagStr = Array.from(/* @__PURE__ */ new Set([...flags, "g"])).join("");
60
+ let regex;
61
+ try {
62
+ regex = new RegExp(pattern, flagStr);
63
+ } catch (e) {
64
+ return { ok: false, error: e.message };
65
+ }
66
+ const matches = [];
67
+ let match;
68
+ let lastIndex = 0;
69
+ while ((match = regex.exec(input)) !== null) {
70
+ matches.push({
71
+ fullMatch: match[0],
72
+ index: match.index,
73
+ groups: match.slice(1),
74
+ namedGroups: match.groups ?? {}
75
+ });
76
+ if (match.index === regex.lastIndex) {
77
+ regex.lastIndex++;
78
+ }
79
+ if (regex.lastIndex <= lastIndex) break;
80
+ lastIndex = regex.lastIndex;
81
+ if (!flags.includes("g")) break;
82
+ }
83
+ return {
84
+ ok: true,
85
+ matches,
86
+ matchCount: matches.length,
87
+ segments: buildSegments(input, matches)
88
+ };
89
+ }
90
+ function buildSegments(input, matches) {
91
+ if (!input) return [];
92
+ if (matches.length === 0) return [{ text: input, matched: false, matchIndex: -1 }];
93
+ const segments = [];
94
+ let cursor = 0;
95
+ for (let i = 0; i < matches.length; i++) {
96
+ const { index, fullMatch } = matches[i];
97
+ if (index > cursor) {
98
+ segments.push({ text: input.slice(cursor, index), matched: false, matchIndex: -1 });
99
+ }
100
+ if (fullMatch.length > 0) {
101
+ segments.push({ text: fullMatch, matched: true, matchIndex: i });
102
+ }
103
+ cursor = index + fullMatch.length;
104
+ }
105
+ if (cursor < input.length) {
106
+ segments.push({ text: input.slice(cursor), matched: false, matchIndex: -1 });
107
+ }
108
+ return segments;
109
+ }
110
+ var CHEATSHEET = [
111
+ { pattern: "^", description: "Matches the start of a string or line", example: "^Hello matches 'Hello world' but not 'Say Hello'", category: "Anchors" },
112
+ { pattern: "$", description: "Matches the end of a string or line", example: "world$ matches 'Hello world' but not 'world domination'", category: "Anchors" },
113
+ { pattern: "\\b", description: "Matches a word boundary", example: "\\bcat\\b matches 'cat' but not 'concatenate'", category: "Anchors" },
114
+ { pattern: "\\B", description: "Matches a non-word boundary", example: "\\Bcat\\B matches 'concatenate' but not standalone 'cat'", category: "Anchors" },
115
+ { pattern: "\\A", description: "Matches the absolute start of the string (not multiline)", example: "\\AHello matches only if string starts with Hello", category: "Anchors" },
116
+ { pattern: "\\Z", description: "Matches the absolute end of the string", example: "world\\Z matches only if string ends with world", category: "Anchors" },
117
+ { pattern: ".", description: "Matches any character except newline", example: "h.t matches 'hat', 'hit', 'hot'", category: "Character Classes" },
118
+ { pattern: "\\d", description: "Matches any digit (0-9)", example: "\\d+ matches '123' in 'abc123def'", category: "Character Classes" },
119
+ { pattern: "\\D", description: "Matches any non-digit character", example: "\\D+ matches 'abc' in 'abc123'", category: "Character Classes" },
120
+ { pattern: "\\w", description: "Matches any word character (alphanumeric plus underscore)", example: "\\w+ matches 'hello_world'", category: "Character Classes" },
121
+ { pattern: "\\W", description: "Matches any non-word character", example: "\\W+ matches spaces and punctuation", category: "Character Classes" },
122
+ { pattern: "\\s", description: "Matches any whitespace character", example: "\\s+ matches spaces, tabs, newlines", category: "Character Classes" },
123
+ { pattern: "\\S", description: "Matches any non-whitespace character", example: "\\S+ matches 'hello' in ' hello '", category: "Character Classes" },
124
+ { pattern: "[abc]", description: "Matches any single character listed in the set", example: "[aeiou] matches any vowel", category: "Character Classes" },
125
+ { pattern: "[^abc]", description: "Matches any single character not in the set", example: "[^aeiou] matches any consonant or non-letter", category: "Character Classes" },
126
+ { pattern: "[a-z]", description: "Matches any character in the specified range", example: "[a-z] matches any lowercase letter", category: "Character Classes" },
127
+ { pattern: "*", description: "Matches 0 or more repetitions of the preceding element", example: "ab* matches 'a', 'ab', 'abb', 'abbb'", category: "Quantifiers" },
128
+ { pattern: "+", description: "Matches 1 or more repetitions of the preceding element", example: "ab+ matches 'ab', 'abb', 'abbb' but not 'a'", category: "Quantifiers" },
129
+ { pattern: "?", description: "Matches 0 or 1 occurrence of the preceding element", example: "colou?r matches 'color' and 'colour'", category: "Quantifiers" },
130
+ { pattern: "{n}", description: "Matches exactly n repetitions", example: "\\d{3} matches exactly 3 digits", category: "Quantifiers" },
131
+ { pattern: "{n,}", description: "Matches n or more repetitions", example: "\\d{2,} matches 2 or more digits", category: "Quantifiers" },
132
+ { pattern: "{n,m}", description: "Matches between n and m repetitions", example: "\\d{2,4} matches 2 to 4 digits", category: "Quantifiers" },
133
+ { pattern: "*?", description: "Lazy match \u2014 matches as few characters as possible", example: "<.*?> matches the shortest possible HTML tag", category: "Quantifiers" },
134
+ { pattern: "+?", description: "Lazy version of +", example: "a+? matches as few 'a's as possible", category: "Quantifiers" },
135
+ { pattern: "(abc)", description: "Capturing group \u2014 captures the matched substring", example: "(\\d+) captures digit sequences", category: "Groups" },
136
+ { pattern: "(?:abc)", description: "Non-capturing group \u2014 groups without capturing", example: "(?:foo|bar)baz matches 'foobaz' or 'barbaz'", category: "Groups" },
137
+ { pattern: "(?<name>abc)", description: "Named capturing group", example: "(?<year>\\d{4}) captures year by name", category: "Groups" },
138
+ { pattern: "a|b", description: "Alternation \u2014 matches either a or b", example: "cat|dog matches 'cat' or 'dog'", category: "Groups" },
139
+ { pattern: "\\1", description: "Backreference to the first capturing group", example: "(\\w+) \\1 matches repeated words like 'the the'", category: "Groups" },
140
+ { pattern: "\\k<name>", description: "Backreference to a named capturing group", example: "(?<word>\\w+) \\k<word> matches repeated named group", category: "Groups" },
141
+ { pattern: "(?=abc)", description: "Positive lookahead \u2014 asserts what follows matches", example: "\\d+(?= dollars) matches digits followed by ' dollars'", category: "Lookahead/Lookbehind" },
142
+ { pattern: "(?!abc)", description: "Negative lookahead \u2014 asserts what follows does not match", example: "\\d+(?! dollars) matches digits not followed by ' dollars'", category: "Lookahead/Lookbehind" },
143
+ { pattern: "(?<=abc)", description: "Positive lookbehind \u2014 asserts what precedes matches", example: "(?<=\\$)\\d+ matches digits preceded by '$'", category: "Lookahead/Lookbehind" },
144
+ { pattern: "(?<!abc)", description: "Negative lookbehind \u2014 asserts what precedes does not match", example: "(?<!\\$)\\d+ matches digits not preceded by '$'", category: "Lookahead/Lookbehind" },
145
+ { pattern: "g", description: "Global flag \u2014 finds all matches rather than stopping at the first", example: "/\\d+/g finds all numbers in a string", category: "Flags" },
146
+ { pattern: "i", description: "Case-insensitive flag \u2014 ignores letter case", example: "/hello/i matches 'Hello', 'HELLO', 'hello'", category: "Flags" },
147
+ { pattern: "m", description: "Multiline flag \u2014 ^ and $ match start/end of each line", example: "/^\\w+/m matches the first word of each line", category: "Flags" },
148
+ { pattern: "s", description: "Dotall flag \u2014 makes . match newline characters too", example: "/a.b/s matches 'a\\nb'", category: "Flags" },
149
+ { pattern: "u", description: "Unicode flag \u2014 enables full Unicode matching", example: "/\\u{1F600}/u matches a Unicode emoji", category: "Flags" },
150
+ { pattern: "y", description: "Sticky flag \u2014 matches only from the lastIndex position", example: "/\\d+/y matches digits starting at the current position", category: "Flags" },
151
+ { pattern: "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}", description: "Matches a basic email address", example: "user@example.com", category: "Common Patterns" },
152
+ { pattern: "https?://[\\w\\-]+(\\.[\\w\\-]+)+([\\w.,@?^=%&:/~+#\\-]*[\\w@?^=%&/~+#\\-])?", description: "Matches an HTTP or HTTPS URL", example: "https://www.example.com/path?query=value", category: "Common Patterns" },
153
+ { pattern: "^(?:\\+1)?[-.\\s]?\\(?\\d{3}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}$", description: "Matches a North American phone number in various formats", example: "(555) 123-4567 or 555-123-4567", category: "Common Patterns" },
154
+ { pattern: "^\\d{5}(?:-\\d{4})?$", description: "Matches a US ZIP code (5 digits or ZIP+4)", example: "12345 or 12345-6789", category: "Common Patterns" },
155
+ { pattern: "^(?:(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$", description: "Matches a valid IPv4 address", example: "192.168.1.1", category: "Common Patterns" },
156
+ { pattern: "^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$", description: "Matches a basic IPv6 address", example: "2001:0db8:85a3:0000:0000:8a2e:0370:7334", category: "Common Patterns" },
157
+ { pattern: "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$", description: "Matches a UUID/GUID", example: "123e4567-e89b-12d3-a456-426614174000", category: "Common Patterns" },
158
+ { pattern: "^(?:(?:31(\\/|-|\\.)(?:0?[13578]|1[02]))\\1|(?:(?:29|30)(\\/|-|\\.)(?:0?[1,3-9]|1[0-2])\\2))(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$|^(?:29(\\/|-|\\.)0?2\\3(?:(?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\\d|2[0-8])(\\/|-|\\.)(?:(?:0?[1-9])|(?:1[0-2]))\\4(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$", description: "Matches a date in DD/MM/YYYY format with basic validation", example: "31/12/2023", category: "Common Patterns" },
159
+ { pattern: "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$", description: "Matches a CSS hex color code", example: "#FF5733 or #F53", category: "Common Patterns" },
160
+ { pattern: "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$", description: "Matches a strong password with uppercase, lowercase, digit, and special character", example: "P@ssword1", category: "Common Patterns" }
161
+ ];
162
+ function testPattern(pattern, flags, text) {
163
+ let regex;
164
+ try {
165
+ const flagsWithGlobal = flags.includes("g") ? flags : flags + "g";
166
+ regex = new RegExp(pattern, flagsWithGlobal);
167
+ } catch (err) {
168
+ return {
169
+ matches: [],
170
+ isValid: false,
171
+ error: err instanceof Error ? err.message : String(err)
172
+ };
173
+ }
174
+ const matches = [];
175
+ let match;
176
+ while ((match = regex.exec(text)) !== null) {
177
+ const result = {
178
+ value: match[0],
179
+ index: match.index
180
+ };
181
+ if (match.groups && Object.keys(match.groups).length > 0) {
182
+ const filteredGroups = {};
183
+ for (const [key, value] of Object.entries(match.groups)) {
184
+ if (value !== void 0) {
185
+ filteredGroups[key] = value;
186
+ }
187
+ }
188
+ if (Object.keys(filteredGroups).length > 0) {
189
+ result.groups = filteredGroups;
190
+ }
191
+ }
192
+ matches.push(result);
193
+ if (match[0].length === 0) {
194
+ regex.lastIndex++;
195
+ }
196
+ }
197
+ return { matches, isValid: true };
198
+ }
199
+ function searchCheatsheet(query) {
200
+ if (query === "") {
201
+ return CHEATSHEET;
202
+ }
203
+ const lower = query.toLowerCase();
204
+ return CHEATSHEET.filter(
205
+ (entry) => entry.pattern.toLowerCase().includes(lower) || entry.description.toLowerCase().includes(lower) || entry.category.toLowerCase().includes(lower)
206
+ );
207
+ }
208
+ var SQL_DEFAULT_OPTIONS = {
209
+ indent: 2,
210
+ uppercase: true,
211
+ linesBetweenQueries: 1
212
+ };
213
+ var SQL_KEYWORDS = [
214
+ "SELECT",
215
+ "DISTINCT",
216
+ "FROM",
217
+ "WHERE",
218
+ "AND",
219
+ "OR",
220
+ "NOT",
221
+ "JOIN",
222
+ "INNER JOIN",
223
+ "LEFT JOIN",
224
+ "RIGHT JOIN",
225
+ "FULL JOIN",
226
+ "FULL OUTER JOIN",
227
+ "LEFT OUTER JOIN",
228
+ "RIGHT OUTER JOIN",
229
+ "CROSS JOIN",
230
+ "ON",
231
+ "AS",
232
+ "GROUP BY",
233
+ "ORDER BY",
234
+ "HAVING",
235
+ "LIMIT",
236
+ "OFFSET",
237
+ "INSERT INTO",
238
+ "VALUES",
239
+ "UPDATE",
240
+ "SET",
241
+ "DELETE FROM",
242
+ "DELETE",
243
+ "CREATE TABLE",
244
+ "CREATE INDEX",
245
+ "CREATE VIEW",
246
+ "ALTER TABLE",
247
+ "DROP TABLE",
248
+ "DROP",
249
+ "IF NOT EXISTS",
250
+ "IF EXISTS",
251
+ "PRIMARY KEY",
252
+ "FOREIGN KEY",
253
+ "REFERENCES",
254
+ "UNIQUE",
255
+ "NOT NULL",
256
+ "DEFAULT",
257
+ "CHECK",
258
+ "CONSTRAINT",
259
+ "INDEX",
260
+ "INTO",
261
+ "IN",
262
+ "IS",
263
+ "NULL",
264
+ "BETWEEN",
265
+ "LIKE",
266
+ "ILIKE",
267
+ "EXISTS",
268
+ "UNION",
269
+ "UNION ALL",
270
+ "INTERSECT",
271
+ "EXCEPT",
272
+ "WITH",
273
+ "CASE",
274
+ "WHEN",
275
+ "THEN",
276
+ "ELSE",
277
+ "END",
278
+ "CAST",
279
+ "COALESCE",
280
+ "COUNT",
281
+ "SUM",
282
+ "AVG",
283
+ "MIN",
284
+ "MAX",
285
+ "ASC",
286
+ "DESC",
287
+ "NULLS FIRST",
288
+ "NULLS LAST",
289
+ "RETURNING",
290
+ "OUTPUT"
291
+ ];
292
+ var MAJOR_CLAUSE_KEYWORDS = /* @__PURE__ */ new Set([
293
+ "SELECT",
294
+ "FROM",
295
+ "WHERE",
296
+ "GROUP BY",
297
+ "ORDER BY",
298
+ "HAVING",
299
+ "LIMIT",
300
+ "OFFSET",
301
+ "JOIN",
302
+ "INNER JOIN",
303
+ "LEFT JOIN",
304
+ "RIGHT JOIN",
305
+ "FULL JOIN",
306
+ "FULL OUTER JOIN",
307
+ "LEFT OUTER JOIN",
308
+ "RIGHT OUTER JOIN",
309
+ "CROSS JOIN",
310
+ "ON",
311
+ "INSERT INTO",
312
+ "VALUES",
313
+ "UPDATE",
314
+ "SET",
315
+ "DELETE FROM",
316
+ "DELETE",
317
+ "CREATE TABLE",
318
+ "ALTER TABLE",
319
+ "DROP TABLE",
320
+ "UNION",
321
+ "UNION ALL",
322
+ "INTERSECT",
323
+ "EXCEPT",
324
+ "RETURNING",
325
+ "WITH"
326
+ ]);
327
+ function sqlTokenize(sql) {
328
+ const tokens = [];
329
+ let i = 0;
330
+ while (i < sql.length) {
331
+ if (sql[i] === "-" && sql[i + 1] === "-") {
332
+ let j = i;
333
+ while (j < sql.length && sql[j] !== "\n") j++;
334
+ tokens.push({ type: "comment", value: sql.slice(i, j), upper: sql.slice(i, j) });
335
+ i = j;
336
+ continue;
337
+ }
338
+ if (sql[i] === "/" && sql[i + 1] === "*") {
339
+ let j = i + 2;
340
+ while (j < sql.length && !(sql[j] === "*" && sql[j + 1] === "/")) j++;
341
+ j += 2;
342
+ tokens.push({ type: "comment", value: sql.slice(i, j), upper: sql.slice(i, j) });
343
+ i = j;
344
+ continue;
345
+ }
346
+ if (sql[i] === "'" || sql[i] === '"' || sql[i] === "`") {
347
+ const quote = sql[i];
348
+ let j = i + 1;
349
+ while (j < sql.length) {
350
+ if (sql[j] === quote && sql[j + 1] === quote) {
351
+ j += 2;
352
+ continue;
353
+ }
354
+ if (sql[j] === quote) {
355
+ j++;
356
+ break;
357
+ }
358
+ if (sql[j] === "\\") j++;
359
+ j++;
360
+ }
361
+ tokens.push({ type: "string", value: sql.slice(i, j), upper: sql.slice(i, j) });
362
+ i = j;
363
+ continue;
364
+ }
365
+ if (sql[i] === "$") {
366
+ const dollarMatch = sql.slice(i).match(/^\$([A-Za-z_]*)\$/);
367
+ if (dollarMatch) {
368
+ const tag = dollarMatch[0];
369
+ const end = sql.indexOf(tag, i + tag.length);
370
+ if (end !== -1) {
371
+ const j = end + tag.length;
372
+ tokens.push({ type: "string", value: sql.slice(i, j), upper: sql.slice(i, j) });
373
+ i = j;
374
+ continue;
375
+ }
376
+ }
377
+ }
378
+ if (/\s/.test(sql[i])) {
379
+ let j = i;
380
+ while (j < sql.length && /\s/.test(sql[j])) j++;
381
+ tokens.push({ type: "whitespace", value: sql.slice(i, j), upper: "" });
382
+ i = j;
383
+ continue;
384
+ }
385
+ if (/[0-9]/.test(sql[i]) || sql[i] === "." && /[0-9]/.test(sql[i + 1] || "")) {
386
+ let j = i;
387
+ while (j < sql.length && /[0-9._eE+\-]/.test(sql[j])) j++;
388
+ tokens.push({ type: "number", value: sql.slice(i, j), upper: sql.slice(i, j) });
389
+ i = j;
390
+ continue;
391
+ }
392
+ if (/[a-zA-Z_]/.test(sql[i])) {
393
+ let j = i;
394
+ while (j < sql.length && /[a-zA-Z0-9_]/.test(sql[j])) j++;
395
+ const word = sql.slice(i, j);
396
+ tokens.push({ type: "word", value: word, upper: word.toUpperCase() });
397
+ i = j;
398
+ continue;
399
+ }
400
+ tokens.push({ type: "punctuation", value: sql[i], upper: sql[i] });
401
+ i++;
402
+ }
403
+ return tokens;
404
+ }
405
+ function mergeKeywordTokens(tokens) {
406
+ const result = [];
407
+ let i = 0;
408
+ while (i < tokens.length) {
409
+ if (tokens[i].type === "word") {
410
+ let matched = false;
411
+ const sortedKws = [...SQL_KEYWORDS].sort((a, b) => b.length - a.length);
412
+ for (const kw of sortedKws) {
413
+ const parts = kw.split(" ");
414
+ let j = i;
415
+ const wordParts = [];
416
+ let ok = true;
417
+ for (const part of parts) {
418
+ while (j < tokens.length && tokens[j].type === "whitespace") {
419
+ wordParts.push(tokens[j]);
420
+ j++;
421
+ }
422
+ if (j < tokens.length && tokens[j].type === "word" && tokens[j].upper === part) {
423
+ wordParts.push(tokens[j]);
424
+ j++;
425
+ } else {
426
+ ok = false;
427
+ break;
428
+ }
429
+ }
430
+ if (ok && parts.length > 1) {
431
+ result.push({ type: "keyword", value: wordParts.map((t) => t.value).join(""), upper: kw });
432
+ i = j;
433
+ matched = true;
434
+ break;
435
+ }
436
+ }
437
+ if (!matched) {
438
+ const upper = tokens[i].upper;
439
+ if (SQL_KEYWORDS.includes(upper)) {
440
+ result.push({ type: "keyword", value: tokens[i].value, upper });
441
+ } else {
442
+ result.push(tokens[i]);
443
+ }
444
+ i++;
445
+ }
446
+ } else {
447
+ result.push(tokens[i]);
448
+ i++;
449
+ }
450
+ }
451
+ return result;
452
+ }
453
+ function applySqlCase(value, upper, uppercase) {
454
+ return uppercase ? upper : value;
455
+ }
456
+ function formatSql(sql, options) {
457
+ const opts = { ...SQL_DEFAULT_OPTIONS, ...options };
458
+ const indent = " ".repeat(opts.indent);
459
+ const statements = splitStatements(sql);
460
+ const separator = "\n".repeat(opts.linesBetweenQueries + 1);
461
+ return statements.map((stmt) => formatSqlStatement(stmt.trim(), opts, indent)).filter((s) => s.length > 0).join(separator);
462
+ }
463
+ function formatSqlStatement(sql, opts, indent) {
464
+ const raw = sqlTokenize(sql);
465
+ const tokens = mergeKeywordTokens(raw).filter((t) => t.type !== "whitespace");
466
+ if (tokens.length === 0) return "";
467
+ const lines = [];
468
+ let currentLine = "";
469
+ let parenDepth = 0;
470
+ let i = 0;
471
+ const flush = () => {
472
+ const trimmed = currentLine.trimEnd();
473
+ if (trimmed) lines.push(trimmed);
474
+ currentLine = "";
475
+ };
476
+ const addToLine = (s) => {
477
+ if (currentLine === "" || currentLine.endsWith(" ")) {
478
+ currentLine += s;
479
+ } else {
480
+ currentLine += " " + s;
481
+ }
482
+ };
483
+ const isColumnSeparatorContext = () => {
484
+ return parenDepth === 0 && lines.length > 0 && /^(SELECT|INSERT INTO)/i.test(lines[0]);
485
+ };
486
+ while (i < tokens.length) {
487
+ const tok = tokens[i];
488
+ if (tok.type === "comment") {
489
+ flush();
490
+ lines.push(tok.value);
491
+ i++;
492
+ continue;
493
+ }
494
+ if (tok.type === "punctuation" && tok.value === "(") {
495
+ currentLine += "(";
496
+ parenDepth++;
497
+ i++;
498
+ continue;
499
+ }
500
+ if (tok.type === "punctuation" && tok.value === ")") {
501
+ currentLine += ")";
502
+ parenDepth--;
503
+ i++;
504
+ continue;
505
+ }
506
+ if (tok.type === "punctuation" && tok.value === ",") {
507
+ currentLine += ",";
508
+ if (parenDepth === 0) {
509
+ flush();
510
+ if (isColumnSeparatorContext()) {
511
+ currentLine = indent;
512
+ }
513
+ }
514
+ i++;
515
+ continue;
516
+ }
517
+ if (tok.type === "punctuation" && tok.value === ";") {
518
+ currentLine += ";";
519
+ flush();
520
+ i++;
521
+ continue;
522
+ }
523
+ if (tok.type === "keyword" && MAJOR_CLAUSE_KEYWORDS.has(tok.upper) && parenDepth === 0) {
524
+ flush();
525
+ const kw = applySqlCase(tok.value, tok.upper, opts.uppercase);
526
+ currentLine = kw;
527
+ i++;
528
+ if (tok.upper === "SELECT" || tok.upper === "INSERT INTO") {
529
+ flush();
530
+ currentLine = indent;
531
+ }
532
+ continue;
533
+ }
534
+ if (tok.type === "keyword") {
535
+ addToLine(applySqlCase(tok.value, tok.upper, opts.uppercase));
536
+ i++;
537
+ continue;
538
+ }
539
+ addToLine(tok.value);
540
+ i++;
541
+ }
542
+ flush();
543
+ return lines.join("\n");
544
+ }
545
+ function minifySql(sql) {
546
+ const tokens = sqlTokenize(sql);
547
+ const result = [];
548
+ let pendingSpace = false;
549
+ for (const tok of tokens) {
550
+ if (tok.type === "comment") {
551
+ pendingSpace = false;
552
+ continue;
553
+ }
554
+ if (tok.type === "whitespace") {
555
+ if (result.length > 0) pendingSpace = true;
556
+ continue;
557
+ }
558
+ if (tok.type === "punctuation" && /^[(),;]$/.test(tok.value)) {
559
+ pendingSpace = false;
560
+ if (result.length > 0 && result[result.length - 1] === " ") {
561
+ result.pop();
562
+ }
563
+ result.push(tok.value);
564
+ pendingSpace = false;
565
+ continue;
566
+ }
567
+ if (pendingSpace) {
568
+ const last = result[result.length - 1] ?? "";
569
+ if (last && last !== "(" && last !== " ") {
570
+ result.push(" ");
571
+ }
572
+ pendingSpace = false;
573
+ }
574
+ result.push(tok.value);
575
+ }
576
+ return result.join("").trim();
577
+ }
578
+ function detectDialect(sql) {
579
+ const upper = sql.toUpperCase();
580
+ if (upper.includes("AUTO_INCREMENT") || upper.includes("ENGINE=") || upper.includes("TINYINT") || upper.includes("SHOW TABLES")) {
581
+ return "mysql";
582
+ }
583
+ if (upper.includes("SERIAL") || upper.includes("RETURNING") || upper.includes("ILIKE") || upper.includes("::") || upper.includes("$$") || upper.includes("JSONB") || upper.includes("ON CONFLICT")) {
584
+ return "postgresql";
585
+ }
586
+ if (upper.includes("AUTOINCREMENT") || upper.includes("PRAGMA") || upper.includes("WITHOUT ROWID") || upper.includes("SQLITE_")) {
587
+ return "sqlite";
588
+ }
589
+ return "generic";
590
+ }
591
+ function splitStatements(sql) {
592
+ const tokens = sqlTokenize(sql);
593
+ const statements = [];
594
+ let current = "";
595
+ let parenDepth = 0;
596
+ for (const tok of tokens) {
597
+ if (tok.type === "punctuation" && tok.value === "(") {
598
+ parenDepth++;
599
+ current += tok.value;
600
+ } else if (tok.type === "punctuation" && tok.value === ")") {
601
+ parenDepth--;
602
+ current += tok.value;
603
+ } else if (tok.type === "punctuation" && tok.value === ";" && parenDepth === 0) {
604
+ const trimmed2 = current.trim();
605
+ if (trimmed2) statements.push(trimmed2);
606
+ current = "";
607
+ } else {
608
+ current += tok.value;
609
+ }
610
+ }
611
+ const trimmed = current.trim();
612
+ if (trimmed) statements.push(trimmed);
613
+ return statements;
614
+ }
615
+ var VOID_ELEMENTS = /* @__PURE__ */ new Set([
616
+ "area",
617
+ "base",
618
+ "br",
619
+ "col",
620
+ "embed",
621
+ "hr",
622
+ "img",
623
+ "input",
624
+ "link",
625
+ "meta",
626
+ "param",
627
+ "source",
628
+ "track",
629
+ "wbr"
630
+ ]);
631
+ var RAW_TEXT_ELEMENTS = /* @__PURE__ */ new Set(["pre", "script", "style", "textarea"]);
632
+ function computeHtmlSavings(originalSize, outputSize) {
633
+ if (originalSize === 0) return 0;
634
+ const pct = Math.round((1 - outputSize / originalSize) * 100);
635
+ return pct > 0 ? pct : 0;
636
+ }
637
+ function htmlTokenize(input) {
638
+ const tokens = [];
639
+ let i = 0;
640
+ while (i < input.length) {
641
+ if (input[i] !== "<") {
642
+ let j = i;
643
+ while (j < input.length && input[j] !== "<") j++;
644
+ tokens.push({ type: "text", raw: input.slice(i, j) });
645
+ i = j;
646
+ continue;
647
+ }
648
+ if (input.startsWith("<!--", i)) {
649
+ const end2 = input.indexOf("-->", i + 4);
650
+ if (end2 === -1) {
651
+ tokens.push({ type: "comment", raw: input.slice(i) });
652
+ break;
653
+ }
654
+ tokens.push({ type: "comment", raw: input.slice(i, end2 + 3) });
655
+ i = end2 + 3;
656
+ continue;
657
+ }
658
+ if (input.slice(i, i + 9).toLowerCase() === "<!doctype") {
659
+ const end2 = input.indexOf(">", i);
660
+ const raw2 = end2 === -1 ? input.slice(i) : input.slice(i, end2 + 1);
661
+ tokens.push({ type: "doctype", raw: raw2 });
662
+ i = end2 === -1 ? input.length : end2 + 1;
663
+ continue;
664
+ }
665
+ if (input[i + 1] === "/") {
666
+ const end2 = input.indexOf(">", i);
667
+ const raw2 = end2 === -1 ? input.slice(i) : input.slice(i, end2 + 1);
668
+ const tag2 = raw2.slice(2, raw2.length - 1).trim().toLowerCase();
669
+ tokens.push({ type: "close", tag: tag2, raw: raw2 });
670
+ i = end2 === -1 ? input.length : end2 + 1;
671
+ continue;
672
+ }
673
+ const end = input.indexOf(">", i);
674
+ if (end === -1) {
675
+ tokens.push({ type: "text", raw: input.slice(i) });
676
+ break;
677
+ }
678
+ const raw = input.slice(i, end + 1);
679
+ const tagMatch = raw.match(/^<([a-zA-Z][a-zA-Z0-9-]*)/);
680
+ if (!tagMatch) {
681
+ tokens.push({ type: "text", raw });
682
+ i = end + 1;
683
+ continue;
684
+ }
685
+ const tag = tagMatch[1].toLowerCase();
686
+ const selfClose = raw.endsWith("/>") || VOID_ELEMENTS.has(tag);
687
+ if (RAW_TEXT_ELEMENTS.has(tag) && !selfClose) {
688
+ const closeTag = `</${tag}>`;
689
+ const closeIdx = input.toLowerCase().indexOf(closeTag, end + 1);
690
+ if (closeIdx === -1) {
691
+ const content = input.slice(end + 1);
692
+ tokens.push({ type: "open", tag, raw, selfClose: false });
693
+ tokens.push({ type: "raw", tag, content, closeTag });
694
+ i = input.length;
695
+ } else {
696
+ const content = input.slice(end + 1, closeIdx);
697
+ tokens.push({ type: "open", tag, raw, selfClose: false });
698
+ tokens.push({ type: "raw", tag, content, closeTag: input.slice(closeIdx, closeIdx + closeTag.length) });
699
+ i = closeIdx + closeTag.length;
700
+ }
701
+ continue;
702
+ }
703
+ tokens.push({ type: "open", tag, raw, selfClose });
704
+ i = end + 1;
705
+ }
706
+ return tokens;
707
+ }
708
+ function formatHtml(input, indentSize = 2) {
709
+ const originalSize = input.length;
710
+ if (input.trim() === "") {
711
+ return { output: "", originalSize, outputSize: 0, savings: 0 };
712
+ }
713
+ const indent = " ".repeat(indentSize);
714
+ const tokens = htmlTokenize(input);
715
+ const lines = [];
716
+ let depth = 0;
717
+ const pad = (d) => indent.repeat(Math.max(0, d));
718
+ for (const token of tokens) {
719
+ switch (token.type) {
720
+ case "doctype":
721
+ lines.push(token.raw.trim());
722
+ break;
723
+ case "comment":
724
+ lines.push(pad(depth) + token.raw.trim());
725
+ break;
726
+ case "open":
727
+ lines.push(pad(depth) + token.raw.trim());
728
+ if (!token.selfClose) {
729
+ depth++;
730
+ }
731
+ break;
732
+ case "close":
733
+ depth = Math.max(0, depth - 1);
734
+ lines.push(pad(depth) + token.raw.trim());
735
+ break;
736
+ case "text": {
737
+ const text = token.raw.trim();
738
+ if (text) {
739
+ lines.push(pad(depth) + text);
740
+ }
741
+ break;
742
+ }
743
+ case "raw": {
744
+ lines.push(token.content);
745
+ depth = Math.max(0, depth - 1);
746
+ lines.push(pad(depth) + token.closeTag.trim());
747
+ break;
748
+ }
749
+ }
750
+ }
751
+ const output = lines.join("\n");
752
+ const outputSize = output.length;
753
+ return {
754
+ output,
755
+ originalSize,
756
+ outputSize,
757
+ savings: computeHtmlSavings(originalSize, outputSize)
758
+ };
759
+ }
760
+ function removeHtmlComments(html) {
761
+ return html.replace(/<!--(?!\[if\s)[\s\S]*?-->/gi, "");
762
+ }
763
+ function collapseHtmlWhitespace(html) {
764
+ const preserved = [];
765
+ let result = html;
766
+ result = result.replace(
767
+ /<(pre|script|style|textarea)[\s\S]*?<\/\1>/gi,
768
+ (match) => {
769
+ preserved.push(match);
770
+ return `\0PRESERVED${preserved.length - 1}\0`;
771
+ }
772
+ );
773
+ result = result.replace(/\s+/g, " ").replace(/>\s+</g, "><").trim();
774
+ result = result.replace(/\x00PRESERVED(\d+)\x00/g, (_, idx) => preserved[parseInt(idx, 10)]);
775
+ return result;
776
+ }
777
+ function removeEmptyAttributes(html) {
778
+ return html.replace(/\s+[\w-]+=(?:""|'')/g, "");
779
+ }
780
+ function removeRedundantAttributes(html) {
781
+ return html.replace(/\s+type="text\/javascript"/gi, "").replace(/\s+type="text\/css"/gi, "").replace(/\s+language="javascript"/gi, "");
782
+ }
783
+ function basicMinifyCss(css) {
784
+ return css.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\s*([{}:;,>+~])\s*/g, "$1").replace(/;\s*}/g, "}").replace(/\s+/g, " ").trim();
785
+ }
786
+ function basicMinifyJsInHtml(js) {
787
+ return js.replace(/\/\/[^\n]*/g, "").replace(/\/\*[\s\S]*?\*\//g, "").replace(/\s+/g, " ").trim();
788
+ }
789
+ function minifyInlineStyle(html) {
790
+ return html.replace(
791
+ /<style([\s\S]*?)>([\s\S]*?)<\/style>/gi,
792
+ (_, attrs, content) => `<style${attrs}>${basicMinifyCss(content)}</style>`
793
+ );
794
+ }
795
+ function minifyInlineScript(html) {
796
+ return html.replace(
797
+ /<script([\s\S]*?)>([\s\S]*?)<\/script>/gi,
798
+ (_, attrs, content) => `<script${attrs}>${basicMinifyJsInHtml(content)}</script>`
799
+ );
800
+ }
801
+ function minifyHtml(html, options = {}) {
802
+ const {
803
+ removeComments: doRemoveComments = true,
804
+ collapseWhitespace: doCollapseWhitespace = true,
805
+ removeEmptyAttributes: doRemoveEmptyAttrs = false,
806
+ removeRedundantAttributes: doRemoveRedundantAttrs = false,
807
+ minifyInlineCSS = false,
808
+ minifyInlineJS = false
809
+ } = options;
810
+ const original = html;
811
+ let minified = html;
812
+ if (doRemoveComments) minified = removeHtmlComments(minified);
813
+ if (doRemoveEmptyAttrs) minified = removeEmptyAttributes(minified);
814
+ if (doRemoveRedundantAttrs) minified = removeRedundantAttributes(minified);
815
+ if (minifyInlineCSS) minified = minifyInlineStyle(minified);
816
+ if (minifyInlineJS) minified = minifyInlineScript(minified);
817
+ if (doCollapseWhitespace) minified = collapseHtmlWhitespace(minified);
818
+ const encoder = new TextEncoder();
819
+ const originalSize = encoder.encode(original).length;
820
+ const minifiedSize = encoder.encode(minified).length;
821
+ const savedBytes = Math.max(0, originalSize - minifiedSize);
822
+ const savedPercent = originalSize > 0 ? Math.round(savedBytes / originalSize * 1e4) / 100 : 0;
823
+ return { original, minified, originalSize, minifiedSize, savedBytes, savedPercent };
824
+ }
825
+ function getHtmlStats(html) {
826
+ const tagMatches = html.match(/<[a-zA-Z][^>]*>/g) ?? [];
827
+ const tags = tagMatches.length;
828
+ let attributes = 0;
829
+ for (const tag of tagMatches) {
830
+ const attrMatches = tag.match(/\s[\w-]+=(?:"[^"]*"|'[^']*'|[^\s>]+)/g) ?? [];
831
+ attributes += attrMatches.length;
832
+ }
833
+ const textNodeMatches = html.replace(/<[^>]+>/g, "\0").split("\0").filter((s) => s.trim().length > 0);
834
+ const textNodes = textNodeMatches.length;
835
+ return { tags, attributes, textNodes };
836
+ }
837
+ function formatGql(input, indentSize = 2) {
838
+ const trimmed = input.trim();
839
+ if (!trimmed) {
840
+ return { output: "", valid: false, error: "Input is empty" };
841
+ }
842
+ const normalized = trimmed.replace(/\s+/g, " ");
843
+ let result = "";
844
+ let indentLevel = 0;
845
+ let lineBuffer = "";
846
+ let argDepth = 0;
847
+ let i = 0;
848
+ const indent = () => " ".repeat(indentSize * indentLevel);
849
+ while (i < normalized.length) {
850
+ const ch = normalized[i];
851
+ if (ch === "(") {
852
+ argDepth++;
853
+ lineBuffer += ch;
854
+ i++;
855
+ while (i < normalized.length && argDepth > 0) {
856
+ const ac = normalized[i];
857
+ if (ac === "(") argDepth++;
858
+ else if (ac === ")") argDepth--;
859
+ lineBuffer += ac;
860
+ i++;
861
+ }
862
+ continue;
863
+ }
864
+ if (ch === "{") {
865
+ const buf2 = lineBuffer.trim();
866
+ if (buf2) {
867
+ result += indent() + buf2 + " {\n";
868
+ } else {
869
+ result += indent() + "{\n";
870
+ }
871
+ lineBuffer = "";
872
+ indentLevel++;
873
+ i++;
874
+ continue;
875
+ }
876
+ if (ch === "}") {
877
+ const buf2 = lineBuffer.trim();
878
+ if (buf2) {
879
+ result += indent() + buf2 + "\n";
880
+ lineBuffer = "";
881
+ }
882
+ indentLevel = Math.max(0, indentLevel - 1);
883
+ result += indent() + "}\n";
884
+ i++;
885
+ continue;
886
+ }
887
+ if (ch === ",") {
888
+ const buf2 = lineBuffer.trim();
889
+ if (buf2) {
890
+ result += indent() + buf2 + "\n";
891
+ lineBuffer = "";
892
+ }
893
+ i++;
894
+ continue;
895
+ }
896
+ if (ch === " ") {
897
+ const buf2 = lineBuffer.trim();
898
+ if (buf2) {
899
+ let j = i + 1;
900
+ while (j < normalized.length && normalized[j] === " ") j++;
901
+ const nextCh = normalized[j];
902
+ if (nextCh === "{" || nextCh === "(" || nextCh === void 0) {
903
+ lineBuffer += " ";
904
+ } else if (nextCh === "}") {
905
+ result += indent() + buf2 + "\n";
906
+ lineBuffer = "";
907
+ } else {
908
+ let k = j;
909
+ let foundOpenBrace = false;
910
+ while (k < normalized.length) {
911
+ if (normalized[k] === "{") {
912
+ foundOpenBrace = true;
913
+ break;
914
+ }
915
+ if (normalized[k] === "}") break;
916
+ k++;
917
+ }
918
+ if (foundOpenBrace) {
919
+ lineBuffer += " ";
920
+ } else {
921
+ result += indent() + buf2 + "\n";
922
+ lineBuffer = "";
923
+ }
924
+ }
925
+ }
926
+ i++;
927
+ continue;
928
+ }
929
+ lineBuffer += ch;
930
+ i++;
931
+ }
932
+ const buf = lineBuffer.trim();
933
+ if (buf) {
934
+ result += indent() + buf + "\n";
935
+ }
936
+ const cleaned = result.split("\n").filter((line) => line.trim() !== "").map((line) => line.trimEnd()).join("\n");
937
+ return { output: cleaned, valid: true };
938
+ }
939
+ function minifyGql(input) {
940
+ const minified = input.replace(/\s+/g, " ").trim();
941
+ return { output: minified, valid: true };
942
+ }
943
+ function detectOperationType(input) {
944
+ const trimmed = input.trim().toLowerCase();
945
+ if (trimmed.startsWith("query")) return "query";
946
+ if (trimmed.startsWith("mutation")) return "mutation";
947
+ if (trimmed.startsWith("subscription")) return "subscription";
948
+ if (trimmed.startsWith("fragment")) return "fragment";
949
+ if (trimmed.includes("{")) return "query";
950
+ return "unknown";
951
+ }
952
+ var OPERATIONS = [
953
+ {
954
+ value: "commit",
955
+ label: "Commit",
956
+ description: "Record changes to the repository",
957
+ options: [
958
+ { key: "message", label: "Message", type: "string", flag: "--message/-m", required: true },
959
+ { key: "amend", label: "Amend", type: "boolean", flag: "--amend" },
960
+ { key: "noVerify", label: "No Verify", type: "boolean", flag: "--no-verify" },
961
+ { key: "all", label: "All", type: "boolean", flag: "--all/-a" }
962
+ ]
963
+ },
964
+ {
965
+ value: "branch",
966
+ label: "Branch",
967
+ description: "List, create, or delete branches",
968
+ options: [
969
+ { key: "name", label: "Branch Name", type: "string", flag: "" },
970
+ { key: "action", label: "Action", type: "string", flag: "", default: "list" },
971
+ { key: "newName", label: "New Name", type: "string", flag: "" },
972
+ { key: "force", label: "Force", type: "boolean", flag: "--force/-f" }
973
+ ]
974
+ },
975
+ {
976
+ value: "checkout",
977
+ label: "Checkout",
978
+ description: "Switch branches or restore working tree files",
979
+ options: [
980
+ { key: "branch", label: "Branch", type: "string", flag: "" },
981
+ { key: "newBranch", label: "New Branch", type: "boolean", flag: "-b" },
982
+ { key: "file", label: "File", type: "string", flag: "" }
983
+ ]
984
+ },
985
+ {
986
+ value: "merge",
987
+ label: "Merge",
988
+ description: "Join two or more development histories together",
989
+ options: [
990
+ { key: "branch", label: "Branch", type: "string", flag: "", required: true },
991
+ { key: "noFF", label: "No Fast Forward", type: "boolean", flag: "--no-ff" },
992
+ { key: "squash", label: "Squash", type: "boolean", flag: "--squash" },
993
+ { key: "message", label: "Message", type: "string", flag: "--message/-m" }
994
+ ]
995
+ },
996
+ {
997
+ value: "rebase",
998
+ label: "Rebase",
999
+ description: "Reapply commits on top of another base tip",
1000
+ options: [
1001
+ { key: "branch", label: "Branch", type: "string", flag: "", required: true },
1002
+ { key: "interactive", label: "Interactive", type: "boolean", flag: "--interactive/-i" },
1003
+ { key: "onto", label: "Onto", type: "string", flag: "--onto" }
1004
+ ]
1005
+ },
1006
+ {
1007
+ value: "stash",
1008
+ label: "Stash",
1009
+ description: "Stash the changes in a dirty working directory away",
1010
+ options: [
1011
+ { key: "action", label: "Action", type: "string", flag: "", default: "push" },
1012
+ { key: "message", label: "Message", type: "string", flag: "" },
1013
+ { key: "index", label: "Index", type: "number", flag: "" }
1014
+ ]
1015
+ },
1016
+ {
1017
+ value: "tag",
1018
+ label: "Tag",
1019
+ description: "Create, list, delete or verify a tag object",
1020
+ options: [
1021
+ { key: "name", label: "Tag Name", type: "string", flag: "", required: true },
1022
+ { key: "message", label: "Message", type: "string", flag: "--message/-m" },
1023
+ { key: "delete", label: "Delete", type: "boolean", flag: "-d" },
1024
+ { key: "ref", label: "Ref", type: "string", flag: "" }
1025
+ ]
1026
+ },
1027
+ {
1028
+ value: "remote",
1029
+ label: "Remote",
1030
+ description: "Manage set of tracked repositories",
1031
+ options: [
1032
+ { key: "action", label: "Action", type: "string", flag: "", default: "list" },
1033
+ { key: "name", label: "Name", type: "string", flag: "" },
1034
+ { key: "url", label: "URL", type: "string", flag: "" },
1035
+ { key: "newName", label: "New Name", type: "string", flag: "" }
1036
+ ]
1037
+ },
1038
+ {
1039
+ value: "reset",
1040
+ label: "Reset",
1041
+ description: "Reset current HEAD to the specified state",
1042
+ options: [
1043
+ { key: "ref", label: "Ref", type: "string", flag: "", default: "HEAD" },
1044
+ { key: "mode", label: "Mode", type: "string", flag: "", default: "mixed" },
1045
+ { key: "file", label: "File", type: "string", flag: "" }
1046
+ ]
1047
+ },
1048
+ {
1049
+ value: "cherry-pick",
1050
+ label: "Cherry Pick",
1051
+ description: "Apply the changes introduced by some existing commits",
1052
+ options: [
1053
+ { key: "commit", label: "Commit", type: "string", flag: "", required: true },
1054
+ { key: "noCommit", label: "No Commit", type: "boolean", flag: "--no-commit/-n" }
1055
+ ]
1056
+ },
1057
+ {
1058
+ value: "log",
1059
+ label: "Log",
1060
+ description: "Show commit logs",
1061
+ options: [
1062
+ { key: "oneline", label: "Oneline", type: "boolean", flag: "--oneline" },
1063
+ { key: "count", label: "Count", type: "number", flag: "-n" },
1064
+ { key: "author", label: "Author", type: "string", flag: "--author" },
1065
+ { key: "since", label: "Since", type: "string", flag: "--since" },
1066
+ { key: "graph", label: "Graph", type: "boolean", flag: "--graph" }
1067
+ ]
1068
+ },
1069
+ {
1070
+ value: "diff",
1071
+ label: "Diff",
1072
+ description: "Show changes between commits, commit and working tree, etc",
1073
+ options: [
1074
+ { key: "cached", label: "Cached", type: "boolean", flag: "--cached" },
1075
+ { key: "file", label: "File", type: "string", flag: "" },
1076
+ { key: "ref1", label: "Ref 1", type: "string", flag: "" },
1077
+ { key: "ref2", label: "Ref 2", type: "string", flag: "" },
1078
+ { key: "stat", label: "Stat", type: "boolean", flag: "--stat" }
1079
+ ]
1080
+ },
1081
+ {
1082
+ value: "clone",
1083
+ label: "Clone",
1084
+ description: "Clone a repository into a new directory",
1085
+ options: [
1086
+ { key: "url", label: "URL", type: "string", flag: "", required: true },
1087
+ { key: "directory", label: "Directory", type: "string", flag: "" },
1088
+ { key: "depth", label: "Depth", type: "number", flag: "--depth" },
1089
+ { key: "branch", label: "Branch", type: "string", flag: "--branch/-b" }
1090
+ ]
1091
+ },
1092
+ {
1093
+ value: "push",
1094
+ label: "Push",
1095
+ description: "Update remote refs along with associated objects",
1096
+ options: [
1097
+ { key: "remote", label: "Remote", type: "string", flag: "", default: "origin" },
1098
+ { key: "branch", label: "Branch", type: "string", flag: "" },
1099
+ { key: "force", label: "Force", type: "boolean", flag: "--force" },
1100
+ { key: "setUpstream", label: "Set Upstream", type: "boolean", flag: "--set-upstream/-u" },
1101
+ { key: "tags", label: "Tags", type: "boolean", flag: "--tags" }
1102
+ ]
1103
+ },
1104
+ {
1105
+ value: "pull",
1106
+ label: "Pull",
1107
+ description: "Fetch from and integrate with another repository or a local branch",
1108
+ options: [
1109
+ { key: "remote", label: "Remote", type: "string", flag: "", default: "origin" },
1110
+ { key: "branch", label: "Branch", type: "string", flag: "" },
1111
+ { key: "rebase", label: "Rebase", type: "boolean", flag: "--rebase" }
1112
+ ]
1113
+ },
1114
+ {
1115
+ value: "fetch",
1116
+ label: "Fetch",
1117
+ description: "Download objects and refs from another repository",
1118
+ options: [
1119
+ { key: "remote", label: "Remote", type: "string", flag: "", default: "origin" },
1120
+ { key: "all", label: "All", type: "boolean", flag: "--all" },
1121
+ { key: "prune", label: "Prune", type: "boolean", flag: "--prune/-p" },
1122
+ { key: "tags", label: "Tags", type: "boolean", flag: "--tags" }
1123
+ ]
1124
+ }
1125
+ ];
1126
+ function buildGitCommand(config) {
1127
+ const { operation, options } = config;
1128
+ switch (operation) {
1129
+ case "commit": {
1130
+ if (!options.message) {
1131
+ return { error: "commit requires a message" };
1132
+ }
1133
+ const flags = [];
1134
+ const parts = ["git", "commit"];
1135
+ if (options.all) {
1136
+ flags.push("-a");
1137
+ parts.push("-a");
1138
+ }
1139
+ if (options.amend) {
1140
+ flags.push("--amend");
1141
+ parts.push("--amend");
1142
+ }
1143
+ if (options.noVerify) {
1144
+ flags.push("--no-verify");
1145
+ parts.push("--no-verify");
1146
+ }
1147
+ flags.push("-m");
1148
+ parts.push(`-m "${options.message}"`);
1149
+ return {
1150
+ command: parts.join(" "),
1151
+ explanation: `Creates a new commit with the message "${options.message}"${options.amend ? ", amending the previous commit" : ""}${options.noVerify ? ", skipping pre-commit hooks" : ""}`,
1152
+ flags
1153
+ };
1154
+ }
1155
+ case "branch": {
1156
+ const action = options.action || "list";
1157
+ const flags = [];
1158
+ let command = "";
1159
+ let explanation = "";
1160
+ if (action === "list") {
1161
+ command = "git branch";
1162
+ explanation = "Lists all local branches";
1163
+ } else if (action === "create") {
1164
+ command = `git branch ${options.name}`;
1165
+ explanation = `Creates a new branch named "${options.name}"`;
1166
+ } else if (action === "delete") {
1167
+ const flag = options.force ? "-D" : "-d";
1168
+ flags.push(flag);
1169
+ command = `git branch ${flag} ${options.name}`;
1170
+ explanation = `Deletes the branch "${options.name}"${options.force ? " (force delete)" : ""}`;
1171
+ } else if (action === "rename") {
1172
+ flags.push("-m");
1173
+ command = `git branch -m ${options.name} ${options.newName}`;
1174
+ explanation = `Renames branch "${options.name}" to "${options.newName}"`;
1175
+ } else {
1176
+ return { error: `Unknown branch action: ${action}` };
1177
+ }
1178
+ return { command, explanation, flags };
1179
+ }
1180
+ case "checkout": {
1181
+ const flags = [];
1182
+ const parts = ["git", "checkout"];
1183
+ if (options.file) {
1184
+ parts.push("--", String(options.file));
1185
+ return { command: parts.join(" "), explanation: `Restores the file "${options.file}" from the index`, flags };
1186
+ }
1187
+ if (options.newBranch) {
1188
+ flags.push("-b");
1189
+ parts.push("-b");
1190
+ }
1191
+ if (options.branch) {
1192
+ parts.push(String(options.branch));
1193
+ }
1194
+ return {
1195
+ command: parts.join(" "),
1196
+ explanation: options.newBranch ? `Creates and switches to a new branch "${options.branch}"` : `Switches to branch "${options.branch}"`,
1197
+ flags
1198
+ };
1199
+ }
1200
+ case "merge": {
1201
+ if (!options.branch) {
1202
+ return { error: "merge requires a branch" };
1203
+ }
1204
+ const flags = [];
1205
+ const parts = ["git", "merge"];
1206
+ if (options.noFF) {
1207
+ flags.push("--no-ff");
1208
+ parts.push("--no-ff");
1209
+ }
1210
+ if (options.squash) {
1211
+ flags.push("--squash");
1212
+ parts.push("--squash");
1213
+ }
1214
+ if (options.message) {
1215
+ flags.push("-m");
1216
+ parts.push(`-m "${options.message}"`);
1217
+ }
1218
+ parts.push(String(options.branch));
1219
+ return {
1220
+ command: parts.join(" "),
1221
+ explanation: `Merges branch "${options.branch}" into the current branch${options.noFF ? " without fast-forwarding" : ""}${options.squash ? ", squashing commits" : ""}`,
1222
+ flags
1223
+ };
1224
+ }
1225
+ case "rebase": {
1226
+ if (!options.branch) {
1227
+ return { error: "rebase requires a branch" };
1228
+ }
1229
+ const flags = [];
1230
+ const parts = ["git", "rebase"];
1231
+ if (options.onto) {
1232
+ flags.push("--onto");
1233
+ parts.push(`--onto ${options.onto}`);
1234
+ }
1235
+ if (options.interactive) {
1236
+ flags.push("-i");
1237
+ parts.push("-i");
1238
+ }
1239
+ parts.push(String(options.branch));
1240
+ return {
1241
+ command: parts.join(" "),
1242
+ explanation: `Rebases current branch onto "${options.branch}"${options.interactive ? " interactively" : ""}`,
1243
+ flags
1244
+ };
1245
+ }
1246
+ case "stash": {
1247
+ const action = options.action || "push";
1248
+ const flags = [];
1249
+ let command = "";
1250
+ let explanation = "";
1251
+ if (action === "push") {
1252
+ const parts = ["git", "stash", "push"];
1253
+ if (options.message) {
1254
+ parts.push(`-m "${options.message}"`);
1255
+ flags.push("-m");
1256
+ }
1257
+ command = parts.join(" ");
1258
+ explanation = `Stashes current changes${options.message ? ` with message "${options.message}"` : ""}`;
1259
+ } else if (action === "pop") {
1260
+ command = options.index !== void 0 ? `git stash pop stash@{${options.index}}` : "git stash pop";
1261
+ explanation = `Pops the${options.index !== void 0 ? ` stash@{${options.index}}` : " latest"} stash and applies it`;
1262
+ } else if (action === "list") {
1263
+ command = "git stash list";
1264
+ explanation = "Lists all stashed changes";
1265
+ } else if (action === "drop") {
1266
+ command = options.index !== void 0 ? `git stash drop stash@{${options.index}}` : "git stash drop";
1267
+ explanation = `Drops the${options.index !== void 0 ? ` stash@{${options.index}}` : " latest"} stash`;
1268
+ } else if (action === "apply") {
1269
+ command = options.index !== void 0 ? `git stash apply stash@{${options.index}}` : "git stash apply";
1270
+ explanation = `Applies the${options.index !== void 0 ? ` stash@{${options.index}}` : " latest"} stash without removing it`;
1271
+ } else {
1272
+ return { error: `Unknown stash action: ${action}` };
1273
+ }
1274
+ return { command, explanation, flags };
1275
+ }
1276
+ case "tag": {
1277
+ if (!options.name) {
1278
+ return { error: "tag requires a name" };
1279
+ }
1280
+ const flags = [];
1281
+ const parts = ["git", "tag"];
1282
+ if (options.delete) {
1283
+ flags.push("-d");
1284
+ parts.push("-d", String(options.name));
1285
+ return { command: parts.join(" "), explanation: `Deletes tag "${options.name}"`, flags };
1286
+ }
1287
+ if (options.message) {
1288
+ flags.push("-m");
1289
+ parts.push(`-m "${options.message}"`);
1290
+ }
1291
+ parts.push(String(options.name));
1292
+ if (options.ref) {
1293
+ parts.push(String(options.ref));
1294
+ }
1295
+ return {
1296
+ command: parts.join(" "),
1297
+ explanation: `Creates a tag "${options.name}"${options.ref ? ` at ${options.ref}` : ""}${options.message ? ` with message "${options.message}"` : ""}`,
1298
+ flags
1299
+ };
1300
+ }
1301
+ case "remote": {
1302
+ const action = options.action || "list";
1303
+ const flags = [];
1304
+ let command = "";
1305
+ let explanation = "";
1306
+ if (action === "list") {
1307
+ command = "git remote";
1308
+ explanation = "Lists all remote connections";
1309
+ } else if (action === "add") {
1310
+ command = `git remote add ${options.name} ${options.url}`;
1311
+ explanation = `Adds a new remote "${options.name}" pointing to "${options.url}"`;
1312
+ } else if (action === "remove") {
1313
+ command = `git remote remove ${options.name}`;
1314
+ explanation = `Removes the remote "${options.name}"`;
1315
+ } else if (action === "rename") {
1316
+ command = `git remote rename ${options.name} ${options.newName}`;
1317
+ explanation = `Renames remote "${options.name}" to "${options.newName}"`;
1318
+ } else {
1319
+ return { error: `Unknown remote action: ${action}` };
1320
+ }
1321
+ return { command, explanation, flags };
1322
+ }
1323
+ case "reset": {
1324
+ const ref = options.ref || "HEAD";
1325
+ const mode = options.mode || "mixed";
1326
+ const flags = [];
1327
+ const parts = ["git", "reset"];
1328
+ if (options.file) {
1329
+ parts.push(ref, "--", String(options.file));
1330
+ return { command: parts.join(" "), explanation: `Resets the file "${options.file}" to ${ref}`, flags };
1331
+ }
1332
+ flags.push(`--${mode}`);
1333
+ parts.push(`--${mode}`, ref);
1334
+ return { command: parts.join(" "), explanation: `Resets HEAD to ${ref} using ${mode} mode`, flags };
1335
+ }
1336
+ case "cherry-pick": {
1337
+ if (!options.commit) {
1338
+ return { error: "cherry-pick requires a commit" };
1339
+ }
1340
+ const flags = [];
1341
+ const parts = ["git", "cherry-pick"];
1342
+ if (options.noCommit) {
1343
+ flags.push("-n");
1344
+ parts.push("-n");
1345
+ }
1346
+ parts.push(String(options.commit));
1347
+ return {
1348
+ command: parts.join(" "),
1349
+ explanation: `Applies the changes from commit "${options.commit}"${options.noCommit ? " without creating a new commit" : ""}`,
1350
+ flags
1351
+ };
1352
+ }
1353
+ case "log": {
1354
+ const flags = [];
1355
+ const parts = ["git", "log"];
1356
+ if (options.graph) {
1357
+ flags.push("--graph");
1358
+ parts.push("--graph");
1359
+ }
1360
+ if (options.oneline) {
1361
+ flags.push("--oneline");
1362
+ parts.push("--oneline");
1363
+ }
1364
+ if (options.count !== void 0) {
1365
+ flags.push("-n");
1366
+ parts.push(`-n ${options.count}`);
1367
+ }
1368
+ if (options.author) {
1369
+ flags.push("--author");
1370
+ parts.push(`--author="${options.author}"`);
1371
+ }
1372
+ if (options.since) {
1373
+ flags.push("--since");
1374
+ parts.push(`--since="${options.since}"`);
1375
+ }
1376
+ return {
1377
+ command: parts.join(" "),
1378
+ explanation: `Shows commit history${options.oneline ? " in condensed format" : ""}${options.count !== void 0 ? `, limited to ${options.count} commits` : ""}${options.author ? ` by "${options.author}"` : ""}${options.since ? ` since "${options.since}"` : ""}`,
1379
+ flags
1380
+ };
1381
+ }
1382
+ case "diff": {
1383
+ const flags = [];
1384
+ const parts = ["git", "diff"];
1385
+ if (options.cached) {
1386
+ flags.push("--cached");
1387
+ parts.push("--cached");
1388
+ }
1389
+ if (options.stat) {
1390
+ flags.push("--stat");
1391
+ parts.push("--stat");
1392
+ }
1393
+ if (options.ref1) {
1394
+ parts.push(String(options.ref1));
1395
+ }
1396
+ if (options.ref2) {
1397
+ parts.push(String(options.ref2));
1398
+ }
1399
+ if (options.file) {
1400
+ parts.push("--", String(options.file));
1401
+ }
1402
+ return {
1403
+ command: parts.join(" "),
1404
+ explanation: `Shows differences${options.cached ? " between index and last commit" : ""}${options.ref1 ? ` for ${options.ref1}${options.ref2 ? `..${options.ref2}` : ""}` : ""}${options.file ? ` in file "${options.file}"` : ""}`,
1405
+ flags
1406
+ };
1407
+ }
1408
+ case "clone": {
1409
+ if (!options.url) {
1410
+ return { error: "clone requires a url" };
1411
+ }
1412
+ const flags = [];
1413
+ const parts = ["git", "clone"];
1414
+ if (options.depth !== void 0) {
1415
+ flags.push("--depth");
1416
+ parts.push(`--depth ${options.depth}`);
1417
+ }
1418
+ if (options.branch) {
1419
+ flags.push("-b");
1420
+ parts.push(`-b ${options.branch}`);
1421
+ }
1422
+ parts.push(String(options.url));
1423
+ if (options.directory) {
1424
+ parts.push(String(options.directory));
1425
+ }
1426
+ return {
1427
+ command: parts.join(" "),
1428
+ explanation: `Clones the repository at "${options.url}"${options.directory ? ` into "${options.directory}"` : ""}${options.branch ? ` on branch "${options.branch}"` : ""}${options.depth !== void 0 ? ` with depth ${options.depth}` : ""}`,
1429
+ flags
1430
+ };
1431
+ }
1432
+ case "push": {
1433
+ const remote = options.remote || "origin";
1434
+ const flags = [];
1435
+ const parts = ["git", "push"];
1436
+ if (options.force) {
1437
+ flags.push("--force");
1438
+ parts.push("--force");
1439
+ }
1440
+ if (options.setUpstream) {
1441
+ flags.push("-u");
1442
+ parts.push("-u");
1443
+ }
1444
+ if (options.tags) {
1445
+ flags.push("--tags");
1446
+ parts.push("--tags");
1447
+ }
1448
+ parts.push(remote);
1449
+ if (options.branch) {
1450
+ parts.push(String(options.branch));
1451
+ }
1452
+ return {
1453
+ command: parts.join(" "),
1454
+ explanation: `Pushes to remote "${remote}"${options.branch ? ` branch "${options.branch}"` : ""}${options.force ? " (force push)" : ""}${options.setUpstream ? ", setting upstream tracking" : ""}`,
1455
+ flags
1456
+ };
1457
+ }
1458
+ case "pull": {
1459
+ const remote = options.remote || "origin";
1460
+ const flags = [];
1461
+ const parts = ["git", "pull"];
1462
+ if (options.rebase) {
1463
+ flags.push("--rebase");
1464
+ parts.push("--rebase");
1465
+ }
1466
+ parts.push(remote);
1467
+ if (options.branch) {
1468
+ parts.push(String(options.branch));
1469
+ }
1470
+ return {
1471
+ command: parts.join(" "),
1472
+ explanation: `Pulls from remote "${remote}"${options.branch ? ` branch "${options.branch}"` : ""}${options.rebase ? " using rebase" : ""}`,
1473
+ flags
1474
+ };
1475
+ }
1476
+ case "fetch": {
1477
+ const remote = options.remote || "origin";
1478
+ const flags = [];
1479
+ const parts = ["git", "fetch"];
1480
+ if (options.all) {
1481
+ flags.push("--all");
1482
+ parts.push("--all");
1483
+ } else {
1484
+ parts.push(remote);
1485
+ }
1486
+ if (options.prune) {
1487
+ flags.push("--prune");
1488
+ parts.push("--prune");
1489
+ }
1490
+ if (options.tags) {
1491
+ flags.push("--tags");
1492
+ parts.push("--tags");
1493
+ }
1494
+ return {
1495
+ command: parts.join(" "),
1496
+ explanation: `Fetches from ${options.all ? "all remotes" : `remote "${remote}"`}${options.prune ? ", pruning deleted remote branches" : ""}${options.tags ? ", including tags" : ""}`,
1497
+ flags
1498
+ };
1499
+ }
1500
+ default:
1501
+ return { error: `Unknown operation: ${operation}` };
1502
+ }
1503
+ }
1504
+ function parseGitCommand(command) {
1505
+ const trimmed = command.trim();
1506
+ if (!trimmed.startsWith("git ")) {
1507
+ return { error: "Not a git command" };
1508
+ }
1509
+ const tokens = trimmed.split(/\s+/);
1510
+ const op = tokens[1];
1511
+ const validOps = [
1512
+ "commit",
1513
+ "branch",
1514
+ "checkout",
1515
+ "merge",
1516
+ "rebase",
1517
+ "stash",
1518
+ "tag",
1519
+ "remote",
1520
+ "reset",
1521
+ "cherry-pick",
1522
+ "log",
1523
+ "diff",
1524
+ "clone",
1525
+ "push",
1526
+ "pull",
1527
+ "fetch"
1528
+ ];
1529
+ if (!validOps.includes(op)) {
1530
+ return { error: "Unknown operation" };
1531
+ }
1532
+ const options = {};
1533
+ const rest = tokens.slice(2);
1534
+ switch (op) {
1535
+ case "log": {
1536
+ for (let i = 0; i < rest.length; i++) {
1537
+ if (rest[i] === "--oneline") options.oneline = true;
1538
+ else if (rest[i] === "--graph") options.graph = true;
1539
+ else if (rest[i] === "-n" && rest[i + 1]) options.count = Number(rest[++i]);
1540
+ else if (rest[i].startsWith("--author=")) options.author = rest[i].replace("--author=", "").replace(/^"|"$/g, "");
1541
+ else if (rest[i].startsWith("--since=")) options.since = rest[i].replace("--since=", "").replace(/^"|"$/g, "");
1542
+ }
1543
+ break;
1544
+ }
1545
+ case "commit": {
1546
+ for (let i = 0; i < rest.length; i++) {
1547
+ if (rest[i] === "--amend") options.amend = true;
1548
+ else if (rest[i] === "--no-verify") options.noVerify = true;
1549
+ else if (rest[i] === "-a" || rest[i] === "--all") options.all = true;
1550
+ else if ((rest[i] === "-m" || rest[i] === "--message") && rest[i + 1]) options.message = rest[++i].replace(/^"|"$/g, "");
1551
+ }
1552
+ break;
1553
+ }
1554
+ case "push": {
1555
+ const positional = [];
1556
+ for (let i = 0; i < rest.length; i++) {
1557
+ if (rest[i] === "--force") options.force = true;
1558
+ else if (rest[i] === "-u" || rest[i] === "--set-upstream") options.setUpstream = true;
1559
+ else if (rest[i] === "--tags") options.tags = true;
1560
+ else if (!rest[i].startsWith("-")) positional.push(rest[i]);
1561
+ }
1562
+ if (positional[0]) options.remote = positional[0];
1563
+ if (positional[1]) options.branch = positional[1];
1564
+ break;
1565
+ }
1566
+ case "pull": {
1567
+ const positional = [];
1568
+ for (let i = 0; i < rest.length; i++) {
1569
+ if (rest[i] === "--rebase") options.rebase = true;
1570
+ else if (!rest[i].startsWith("-")) positional.push(rest[i]);
1571
+ }
1572
+ if (positional[0]) options.remote = positional[0];
1573
+ if (positional[1]) options.branch = positional[1];
1574
+ break;
1575
+ }
1576
+ case "fetch": {
1577
+ const positional = [];
1578
+ for (let i = 0; i < rest.length; i++) {
1579
+ if (rest[i] === "--all") options.all = true;
1580
+ else if (rest[i] === "--prune" || rest[i] === "-p") options.prune = true;
1581
+ else if (rest[i] === "--tags") options.tags = true;
1582
+ else if (!rest[i].startsWith("-")) positional.push(rest[i]);
1583
+ }
1584
+ if (positional[0]) options.remote = positional[0];
1585
+ break;
1586
+ }
1587
+ case "checkout": {
1588
+ for (let i = 0; i < rest.length; i++) {
1589
+ if (rest[i] === "-b") options.newBranch = true;
1590
+ else if (rest[i] === "--" && rest[i + 1]) options.file = rest[++i];
1591
+ else if (!rest[i].startsWith("-")) options.branch = rest[i];
1592
+ }
1593
+ break;
1594
+ }
1595
+ case "branch": {
1596
+ const positional = [];
1597
+ for (let i = 0; i < rest.length; i++) {
1598
+ if (rest[i] === "-d") {
1599
+ options.action = "delete";
1600
+ } else if (rest[i] === "-D") {
1601
+ options.action = "delete";
1602
+ options.force = true;
1603
+ } else if (rest[i] === "-m") {
1604
+ options.action = "rename";
1605
+ if (rest[i + 1]) positional.push(rest[++i]);
1606
+ if (rest[i + 1]) positional.push(rest[++i]);
1607
+ } else if (!rest[i].startsWith("-")) positional.push(rest[i]);
1608
+ }
1609
+ if (!options.action) {
1610
+ options.action = positional.length > 0 ? "create" : "list";
1611
+ }
1612
+ if (positional[0]) options.name = positional[0];
1613
+ if (positional[1]) options.newName = positional[1];
1614
+ break;
1615
+ }
1616
+ case "merge": {
1617
+ const positional = [];
1618
+ for (let i = 0; i < rest.length; i++) {
1619
+ if (rest[i] === "--no-ff") options.noFF = true;
1620
+ else if (rest[i] === "--squash") options.squash = true;
1621
+ else if ((rest[i] === "-m" || rest[i] === "--message") && rest[i + 1]) options.message = rest[++i].replace(/^"|"$/g, "");
1622
+ else if (!rest[i].startsWith("-")) positional.push(rest[i]);
1623
+ }
1624
+ if (positional[0]) options.branch = positional[0];
1625
+ break;
1626
+ }
1627
+ case "rebase": {
1628
+ const positional = [];
1629
+ for (let i = 0; i < rest.length; i++) {
1630
+ if (rest[i] === "-i" || rest[i] === "--interactive") options.interactive = true;
1631
+ else if (rest[i] === "--onto" && rest[i + 1]) options.onto = rest[++i];
1632
+ else if (!rest[i].startsWith("-")) positional.push(rest[i]);
1633
+ }
1634
+ if (positional[0]) options.branch = positional[0];
1635
+ break;
1636
+ }
1637
+ case "reset": {
1638
+ const positional = [];
1639
+ for (let i = 0; i < rest.length; i++) {
1640
+ if (rest[i] === "--soft") options.mode = "soft";
1641
+ else if (rest[i] === "--mixed") options.mode = "mixed";
1642
+ else if (rest[i] === "--hard") options.mode = "hard";
1643
+ else if (rest[i] === "--" && rest[i + 1]) options.file = rest[++i];
1644
+ else if (!rest[i].startsWith("-")) positional.push(rest[i]);
1645
+ }
1646
+ if (positional[0]) options.ref = positional[0];
1647
+ break;
1648
+ }
1649
+ case "stash": {
1650
+ if (rest[0] === "pop") options.action = "pop";
1651
+ else if (rest[0] === "list") options.action = "list";
1652
+ else if (rest[0] === "drop") options.action = "drop";
1653
+ else if (rest[0] === "apply") options.action = "apply";
1654
+ else options.action = "push";
1655
+ break;
1656
+ }
1657
+ case "tag": {
1658
+ const positional = [];
1659
+ for (let i = 0; i < rest.length; i++) {
1660
+ if (rest[i] === "-d") options.delete = true;
1661
+ else if ((rest[i] === "-m" || rest[i] === "--message") && rest[i + 1]) options.message = rest[++i].replace(/^"|"$/g, "");
1662
+ else if (!rest[i].startsWith("-")) positional.push(rest[i]);
1663
+ }
1664
+ if (positional[0]) options.name = positional[0];
1665
+ if (positional[1]) options.ref = positional[1];
1666
+ break;
1667
+ }
1668
+ case "clone": {
1669
+ const positional = [];
1670
+ for (let i = 0; i < rest.length; i++) {
1671
+ if (rest[i] === "--depth" && rest[i + 1]) options.depth = Number(rest[++i]);
1672
+ else if ((rest[i] === "-b" || rest[i] === "--branch") && rest[i + 1]) options.branch = rest[++i];
1673
+ else if (!rest[i].startsWith("-")) positional.push(rest[i]);
1674
+ }
1675
+ if (positional[0]) options.url = positional[0];
1676
+ if (positional[1]) options.directory = positional[1];
1677
+ break;
1678
+ }
1679
+ case "diff": {
1680
+ const positional = [];
1681
+ for (let i = 0; i < rest.length; i++) {
1682
+ if (rest[i] === "--cached") options.cached = true;
1683
+ else if (rest[i] === "--stat") options.stat = true;
1684
+ else if (rest[i] === "--" && rest[i + 1]) options.file = rest[++i];
1685
+ else if (!rest[i].startsWith("-")) positional.push(rest[i]);
1686
+ }
1687
+ if (positional[0]) options.ref1 = positional[0];
1688
+ if (positional[1]) options.ref2 = positional[1];
1689
+ break;
1690
+ }
1691
+ case "cherry-pick": {
1692
+ for (let i = 0; i < rest.length; i++) {
1693
+ if (rest[i] === "-n" || rest[i] === "--no-commit") options.noCommit = true;
1694
+ else if (!rest[i].startsWith("-")) options.commit = rest[i];
1695
+ }
1696
+ break;
1697
+ }
1698
+ case "remote": {
1699
+ if (rest[0] === "add") {
1700
+ options.action = "add";
1701
+ options.name = rest[1];
1702
+ options.url = rest[2];
1703
+ } else if (rest[0] === "remove") {
1704
+ options.action = "remove";
1705
+ options.name = rest[1];
1706
+ } else if (rest[0] === "rename") {
1707
+ options.action = "rename";
1708
+ options.name = rest[1];
1709
+ options.newName = rest[2];
1710
+ } else options.action = "list";
1711
+ break;
1712
+ }
1713
+ }
1714
+ return { operation: op, options };
1715
+ }
1716
+ var OFFICIAL_REGISTRY = "docker.io";
1717
+ var OFFICIAL_NAMESPACE = "library";
1718
+ var DEFAULT_DOCKER_TAG = "latest";
1719
+ function parseDockerImage(ref) {
1720
+ if (!ref || typeof ref !== "string" || ref.trim() === "") {
1721
+ return { error: "Empty image reference" };
1722
+ }
1723
+ const trimmed = ref.trim();
1724
+ if (/\s/.test(trimmed)) {
1725
+ return { error: "Image reference must not contain whitespace" };
1726
+ }
1727
+ let registry = OFFICIAL_REGISTRY;
1728
+ let namespace = "";
1729
+ let repository = "";
1730
+ let tag = DEFAULT_DOCKER_TAG;
1731
+ let digest = "";
1732
+ let remaining = trimmed;
1733
+ const digestIdx = remaining.indexOf("@");
1734
+ if (digestIdx !== -1) {
1735
+ digest = remaining.slice(digestIdx + 1);
1736
+ remaining = remaining.slice(0, digestIdx);
1737
+ if (!/^sha256:[a-fA-F0-9]+$/.test(digest)) {
1738
+ return { error: `Invalid digest format: ${digest}` };
1739
+ }
1740
+ tag = "";
1741
+ }
1742
+ const tagIdx = remaining.indexOf(":");
1743
+ if (tagIdx !== -1) {
1744
+ const potentialTag = remaining.slice(tagIdx + 1);
1745
+ const potentialHost = remaining.slice(0, tagIdx);
1746
+ const looksLikeHost = /^(localhost|[a-zA-Z0-9-]+\.[a-zA-Z0-9-]+)$/.test(potentialHost);
1747
+ if (!looksLikeHost || remaining.slice(tagIdx + 1).includes("/")) {
1748
+ const slashAfterColon = remaining.indexOf("/", tagIdx);
1749
+ if (slashAfterColon === -1) {
1750
+ tag = potentialTag;
1751
+ remaining = potentialHost;
1752
+ }
1753
+ }
1754
+ }
1755
+ const parts = remaining.split("/");
1756
+ if (parts.length === 1) {
1757
+ registry = OFFICIAL_REGISTRY;
1758
+ namespace = OFFICIAL_NAMESPACE;
1759
+ repository = parts[0];
1760
+ } else if (parts.length === 2) {
1761
+ const firstPart = parts[0];
1762
+ if (firstPart.includes(".") || firstPart.includes(":") || firstPart === "localhost") {
1763
+ registry = firstPart;
1764
+ namespace = "";
1765
+ repository = parts[1];
1766
+ } else {
1767
+ registry = OFFICIAL_REGISTRY;
1768
+ namespace = firstPart;
1769
+ repository = parts[1];
1770
+ }
1771
+ } else {
1772
+ const firstPart = parts[0];
1773
+ if (firstPart.includes(".") || firstPart.includes(":") || firstPart === "localhost") {
1774
+ registry = firstPart;
1775
+ namespace = parts[1];
1776
+ repository = parts.slice(2).join("/");
1777
+ } else {
1778
+ registry = OFFICIAL_REGISTRY;
1779
+ namespace = parts[0];
1780
+ repository = parts.slice(1).join("/");
1781
+ }
1782
+ }
1783
+ if (repository.includes(":") && tag === DEFAULT_DOCKER_TAG && digest === "") {
1784
+ const repoTagIdx = repository.lastIndexOf(":");
1785
+ tag = repository.slice(repoTagIdx + 1);
1786
+ repository = repository.slice(0, repoTagIdx);
1787
+ }
1788
+ if (!repository) {
1789
+ return { error: "Could not determine repository name" };
1790
+ }
1791
+ if (tag && !isValidTag(tag)) {
1792
+ return { error: `Invalid tag: ${tag}` };
1793
+ }
1794
+ if (digest && tag === DEFAULT_DOCKER_TAG) {
1795
+ tag = "";
1796
+ }
1797
+ const isOfficial = registry === OFFICIAL_REGISTRY && namespace === OFFICIAL_NAMESPACE;
1798
+ return {
1799
+ registry,
1800
+ namespace,
1801
+ repository,
1802
+ tag: tag || (digest ? "" : DEFAULT_DOCKER_TAG),
1803
+ digest,
1804
+ isOfficial
1805
+ };
1806
+ }
1807
+ function buildDockerImageRef(parsed) {
1808
+ let ref = "";
1809
+ if (parsed.registry === OFFICIAL_REGISTRY && parsed.namespace === OFFICIAL_NAMESPACE) {
1810
+ ref = parsed.repository;
1811
+ } else if (parsed.registry === OFFICIAL_REGISTRY) {
1812
+ ref = parsed.namespace ? `${parsed.namespace}/${parsed.repository}` : parsed.repository;
1813
+ } else {
1814
+ if (parsed.namespace) {
1815
+ ref = `${parsed.registry}/${parsed.namespace}/${parsed.repository}`;
1816
+ } else {
1817
+ ref = `${parsed.registry}/${parsed.repository}`;
1818
+ }
1819
+ }
1820
+ if (parsed.digest) {
1821
+ ref += `@${parsed.digest}`;
1822
+ } else if (parsed.tag) {
1823
+ ref += `:${parsed.tag}`;
1824
+ }
1825
+ return ref;
1826
+ }
1827
+ function buildDockerPull(parsed) {
1828
+ return `docker pull ${buildDockerImageRef(parsed)}`;
1829
+ }
1830
+ function buildDockerRun(parsed, containerName) {
1831
+ const image = buildDockerImageRef(parsed);
1832
+ const name = containerName ?? parsed.repository.replace(/[^a-zA-Z0-9_.-]/g, "-");
1833
+ return `docker run -d --name ${name} ${image}`;
1834
+ }
1835
+ function isValidTag(tag) {
1836
+ if (!tag || tag.length === 0 || tag.length > 128) return false;
1837
+ if (tag.startsWith(".") || tag.startsWith("-")) return false;
1838
+ return /^[a-zA-Z0-9._-]+$/.test(tag);
1839
+ }
1840
+ function normalizeRef(ref) {
1841
+ const parsed = parseDockerImage(ref);
1842
+ if ("error" in parsed) return ref;
1843
+ const ns = parsed.namespace ? `${parsed.namespace}/` : "";
1844
+ const tagPart = parsed.digest ? `@${parsed.digest}` : parsed.tag ? `:${parsed.tag}` : "";
1845
+ return `${parsed.registry}/${ns}${parsed.repository}${tagPart}`;
1846
+ }
1847
+ function removeJsComments(code) {
1848
+ let result = "";
1849
+ let i = 0;
1850
+ while (i < code.length) {
1851
+ if (code[i] === '"' || code[i] === "'" || code[i] === "`") {
1852
+ const quote = code[i];
1853
+ result += code[i++];
1854
+ while (i < code.length) {
1855
+ if (code[i] === "\\") {
1856
+ result += code[i++];
1857
+ if (i < code.length) result += code[i++];
1858
+ continue;
1859
+ }
1860
+ result += code[i];
1861
+ if (code[i] === quote) {
1862
+ i++;
1863
+ break;
1864
+ }
1865
+ i++;
1866
+ }
1867
+ continue;
1868
+ }
1869
+ if (code[i] === "/" && code[i + 1] === "/") {
1870
+ while (i < code.length && code[i] !== "\n") i++;
1871
+ continue;
1872
+ }
1873
+ if (code[i] === "/" && code[i + 1] === "*") {
1874
+ i += 2;
1875
+ while (i < code.length) {
1876
+ if (code[i] === "*" && code[i + 1] === "/") {
1877
+ i += 2;
1878
+ break;
1879
+ }
1880
+ i++;
1881
+ }
1882
+ continue;
1883
+ }
1884
+ result += code[i++];
1885
+ }
1886
+ return result;
1887
+ }
1888
+ function collapseJsWhitespace(code) {
1889
+ let result = code.replace(/[ \t]+/g, " ");
1890
+ result = result.replace(/\n{2,}/g, "\n");
1891
+ result = result.split("\n").map((line) => line.trim()).join("\n");
1892
+ result = result.replace(/^\n+|\n+$/g, "").trim();
1893
+ return result;
1894
+ }
1895
+ function removeConsoleCalls(code) {
1896
+ return code.replace(/console\.(log|warn|error|debug|info)\s*\([^)]*\)\s*;?/g, "");
1897
+ }
1898
+ function getJsStats(code) {
1899
+ const lines = code.split("\n").length;
1900
+ const chars = code.length;
1901
+ const functions = (code.match(/\bfunction\b/g) ?? []).length;
1902
+ const variables = (code.match(/\b(var|let|const)\b/g) ?? []).length;
1903
+ return { lines, chars, functions, variables };
1904
+ }
1905
+ function minifyJs(code, options) {
1906
+ const opts = {
1907
+ removeComments: options?.removeComments ?? true,
1908
+ collapseWhitespace: options?.collapseWhitespace ?? true,
1909
+ removeConsole: options?.removeConsole ?? false,
1910
+ removeSemicolons: options?.removeSemicolons ?? false,
1911
+ mangle: options?.mangle ?? false
1912
+ };
1913
+ const originalSize = code.length;
1914
+ let minified = code;
1915
+ if (opts.removeComments) minified = removeJsComments(minified);
1916
+ if (opts.removeConsole) minified = removeConsoleCalls(minified);
1917
+ if (opts.collapseWhitespace) minified = collapseJsWhitespace(minified);
1918
+ if (opts.removeSemicolons) {
1919
+ minified = minified.replace(/;\s*}/g, "}");
1920
+ minified = minified.replace(/;(\s*\n)/g, "$1");
1921
+ }
1922
+ minified = minified.trim();
1923
+ const minifiedSize = minified.length;
1924
+ const savedBytes = originalSize - minifiedSize;
1925
+ const savedPercent = originalSize === 0 ? 0 : Math.round(savedBytes / originalSize * 100 * 100) / 100;
1926
+ return { original: code, minified, originalSize, minifiedSize, savedBytes, savedPercent };
1927
+ }
1928
+ var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
1929
+ function detectSpecVersion(raw) {
1930
+ if (typeof raw.openapi === "string" && raw.openapi.startsWith("3")) return "openapi-3";
1931
+ if (typeof raw.swagger === "string" && raw.swagger.startsWith("2")) return "swagger-2";
1932
+ return "unknown";
1933
+ }
1934
+ function parseOpenApi3Endpoints(raw) {
1935
+ const endpoints = [];
1936
+ const paths = raw.paths ?? {};
1937
+ for (const [path, pathItem] of Object.entries(paths)) {
1938
+ if (!pathItem || typeof pathItem !== "object") continue;
1939
+ const pi = pathItem;
1940
+ for (const method of HTTP_METHODS) {
1941
+ const op = pi[method.toLowerCase()];
1942
+ if (!op) continue;
1943
+ const parameters = [];
1944
+ const rawParams = op.parameters ?? [];
1945
+ for (const p of rawParams) {
1946
+ if (!p || typeof p !== "object") continue;
1947
+ const param = p;
1948
+ parameters.push({
1949
+ name: String(param.name ?? ""),
1950
+ in: String(param.in ?? ""),
1951
+ required: Boolean(param.required ?? false),
1952
+ description: param.description !== void 0 ? String(param.description) : void 0,
1953
+ schema: param.schema
1954
+ });
1955
+ }
1956
+ let requestBody;
1957
+ if (op.requestBody && typeof op.requestBody === "object") {
1958
+ const rb = op.requestBody;
1959
+ const content = rb.content ?? {};
1960
+ requestBody = { required: Boolean(rb.required ?? false), contentTypes: Object.keys(content) };
1961
+ }
1962
+ const responses = {};
1963
+ const rawResponses = op.responses ?? {};
1964
+ for (const [statusCode, resp] of Object.entries(rawResponses)) {
1965
+ if (!resp || typeof resp !== "object") continue;
1966
+ const r = resp;
1967
+ const content = r.content ?? {};
1968
+ responses[statusCode] = { description: String(r.description ?? ""), contentTypes: Object.keys(content) };
1969
+ }
1970
+ endpoints.push({
1971
+ method,
1972
+ path,
1973
+ summary: op.summary !== void 0 ? String(op.summary) : void 0,
1974
+ description: op.description !== void 0 ? String(op.description) : void 0,
1975
+ tags: Array.isArray(op.tags) ? op.tags.map(String) : [],
1976
+ parameters,
1977
+ requestBody,
1978
+ responses,
1979
+ deprecated: Boolean(op.deprecated ?? false)
1980
+ });
1981
+ }
1982
+ }
1983
+ return endpoints;
1984
+ }
1985
+ function parseSwagger2Endpoints(raw) {
1986
+ const endpoints = [];
1987
+ const paths = raw.paths ?? {};
1988
+ for (const [path, pathItem] of Object.entries(paths)) {
1989
+ if (!pathItem || typeof pathItem !== "object") continue;
1990
+ const pi = pathItem;
1991
+ for (const method of HTTP_METHODS) {
1992
+ const op = pi[method.toLowerCase()];
1993
+ if (!op) continue;
1994
+ const parameters = [];
1995
+ const rawParams = op.parameters ?? [];
1996
+ let requestBody;
1997
+ for (const p of rawParams) {
1998
+ if (!p || typeof p !== "object") continue;
1999
+ const param = p;
2000
+ if (param.in === "body") {
2001
+ const consumes = Array.isArray(op.consumes) ? op.consumes.map(String) : Array.isArray(raw.consumes) ? raw.consumes.map(String) : ["application/json"];
2002
+ requestBody = { required: Boolean(param.required ?? false), contentTypes: consumes };
2003
+ } else {
2004
+ parameters.push({
2005
+ name: String(param.name ?? ""),
2006
+ in: String(param.in ?? ""),
2007
+ required: Boolean(param.required ?? false),
2008
+ description: param.description !== void 0 ? String(param.description) : void 0,
2009
+ schema: param.schema
2010
+ });
2011
+ }
2012
+ }
2013
+ const responses = {};
2014
+ const rawResponses = op.responses ?? {};
2015
+ for (const [statusCode, resp] of Object.entries(rawResponses)) {
2016
+ if (!resp || typeof resp !== "object") continue;
2017
+ const r = resp;
2018
+ const produces = Array.isArray(op.produces) ? op.produces.map(String) : Array.isArray(raw.produces) ? raw.produces.map(String) : [];
2019
+ responses[statusCode] = { description: String(r.description ?? ""), contentTypes: produces };
2020
+ }
2021
+ endpoints.push({
2022
+ method,
2023
+ path,
2024
+ summary: op.summary !== void 0 ? String(op.summary) : void 0,
2025
+ description: op.description !== void 0 ? String(op.description) : void 0,
2026
+ tags: Array.isArray(op.tags) ? op.tags.map(String) : [],
2027
+ parameters,
2028
+ requestBody,
2029
+ responses,
2030
+ deprecated: Boolean(op.deprecated ?? false)
2031
+ });
2032
+ }
2033
+ }
2034
+ return endpoints;
2035
+ }
2036
+ function extractBaseUrl(raw, version) {
2037
+ if (version === "openapi-3") {
2038
+ const servers = raw.servers;
2039
+ if (Array.isArray(servers) && servers.length > 0) return String(servers[0].url ?? "");
2040
+ return void 0;
2041
+ }
2042
+ if (version === "swagger-2") {
2043
+ const scheme = Array.isArray(raw.schemes) ? raw.schemes[0] : "https";
2044
+ const host = raw.host ? String(raw.host) : void 0;
2045
+ const basePath = raw.basePath ? String(raw.basePath) : "";
2046
+ if (host) return `${scheme}://${host}${basePath}`;
2047
+ return basePath || void 0;
2048
+ }
2049
+ return void 0;
2050
+ }
2051
+ function extractSchemas(raw, version) {
2052
+ if (version === "openapi-3") {
2053
+ const components = raw.components;
2054
+ const schemas = components?.schemas;
2055
+ return schemas ? Object.keys(schemas) : [];
2056
+ }
2057
+ if (version === "swagger-2") {
2058
+ const definitions = raw.definitions;
2059
+ return definitions ? Object.keys(definitions) : [];
2060
+ }
2061
+ return [];
2062
+ }
2063
+ function parseSpec(input) {
2064
+ if (!input.trim()) return { error: "Empty input" };
2065
+ let raw;
2066
+ try {
2067
+ raw = JSON.parse(input);
2068
+ } catch {
2069
+ try {
2070
+ raw = load(input);
2071
+ } catch (e) {
2072
+ return { error: `Failed to parse input as JSON or YAML: ${String(e)}` };
2073
+ }
2074
+ }
2075
+ if (!raw || typeof raw !== "object") return { error: "Input did not parse to an object" };
2076
+ const version = detectSpecVersion(raw);
2077
+ const infoRaw = raw.info ?? {};
2078
+ const info = {
2079
+ title: String(infoRaw.title ?? "Untitled"),
2080
+ version: String(infoRaw.version ?? ""),
2081
+ description: infoRaw.description !== void 0 ? String(infoRaw.description) : void 0,
2082
+ baseUrl: extractBaseUrl(raw, version)
2083
+ };
2084
+ const endpoints = version === "openapi-3" ? parseOpenApi3Endpoints(raw) : version === "swagger-2" ? parseSwagger2Endpoints(raw) : [];
2085
+ const tagSet = /* @__PURE__ */ new Set();
2086
+ for (const ep of endpoints) {
2087
+ for (const t of ep.tags) tagSet.add(t);
2088
+ }
2089
+ const rawTags = raw.tags;
2090
+ if (Array.isArray(rawTags)) {
2091
+ for (const t of rawTags) {
2092
+ if (t.name) tagSet.add(String(t.name));
2093
+ }
2094
+ }
2095
+ return { version, info, endpoints, tags: [...tagSet], schemas: extractSchemas(raw, version) };
2096
+ }
2097
+ function getEndpointsByTag(spec, tag) {
2098
+ return spec.endpoints.filter((ep) => ep.tags.includes(tag));
2099
+ }
2100
+ function searchEndpoints(spec, query) {
2101
+ const q = query.toLowerCase();
2102
+ return spec.endpoints.filter(
2103
+ (ep) => ep.path.toLowerCase().includes(q) || ep.method.toLowerCase().includes(q) || (ep.summary ?? "").toLowerCase().includes(q) || (ep.description ?? "").toLowerCase().includes(q) || ep.tags.some((t) => t.toLowerCase().includes(q))
2104
+ );
2105
+ }
2106
+ function getMethodColor(method) {
2107
+ const colors = {
2108
+ GET: "green",
2109
+ POST: "blue",
2110
+ PUT: "amber",
2111
+ PATCH: "purple",
2112
+ DELETE: "red",
2113
+ HEAD: "gray",
2114
+ OPTIONS: "gray"
2115
+ };
2116
+ return colors[method.toUpperCase()] ?? "gray";
2117
+ }
2118
+ function parseEnv(input) {
2119
+ const entries = [];
2120
+ const comments = [];
2121
+ const errors = [];
2122
+ const keyCount = {};
2123
+ const rawLines = input.split("\n");
2124
+ const lines = [];
2125
+ let i = 0;
2126
+ while (i < rawLines.length) {
2127
+ let line = rawLines[i];
2128
+ while (line.endsWith("\\") && i + 1 < rawLines.length) {
2129
+ line = line.slice(0, -1) + rawLines[i + 1];
2130
+ i++;
2131
+ }
2132
+ lines.push(line);
2133
+ i++;
2134
+ }
2135
+ for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
2136
+ const lineNum = lineIdx + 1;
2137
+ const line = lines[lineIdx];
2138
+ const trimmed = line.trim();
2139
+ if (trimmed === "") continue;
2140
+ if (trimmed.startsWith("#")) {
2141
+ comments.push({ line: lineNum, text: trimmed.slice(1).trim() });
2142
+ continue;
2143
+ }
2144
+ const eqIdx = trimmed.indexOf("=");
2145
+ if (eqIdx === -1) {
2146
+ errors.push({ line: lineNum, message: `Invalid line: missing '='` });
2147
+ continue;
2148
+ }
2149
+ const key = trimmed.slice(0, eqIdx).trim();
2150
+ if (!validateEnvKey(key)) {
2151
+ errors.push({ line: lineNum, message: `Invalid key: '${key}'` });
2152
+ continue;
2153
+ }
2154
+ const rest = trimmed.slice(eqIdx + 1);
2155
+ let value = "";
2156
+ let hasQuotes = false;
2157
+ let inlineComment;
2158
+ if (rest.startsWith('"')) {
2159
+ hasQuotes = true;
2160
+ const closeIdx = rest.indexOf('"', 1);
2161
+ if (closeIdx === -1) {
2162
+ errors.push({ line: lineNum, message: `Unclosed double quote for key '${key}'` });
2163
+ continue;
2164
+ }
2165
+ value = rest.slice(1, closeIdx);
2166
+ const afterQuote = rest.slice(closeIdx + 1).trim();
2167
+ if (afterQuote.startsWith("#")) inlineComment = afterQuote.slice(1).trim();
2168
+ } else if (rest.startsWith("'")) {
2169
+ hasQuotes = true;
2170
+ const closeIdx = rest.indexOf("'", 1);
2171
+ if (closeIdx === -1) {
2172
+ errors.push({ line: lineNum, message: `Unclosed single quote for key '${key}'` });
2173
+ continue;
2174
+ }
2175
+ value = rest.slice(1, closeIdx);
2176
+ const afterQuote = rest.slice(closeIdx + 1).trim();
2177
+ if (afterQuote.startsWith("#")) inlineComment = afterQuote.slice(1).trim();
2178
+ } else {
2179
+ const hashIdx = rest.indexOf("#");
2180
+ if (hashIdx !== -1) {
2181
+ inlineComment = rest.slice(hashIdx + 1).trim();
2182
+ value = rest.slice(0, hashIdx).trim();
2183
+ } else {
2184
+ value = rest.trim();
2185
+ }
2186
+ }
2187
+ const interpolated = /\$\{[^}]+\}/.test(value);
2188
+ keyCount[key] = (keyCount[key] ?? 0) + 1;
2189
+ const entry = { key, value, line: lineNum, hasQuotes, interpolated };
2190
+ if (inlineComment !== void 0) entry.comment = inlineComment;
2191
+ entries.push(entry);
2192
+ }
2193
+ const duplicates = Object.entries(keyCount).filter(([, count]) => count > 1).map(([key]) => key);
2194
+ return { entries, comments, errors, duplicates };
2195
+ }
2196
+ function envToJson(input) {
2197
+ const result = parseEnv(input);
2198
+ if (result.errors.length > 0) {
2199
+ return { error: result.errors.map((e) => `Line ${e.line}: ${e.message}`).join("; ") };
2200
+ }
2201
+ const obj = {};
2202
+ for (const entry of result.entries) {
2203
+ obj[entry.key] = entry.value;
2204
+ }
2205
+ return JSON.stringify(obj, null, 2);
2206
+ }
2207
+ function envToExport(input) {
2208
+ const result = parseEnv(input);
2209
+ return result.entries.map((entry) => `export ${entry.key}="${entry.value.replace(/"/g, '\\"')}"`).join("\n");
2210
+ }
2211
+ function validateEnvKey(key) {
2212
+ return /^[A-Za-z_][A-Za-z0-9_]*$/.test(key);
2213
+ }
2214
+
2215
+ export { ALL_FLAGS, CHEATSHEET, OPERATIONS, SQL_DEFAULT_OPTIONS, buildDockerPull, buildDockerRun, buildGitCommand, code_exports, collapseHtmlWhitespace, collapseJsWhitespace, detectDialect, detectOperationType, envToExport, envToJson, formatGql, formatHtml, formatSql, getEndpointsByTag, getHtmlStats, getJsStats, getMethodColor, isValidTag, minifyGql, minifyHtml, minifyJs, minifySql, normalizeRef, parseDockerImage, parseEnv, parseGitCommand, parseSpec, removeConsoleCalls, removeEmptyAttributes, removeHtmlComments, removeJsComments, removeRedundantAttributes, searchCheatsheet, searchEndpoints, splitStatements, testPattern, testRegex, validateEnvKey };