norn-cli 2.3.0 → 2.4.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.
- package/.claude/skills/norn-social-campaign/SKILL.md +70 -0
- package/CHANGELOG.md +6 -0
- package/demos/nornenv-region-refactor/README.md +64 -0
- package/dist/cli.js +360 -1
- package/out/apiResponseIntellisenseCache.js +394 -0
- package/out/assertionRunner.js +567 -0
- package/out/cacheDir.js +136 -0
- package/out/chatParticipant.js +763 -0
- package/out/cli/colors.js +127 -0
- package/out/cli/formatters/assertion.js +102 -0
- package/out/cli/formatters/index.js +23 -0
- package/out/cli/formatters/response.js +106 -0
- package/out/cli/formatters/summary.js +246 -0
- package/out/cli/redaction.js +237 -0
- package/out/cli/reporters/html.js +689 -0
- package/out/cli/reporters/index.js +22 -0
- package/out/cli/reporters/junit.js +226 -0
- package/out/codeLensProvider.js +351 -0
- package/out/compareContentProvider.js +85 -0
- package/out/completionProvider.js +3739 -0
- package/out/contractAssertionSummary.js +225 -0
- package/out/contractDecorationProvider.js +243 -0
- package/out/coverageCalculator.js +879 -0
- package/out/coveragePanel.js +597 -0
- package/out/debug/breakpointResolver.js +84 -0
- package/out/debug/breakpoints.js +52 -0
- package/out/debug/nornDebugAdapter.js +166 -0
- package/out/debug/nornDebugSession.js +613 -0
- package/out/debug/sequenceLocationIndex.js +77 -0
- package/out/debug/types.js +3 -0
- package/out/deepClone.js +21 -0
- package/out/diagnosticProvider.js +2554 -0
- package/out/environmentParser.js +736 -0
- package/out/environmentProvider.js +544 -0
- package/out/environmentTemplates.js +146 -0
- package/out/errors/formatError.js +113 -0
- package/out/errors/nornError.js +29 -0
- package/out/formUrlEncoded.js +89 -0
- package/out/httpClient.js +348 -0
- package/out/httpRuntimeOptions.js +16 -0
- package/out/importErrors.js +31 -0
- package/out/inlayHintResolver.js +70 -0
- package/out/jsonFileReader.js +323 -0
- package/out/mcpClient.js +193 -0
- package/out/mcpConfig.js +184 -0
- package/out/mcpToolIntellisenseCache.js +96 -0
- package/out/mcpToolSchema.js +50 -0
- package/out/nornConfig.js +132 -0
- package/out/nornHoverProvider.js +124 -0
- package/out/nornInlayHintsProvider.js +191 -0
- package/out/nornPrompt.js +755 -0
- package/out/nornSqlParser.js +286 -0
- package/out/nornapiHoverProvider.js +135 -0
- package/out/nornapiInlayHintsProvider.js +94 -0
- package/out/nornapiParser.js +324 -0
- package/out/nornenvCodeActionProvider.js +101 -0
- package/out/nornenvDecorationProvider.js +239 -0
- package/out/nornenvFoldingProvider.js +63 -0
- package/out/nornenvHoverProvider.js +114 -0
- package/out/nornenvInlayHintsProvider.js +99 -0
- package/out/nornenvLanguageModel.js +187 -0
- package/out/nornenvRegionRefactor.js +267 -0
- package/out/nornsqlHoverProvider.js +95 -0
- package/out/nornsqlInlayHintsProvider.js +114 -0
- package/out/parser.js +839 -0
- package/out/pathAccess.js +28 -0
- package/out/postmanImportPanel.js +732 -0
- package/out/postmanImportPlanner.js +1155 -0
- package/out/postmanImportSidebarView.js +532 -0
- package/out/quotedString.js +35 -0
- package/out/requestPreparation.js +179 -0
- package/out/requestValidation.js +146 -0
- package/out/responsePanel.js +7754 -0
- package/out/schemaGenerator.js +562 -0
- package/out/scriptRunner.js +419 -0
- package/out/secrets/cliSecrets.js +415 -0
- package/out/secrets/crypto.js +105 -0
- package/out/secrets/envFileSecrets.js +177 -0
- package/out/secrets/keyStore.js +259 -0
- package/out/sequenceDeclaration.js +15 -0
- package/out/sequenceRunner.js +3590 -0
- package/out/sqlAdapterRunner.js +122 -0
- package/out/sqlBuiltInAdapters.js +604 -0
- package/out/sqlConfig.js +184 -0
- package/out/starterCatalog.js +554 -0
- package/out/stringUtils.js +25 -0
- package/out/swaggerBodyIntellisenseCache.js +114 -0
- package/out/swaggerParser.js +464 -0
- package/out/testProvider.js +767 -0
- package/out/theoryCaseLoader.js +113 -0
- package/out/validationCache.js +211 -0
- package/package.json +6 -1
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.parseApiResponseRequestLine = parseApiResponseRequestLine;
|
|
37
|
+
exports.parseApiResponseRequestText = parseApiResponseRequestText;
|
|
38
|
+
exports.saveApiResponseShapeForRequest = saveApiResponseShapeForRequest;
|
|
39
|
+
exports.getCachedApiResponseShapeForRequest = getCachedApiResponseShapeForRequest;
|
|
40
|
+
exports.getApiResponseShapeNodeAtPath = getApiResponseShapeNodeAtPath;
|
|
41
|
+
exports.getApiResponseShapeProperties = getApiResponseShapeProperties;
|
|
42
|
+
exports.getApiResponseShapeTypeSummary = getApiResponseShapeTypeSummary;
|
|
43
|
+
exports.parseApiResponseBodyPathForCompletion = parseApiResponseBodyPathForCompletion;
|
|
44
|
+
const crypto = __importStar(require("crypto"));
|
|
45
|
+
const path = __importStar(require("path"));
|
|
46
|
+
const cacheDir_1 = require("./cacheDir");
|
|
47
|
+
const stringUtils_1 = require("./stringUtils");
|
|
48
|
+
const CACHE_VERSION = 1;
|
|
49
|
+
const CACHE_FILE = 'api-response-intellisense.json';
|
|
50
|
+
const MAX_DEPTH = 6;
|
|
51
|
+
const MAX_OBJECT_PROPERTIES = 100;
|
|
52
|
+
const MAX_ARRAY_ITEMS = 20;
|
|
53
|
+
function removeRetryOptions(value) {
|
|
54
|
+
return value
|
|
55
|
+
.replace(/\bretry\s+\d+\b/ig, '')
|
|
56
|
+
.replace(/\bbackoff\s+\d+(?:\.\d+)?\s*(?:s|ms|seconds?|milliseconds?)?\b/ig, '')
|
|
57
|
+
.trim();
|
|
58
|
+
}
|
|
59
|
+
function normalizeQuotedTarget(target) {
|
|
60
|
+
const trimmed = target.trim();
|
|
61
|
+
if ((trimmed.startsWith('"') && trimmed.endsWith('"')) ||
|
|
62
|
+
(trimmed.startsWith('\'') && trimmed.endsWith('\''))) {
|
|
63
|
+
return trimmed.slice(1, -1).trim();
|
|
64
|
+
}
|
|
65
|
+
return trimmed;
|
|
66
|
+
}
|
|
67
|
+
function normalizeTargetForIdentity(target) {
|
|
68
|
+
return normalizeQuotedTarget(removeRetryOptions(target)).replace(/\s+/g, ' ').trim();
|
|
69
|
+
}
|
|
70
|
+
function hashTarget(target) {
|
|
71
|
+
return crypto.createHash('sha256').update(target).digest('hex').slice(0, 16);
|
|
72
|
+
}
|
|
73
|
+
function redactSensitiveTargetParts(target) {
|
|
74
|
+
let redacted = target.replace(/(https?:\/\/)([^/\s:@]+):([^/\s@]+)@/ig, '$1***@');
|
|
75
|
+
redacted = redacted.replace(/([?&][^=&\s]*(?:token|secret|password|passwd|pwd|key|auth|signature|sig)[^=&\s]*=)[^&\s]+/ig, '$1***');
|
|
76
|
+
redacted = redacted.replace(/\b(?:bearer|basic)\s+[a-z0-9._~+/=-]+/ig, match => `${match.split(/\s+/)[0]} ***`);
|
|
77
|
+
return redacted;
|
|
78
|
+
}
|
|
79
|
+
function normalizeEnvironment(environment) {
|
|
80
|
+
const trimmed = environment?.trim();
|
|
81
|
+
return trimmed ? trimmed : undefined;
|
|
82
|
+
}
|
|
83
|
+
function normalizeIdentity(identity) {
|
|
84
|
+
const rootPath = (0, cacheDir_1.findProjectRoot)(identity.sourceFile);
|
|
85
|
+
const absoluteSourceFile = path.resolve(identity.sourceFile);
|
|
86
|
+
const relativeSourceFile = path.relative(rootPath, absoluteSourceFile).replace(/\\/g, '/');
|
|
87
|
+
const target = normalizeTargetForIdentity(identity.target);
|
|
88
|
+
return {
|
|
89
|
+
rootPath,
|
|
90
|
+
sourceFile: relativeSourceFile || path.basename(absoluteSourceFile),
|
|
91
|
+
sourceLine: identity.sourceLine,
|
|
92
|
+
method: identity.method.toUpperCase(),
|
|
93
|
+
target,
|
|
94
|
+
targetHash: hashTarget(target),
|
|
95
|
+
environment: normalizeEnvironment(identity.environment)
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function buildCacheKey(identity) {
|
|
99
|
+
return [
|
|
100
|
+
identity.sourceFile,
|
|
101
|
+
identity.sourceLine === undefined ? '' : String(identity.sourceLine),
|
|
102
|
+
identity.method,
|
|
103
|
+
identity.targetHash,
|
|
104
|
+
identity.environment ?? ''
|
|
105
|
+
].map(encodeURIComponent).join('|');
|
|
106
|
+
}
|
|
107
|
+
function getCachePath(rootPath) {
|
|
108
|
+
return (0, cacheDir_1.getNornCacheFilePath)(rootPath, CACHE_FILE);
|
|
109
|
+
}
|
|
110
|
+
function loadCache(rootPath) {
|
|
111
|
+
return (0, cacheDir_1.loadVersionedJsonCache)({
|
|
112
|
+
cachePath: getCachePath(rootPath),
|
|
113
|
+
version: CACHE_VERSION,
|
|
114
|
+
createDefault: () => ({ version: CACHE_VERSION, entries: {} }),
|
|
115
|
+
isValid: cache => typeof cache.entries === 'object' && cache.entries !== null
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
function saveCache(rootPath, cache) {
|
|
119
|
+
return (0, cacheDir_1.saveVersionedJsonCache)(getCachePath(rootPath), cache, () => !!(0, cacheDir_1.ensureNornCacheDir)(rootPath));
|
|
120
|
+
}
|
|
121
|
+
function parseApiResponseRequestLine(line) {
|
|
122
|
+
const trimmed = (0, stringUtils_1.stripInlineComment)(line).trim();
|
|
123
|
+
const varMatch = trimmed.match(/^var\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s+(.+)$/i);
|
|
124
|
+
if (varMatch) {
|
|
125
|
+
return {
|
|
126
|
+
variableName: varMatch[1],
|
|
127
|
+
method: varMatch[2].toUpperCase(),
|
|
128
|
+
target: normalizeTargetForIdentity(varMatch[3])
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
const requestMatch = trimmed.match(/^(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s+(.+)$/i);
|
|
132
|
+
if (!requestMatch) {
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
method: requestMatch[1].toUpperCase(),
|
|
137
|
+
target: normalizeTargetForIdentity(requestMatch[2])
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
function parseApiResponseRequestText(requestText) {
|
|
141
|
+
const lines = requestText.split('\n');
|
|
142
|
+
for (let lineOffset = 0; lineOffset < lines.length; lineOffset++) {
|
|
143
|
+
const request = parseApiResponseRequestLine(lines[lineOffset]);
|
|
144
|
+
if (request) {
|
|
145
|
+
return { lineOffset, request };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
function getCacheableJsonRoot(responseBody) {
|
|
151
|
+
let candidate = responseBody;
|
|
152
|
+
if (typeof candidate === 'string') {
|
|
153
|
+
try {
|
|
154
|
+
candidate = JSON.parse(candidate);
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (candidate !== null && typeof candidate === 'object') {
|
|
161
|
+
return candidate;
|
|
162
|
+
}
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
function getPrimitiveShape(value) {
|
|
166
|
+
if (value === null) {
|
|
167
|
+
return { type: 'null' };
|
|
168
|
+
}
|
|
169
|
+
switch (typeof value) {
|
|
170
|
+
case 'string':
|
|
171
|
+
return { type: 'string' };
|
|
172
|
+
case 'number':
|
|
173
|
+
return { type: 'number' };
|
|
174
|
+
case 'boolean':
|
|
175
|
+
return { type: 'boolean' };
|
|
176
|
+
default:
|
|
177
|
+
return { type: 'unknown' };
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function buildShape(value, depth = 0) {
|
|
181
|
+
if (depth >= MAX_DEPTH) {
|
|
182
|
+
if (Array.isArray(value)) {
|
|
183
|
+
return { type: 'array', items: { type: 'unknown' } };
|
|
184
|
+
}
|
|
185
|
+
if (value !== null && typeof value === 'object') {
|
|
186
|
+
return { type: 'object', properties: {} };
|
|
187
|
+
}
|
|
188
|
+
return getPrimitiveShape(value);
|
|
189
|
+
}
|
|
190
|
+
if (Array.isArray(value)) {
|
|
191
|
+
const itemShapes = value
|
|
192
|
+
.slice(0, MAX_ARRAY_ITEMS)
|
|
193
|
+
.map(item => buildShape(item, depth + 1));
|
|
194
|
+
return {
|
|
195
|
+
type: 'array',
|
|
196
|
+
items: mergeShapes(itemShapes)
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
if (value !== null && typeof value === 'object') {
|
|
200
|
+
const properties = {};
|
|
201
|
+
const entries = Object.entries(value).slice(0, MAX_OBJECT_PROPERTIES);
|
|
202
|
+
for (const [name, propertyValue] of entries) {
|
|
203
|
+
properties[name] = buildShape(propertyValue, depth + 1);
|
|
204
|
+
}
|
|
205
|
+
return { type: 'object', properties };
|
|
206
|
+
}
|
|
207
|
+
return getPrimitiveShape(value);
|
|
208
|
+
}
|
|
209
|
+
function mergeObjectShapes(nodes) {
|
|
210
|
+
const propertyNames = new Set();
|
|
211
|
+
for (const node of nodes) {
|
|
212
|
+
for (const name of Object.keys(node.properties ?? {})) {
|
|
213
|
+
propertyNames.add(name);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
const properties = {};
|
|
217
|
+
for (const name of [...propertyNames].slice(0, MAX_OBJECT_PROPERTIES)) {
|
|
218
|
+
const propertyShapes = nodes
|
|
219
|
+
.map(node => node.properties?.[name])
|
|
220
|
+
.filter((node) => Boolean(node));
|
|
221
|
+
properties[name] = mergeShapes(propertyShapes);
|
|
222
|
+
}
|
|
223
|
+
return { type: 'object', properties };
|
|
224
|
+
}
|
|
225
|
+
function mergeArrayShapes(nodes) {
|
|
226
|
+
return {
|
|
227
|
+
type: 'array',
|
|
228
|
+
items: mergeShapes(nodes
|
|
229
|
+
.map(node => node.items)
|
|
230
|
+
.filter((node) => Boolean(node)))
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
function mergeShapes(nodes) {
|
|
234
|
+
if (nodes.length === 0) {
|
|
235
|
+
return { type: 'unknown' };
|
|
236
|
+
}
|
|
237
|
+
const hasNull = nodes.some(node => node.type === 'null');
|
|
238
|
+
const nonNullNodes = nodes.filter(node => node.type !== 'null');
|
|
239
|
+
const effectiveNodes = nonNullNodes.length > 0 ? nonNullNodes : nodes;
|
|
240
|
+
const firstType = effectiveNodes[0].type;
|
|
241
|
+
const sameType = effectiveNodes.every(node => node.type === firstType);
|
|
242
|
+
if (!sameType) {
|
|
243
|
+
return { type: 'unknown', nullable: hasNull || undefined };
|
|
244
|
+
}
|
|
245
|
+
let merged;
|
|
246
|
+
if (firstType === 'object') {
|
|
247
|
+
merged = mergeObjectShapes(effectiveNodes);
|
|
248
|
+
}
|
|
249
|
+
else if (firstType === 'array') {
|
|
250
|
+
merged = mergeArrayShapes(effectiveNodes);
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
merged = { type: firstType };
|
|
254
|
+
}
|
|
255
|
+
if (hasNull && merged.type !== 'null') {
|
|
256
|
+
merged.nullable = true;
|
|
257
|
+
}
|
|
258
|
+
return merged;
|
|
259
|
+
}
|
|
260
|
+
function saveApiResponseShapeForRequest(identity, responseBody) {
|
|
261
|
+
const root = getCacheableJsonRoot(responseBody);
|
|
262
|
+
if (root === undefined) {
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
const shape = buildShape(root);
|
|
266
|
+
if (shape.type !== 'object' && shape.type !== 'array') {
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
const normalizedIdentity = normalizeIdentity(identity);
|
|
270
|
+
const cache = loadCache(normalizedIdentity.rootPath);
|
|
271
|
+
const key = buildCacheKey(normalizedIdentity);
|
|
272
|
+
cache.entries[key] = {
|
|
273
|
+
method: normalizedIdentity.method,
|
|
274
|
+
target: redactSensitiveTargetParts(normalizedIdentity.target),
|
|
275
|
+
targetHash: normalizedIdentity.targetHash,
|
|
276
|
+
sourceFile: normalizedIdentity.sourceFile,
|
|
277
|
+
sourceLine: normalizedIdentity.sourceLine,
|
|
278
|
+
environment: normalizedIdentity.environment,
|
|
279
|
+
cachedAt: new Date().toISOString(),
|
|
280
|
+
shape
|
|
281
|
+
};
|
|
282
|
+
return saveCache(normalizedIdentity.rootPath, cache);
|
|
283
|
+
}
|
|
284
|
+
function findBestEntry(entries, identity) {
|
|
285
|
+
const exactLineEntries = entries.filter(entry => entry.sourceLine === identity.sourceLine);
|
|
286
|
+
const linePreferredEntries = exactLineEntries.length > 0 ? exactLineEntries : entries;
|
|
287
|
+
const exactEnvironment = identity.environment
|
|
288
|
+
? linePreferredEntries.find(entry => entry.environment === identity.environment)
|
|
289
|
+
: undefined;
|
|
290
|
+
if (exactEnvironment) {
|
|
291
|
+
return exactEnvironment;
|
|
292
|
+
}
|
|
293
|
+
const noEnvironment = linePreferredEntries.find(entry => !entry.environment);
|
|
294
|
+
if (noEnvironment) {
|
|
295
|
+
return noEnvironment;
|
|
296
|
+
}
|
|
297
|
+
return linePreferredEntries
|
|
298
|
+
.slice()
|
|
299
|
+
.sort((a, b) => b.cachedAt.localeCompare(a.cachedAt))[0];
|
|
300
|
+
}
|
|
301
|
+
function getCachedApiResponseShapeForRequest(identity) {
|
|
302
|
+
const normalizedIdentity = normalizeIdentity(identity);
|
|
303
|
+
const cache = loadCache(normalizedIdentity.rootPath);
|
|
304
|
+
const exactKey = buildCacheKey(normalizedIdentity);
|
|
305
|
+
const exactEntry = cache.entries[exactKey];
|
|
306
|
+
if (exactEntry) {
|
|
307
|
+
return exactEntry;
|
|
308
|
+
}
|
|
309
|
+
const candidates = Object.values(cache.entries).filter(entry => entry.sourceFile === normalizedIdentity.sourceFile &&
|
|
310
|
+
entry.method === normalizedIdentity.method &&
|
|
311
|
+
entry.targetHash === normalizedIdentity.targetHash);
|
|
312
|
+
return findBestEntry(candidates, normalizedIdentity);
|
|
313
|
+
}
|
|
314
|
+
function isNumericSegment(segment) {
|
|
315
|
+
return /^\d+$/.test(segment);
|
|
316
|
+
}
|
|
317
|
+
function getApiResponseShapeNodeAtPath(shape, pathSegments) {
|
|
318
|
+
let current = shape;
|
|
319
|
+
for (const segment of pathSegments) {
|
|
320
|
+
if (!current) {
|
|
321
|
+
return undefined;
|
|
322
|
+
}
|
|
323
|
+
if (current.type === 'array') {
|
|
324
|
+
current = current.items;
|
|
325
|
+
if (isNumericSegment(segment)) {
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
if (current?.type !== 'object') {
|
|
330
|
+
return undefined;
|
|
331
|
+
}
|
|
332
|
+
current = current.properties?.[segment];
|
|
333
|
+
}
|
|
334
|
+
return current;
|
|
335
|
+
}
|
|
336
|
+
function isPathSafePropertyName(name) {
|
|
337
|
+
return /^[a-zA-Z_][a-zA-Z0-9_-]*$/.test(name);
|
|
338
|
+
}
|
|
339
|
+
function getApiResponseShapeProperties(node) {
|
|
340
|
+
if (!node) {
|
|
341
|
+
return [];
|
|
342
|
+
}
|
|
343
|
+
if (node.type === 'array') {
|
|
344
|
+
const itemProperties = getApiResponseShapeProperties(node.items);
|
|
345
|
+
return [
|
|
346
|
+
{ name: 'count', shape: { type: 'number' } },
|
|
347
|
+
...itemProperties
|
|
348
|
+
];
|
|
349
|
+
}
|
|
350
|
+
if (node.type !== 'object' || !node.properties) {
|
|
351
|
+
return [];
|
|
352
|
+
}
|
|
353
|
+
return Object.entries(node.properties)
|
|
354
|
+
.filter(([name]) => isPathSafePropertyName(name))
|
|
355
|
+
.map(([name, shape]) => ({ name, shape }))
|
|
356
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
357
|
+
}
|
|
358
|
+
function getApiResponseShapeTypeSummary(node) {
|
|
359
|
+
let summary;
|
|
360
|
+
if (node.type === 'array') {
|
|
361
|
+
const itemSummary = node.items ? getApiResponseShapeTypeSummary(node.items) : 'unknown';
|
|
362
|
+
summary = `array<${itemSummary}>`;
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
summary = node.type;
|
|
366
|
+
}
|
|
367
|
+
return node.nullable ? `${summary} | null` : summary;
|
|
368
|
+
}
|
|
369
|
+
function parseApiResponseBodyPathForCompletion(suffix) {
|
|
370
|
+
const pathSuffix = suffix.startsWith('[') ? `.${suffix}` : suffix;
|
|
371
|
+
if (!pathSuffix.startsWith('.')) {
|
|
372
|
+
return undefined;
|
|
373
|
+
}
|
|
374
|
+
const normalized = pathSuffix.replace(/\[(\d+)\]/g, '.$1');
|
|
375
|
+
if (!normalized.startsWith('.')) {
|
|
376
|
+
return undefined;
|
|
377
|
+
}
|
|
378
|
+
const withoutLeadingDot = normalized.slice(1);
|
|
379
|
+
const endsAtSeparator = normalized.endsWith('.');
|
|
380
|
+
const rawParts = withoutLeadingDot.split('.');
|
|
381
|
+
const nonEmptyParts = rawParts.filter(part => part !== '');
|
|
382
|
+
if (endsAtSeparator) {
|
|
383
|
+
return {
|
|
384
|
+
pathSegments: nonEmptyParts,
|
|
385
|
+
partial: ''
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
const partial = nonEmptyParts.at(-1) ?? '';
|
|
389
|
+
return {
|
|
390
|
+
pathSegments: nonEmptyParts.slice(0, -1),
|
|
391
|
+
partial
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
//# sourceMappingURL=apiResponseIntellisenseCache.js.map
|