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,286 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseNornSqlFile = parseNornSqlFile;
|
|
4
|
+
const CONNECTION_REGEX = /^connection\s+([A-Za-z_][A-Za-z0-9_-]*)\s*$/i;
|
|
5
|
+
const OPERATION_REGEX = /^(query|command)\s+([A-Za-z_][A-Za-z0-9_-]*)(?:\s*\((.*)\))?\s*$/i;
|
|
6
|
+
const PARAMETER_NAME_REGEX = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
7
|
+
function splitCommaSeparated(value) {
|
|
8
|
+
const parts = [];
|
|
9
|
+
let current = '';
|
|
10
|
+
for (let i = 0; i < value.length; i++) {
|
|
11
|
+
const char = value[i];
|
|
12
|
+
if (char === ',') {
|
|
13
|
+
parts.push(current.trim());
|
|
14
|
+
current = '';
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
current += char;
|
|
18
|
+
}
|
|
19
|
+
parts.push(current.trim());
|
|
20
|
+
return parts;
|
|
21
|
+
}
|
|
22
|
+
function parseParameterList(rawParams) {
|
|
23
|
+
if (rawParams === undefined) {
|
|
24
|
+
return { parameters: [] };
|
|
25
|
+
}
|
|
26
|
+
const trimmed = rawParams.trim();
|
|
27
|
+
if (!trimmed) {
|
|
28
|
+
return { parameters: [] };
|
|
29
|
+
}
|
|
30
|
+
const parts = splitCommaSeparated(trimmed);
|
|
31
|
+
const parameters = [];
|
|
32
|
+
const seen = new Set();
|
|
33
|
+
for (const part of parts) {
|
|
34
|
+
if (!part) {
|
|
35
|
+
return {
|
|
36
|
+
parameters: [],
|
|
37
|
+
error: 'Invalid parameter list syntax. Use query Name(param1, param2) or command Name(param1, param2).'
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
if (!PARAMETER_NAME_REGEX.test(part)) {
|
|
41
|
+
return {
|
|
42
|
+
parameters: [],
|
|
43
|
+
error: 'Invalid parameter list syntax. Use query Name(param1, param2) or command Name(param1, param2).'
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const lower = part.toLowerCase();
|
|
47
|
+
if (seen.has(lower)) {
|
|
48
|
+
return {
|
|
49
|
+
parameters: [],
|
|
50
|
+
error: `Duplicate parameter name '${part}' in operation declaration.`
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
seen.add(lower);
|
|
54
|
+
parameters.push(part);
|
|
55
|
+
}
|
|
56
|
+
return { parameters };
|
|
57
|
+
}
|
|
58
|
+
function collectSqlPlaceholders(sql) {
|
|
59
|
+
const placeholders = new Set();
|
|
60
|
+
let inSingleQuote = false;
|
|
61
|
+
let inDoubleQuote = false;
|
|
62
|
+
let inLineComment = false;
|
|
63
|
+
let inBlockComment = false;
|
|
64
|
+
for (let i = 0; i < sql.length; i++) {
|
|
65
|
+
const char = sql[i];
|
|
66
|
+
const next = i + 1 < sql.length ? sql[i + 1] : '';
|
|
67
|
+
const prev = i > 0 ? sql[i - 1] : '';
|
|
68
|
+
if (inLineComment) {
|
|
69
|
+
if (char === '\n') {
|
|
70
|
+
inLineComment = false;
|
|
71
|
+
}
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (inBlockComment) {
|
|
75
|
+
if (char === '*' && next === '/') {
|
|
76
|
+
inBlockComment = false;
|
|
77
|
+
i++;
|
|
78
|
+
}
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (inSingleQuote) {
|
|
82
|
+
if (char === "'" && next === "'") {
|
|
83
|
+
i++;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (char === "'") {
|
|
87
|
+
inSingleQuote = false;
|
|
88
|
+
}
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (inDoubleQuote) {
|
|
92
|
+
if (char === '"' && next === '"') {
|
|
93
|
+
i++;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (char === '"') {
|
|
97
|
+
inDoubleQuote = false;
|
|
98
|
+
}
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (char === '-' && next === '-') {
|
|
102
|
+
inLineComment = true;
|
|
103
|
+
i++;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (char === '/' && next === '*') {
|
|
107
|
+
inBlockComment = true;
|
|
108
|
+
i++;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (char === "'") {
|
|
112
|
+
inSingleQuote = true;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (char === '"') {
|
|
116
|
+
inDoubleQuote = true;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (char !== ':' || next === ':' || prev === ':') {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (/[A-Za-z0-9_]/.test(prev)) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const match = sql.slice(i + 1).match(/^([A-Za-z_][A-Za-z0-9_]*)/);
|
|
126
|
+
if (!match) {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
placeholders.add(match[1]);
|
|
130
|
+
i += match[1].length;
|
|
131
|
+
}
|
|
132
|
+
return Array.from(placeholders.values());
|
|
133
|
+
}
|
|
134
|
+
function validatePlaceholders(operation, errors, endLine) {
|
|
135
|
+
const declared = new Set(operation.parameters.map(param => param.toLowerCase()));
|
|
136
|
+
const placeholders = collectSqlPlaceholders(operation.bodyLines.join('\n'));
|
|
137
|
+
for (const placeholder of placeholders) {
|
|
138
|
+
if (!declared.has(placeholder.toLowerCase())) {
|
|
139
|
+
errors.push({
|
|
140
|
+
message: `Obvious SQL placeholder ':${placeholder}' does not match a declared parameter.`,
|
|
141
|
+
lineNumber: endLine,
|
|
142
|
+
blocking: true
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function parseNornSqlFile(text, sourcePath) {
|
|
148
|
+
const lines = text.split('\n');
|
|
149
|
+
const operations = [];
|
|
150
|
+
const errors = [];
|
|
151
|
+
let connectionName;
|
|
152
|
+
let connectionLine = -1;
|
|
153
|
+
let currentBlock;
|
|
154
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
155
|
+
const rawLine = lines[lineIndex];
|
|
156
|
+
const trimmed = rawLine.trim();
|
|
157
|
+
if (currentBlock) {
|
|
158
|
+
if (trimmed.toLowerCase() === `end ${currentBlock.type}`) {
|
|
159
|
+
validatePlaceholders(currentBlock, errors, lineIndex);
|
|
160
|
+
operations.push({
|
|
161
|
+
type: currentBlock.type,
|
|
162
|
+
name: currentBlock.name,
|
|
163
|
+
parameters: currentBlock.parameters,
|
|
164
|
+
sql: currentBlock.bodyLines.join('\n'),
|
|
165
|
+
connectionName: connectionName || '',
|
|
166
|
+
sourcePath,
|
|
167
|
+
startLine: currentBlock.startLine,
|
|
168
|
+
endLine: lineIndex
|
|
169
|
+
});
|
|
170
|
+
currentBlock = undefined;
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
if (trimmed.toLowerCase() === 'end query' || trimmed.toLowerCase() === 'end command') {
|
|
174
|
+
errors.push({
|
|
175
|
+
message: `${trimmed.toLowerCase()} without a matching ${trimmed.toLowerCase() === 'end query' ? 'query' : 'command'}.`,
|
|
176
|
+
lineNumber: lineIndex,
|
|
177
|
+
blocking: true
|
|
178
|
+
});
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
currentBlock.bodyLines.push(rawLine);
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
if (!trimmed || trimmed.startsWith('#')) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
if (/^import\b/i.test(trimmed)) {
|
|
188
|
+
errors.push({
|
|
189
|
+
message: '`import` is not supported in `.nornsql`. Import SQL files from a `.norn` file instead.',
|
|
190
|
+
lineNumber: lineIndex,
|
|
191
|
+
blocking: true
|
|
192
|
+
});
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (/^end\s+query$/i.test(trimmed)) {
|
|
196
|
+
errors.push({
|
|
197
|
+
message: '`end query` without a matching `query`.',
|
|
198
|
+
lineNumber: lineIndex,
|
|
199
|
+
blocking: true
|
|
200
|
+
});
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if (/^end\s+command$/i.test(trimmed)) {
|
|
204
|
+
errors.push({
|
|
205
|
+
message: '`end command` without a matching `command`.',
|
|
206
|
+
lineNumber: lineIndex,
|
|
207
|
+
blocking: true
|
|
208
|
+
});
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
const connectionMatch = trimmed.match(CONNECTION_REGEX);
|
|
212
|
+
if (connectionMatch) {
|
|
213
|
+
if (connectionName) {
|
|
214
|
+
errors.push({
|
|
215
|
+
message: 'Duplicate `connection` declaration. Each `.nornsql` file can declare only one `connection`.',
|
|
216
|
+
lineNumber: lineIndex,
|
|
217
|
+
blocking: true
|
|
218
|
+
});
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
connectionName = connectionMatch[1];
|
|
222
|
+
connectionLine = lineIndex;
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
if (/^(query|command)\b/i.test(trimmed)) {
|
|
226
|
+
const operationMatch = trimmed.match(OPERATION_REGEX);
|
|
227
|
+
if (!operationMatch) {
|
|
228
|
+
errors.push({
|
|
229
|
+
message: 'Invalid parameter list syntax. Use query Name(param1, param2) or command Name(param1, param2).',
|
|
230
|
+
lineNumber: lineIndex,
|
|
231
|
+
blocking: true
|
|
232
|
+
});
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
const type = operationMatch[1].toLowerCase();
|
|
236
|
+
const name = operationMatch[2];
|
|
237
|
+
const paramResult = parseParameterList(operationMatch[3]);
|
|
238
|
+
if (paramResult.error) {
|
|
239
|
+
errors.push({
|
|
240
|
+
message: paramResult.error,
|
|
241
|
+
lineNumber: lineIndex,
|
|
242
|
+
blocking: true
|
|
243
|
+
});
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
currentBlock = {
|
|
247
|
+
type,
|
|
248
|
+
name,
|
|
249
|
+
parameters: paramResult.parameters,
|
|
250
|
+
startLine: lineIndex,
|
|
251
|
+
bodyLines: []
|
|
252
|
+
};
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
errors.push({
|
|
256
|
+
message: 'Unknown top-level statement. Supported statements are: `connection`, `query`, `command`, `end query`, `end command`.',
|
|
257
|
+
lineNumber: lineIndex,
|
|
258
|
+
blocking: true
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
if (currentBlock) {
|
|
262
|
+
errors.push({
|
|
263
|
+
message: `Unterminated \`${currentBlock.type}\` block. Add \`end ${currentBlock.type}\`.`,
|
|
264
|
+
lineNumber: currentBlock.startLine,
|
|
265
|
+
blocking: true
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
if (!connectionName) {
|
|
269
|
+
errors.push({
|
|
270
|
+
message: 'Missing `connection` declaration. Each `.nornsql` file must declare exactly one `connection`.',
|
|
271
|
+
lineNumber: connectionLine >= 0 ? connectionLine : 0,
|
|
272
|
+
blocking: true
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
if (connectionName) {
|
|
276
|
+
for (const operation of operations) {
|
|
277
|
+
operation.connectionName = connectionName;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return {
|
|
281
|
+
connectionName,
|
|
282
|
+
operations,
|
|
283
|
+
errors
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
//# sourceMappingURL=nornSqlParser.js.map
|
|
@@ -0,0 +1,135 @@
|
|
|
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.NornapiHoverProvider = void 0;
|
|
37
|
+
exports.findTemplateTokenAt = findTemplateTokenAt;
|
|
38
|
+
exports.renderTemplateReferenceHover = renderTemplateReferenceHover;
|
|
39
|
+
const vscode = __importStar(require("vscode"));
|
|
40
|
+
const environmentProvider_1 = require("./environmentProvider");
|
|
41
|
+
const environmentParser_1 = require("./environmentParser");
|
|
42
|
+
const inlayHintResolver_1 = require("./inlayHintResolver");
|
|
43
|
+
const TEMPLATE_TOKEN_REGEX = /\{\{([^{}]+)\}\}/g;
|
|
44
|
+
/**
|
|
45
|
+
* Hover over a `{{name}}` / `{{$env.name}}` token in a `.nornapi` file shows the
|
|
46
|
+
* resolution chain: where the variable is defined in `.nornenv`, the current resolved
|
|
47
|
+
* value under the active env, and a secret flag if applicable.
|
|
48
|
+
*/
|
|
49
|
+
class NornapiHoverProvider {
|
|
50
|
+
provideHover(document, position) {
|
|
51
|
+
try {
|
|
52
|
+
const filePath = document.uri.scheme === 'file' ? document.uri.fsPath : undefined;
|
|
53
|
+
if (!filePath) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
const lineText = document.lineAt(position.line).text;
|
|
57
|
+
const tokenMatch = findTemplateTokenAt(lineText, position.character);
|
|
58
|
+
if (!tokenMatch) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
const parsed = (0, inlayHintResolver_1.parseInlayReference)(tokenMatch.referenceRaw);
|
|
62
|
+
if (!parsed) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
const config = (0, environmentProvider_1.loadEnvironmentConfig)(filePath);
|
|
66
|
+
if (!config) {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
const activeEnvironment = (0, environmentProvider_1.getActiveEnvironment)(filePath);
|
|
70
|
+
const markdown = renderTemplateReferenceHover(parsed.name, config, activeEnvironment);
|
|
71
|
+
return new vscode.Hover(markdown, new vscode.Range(new vscode.Position(position.line, tokenMatch.tokenStart), new vscode.Position(position.line, tokenMatch.tokenEnd)));
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
exports.NornapiHoverProvider = NornapiHoverProvider;
|
|
79
|
+
function findTemplateTokenAt(lineText, character) {
|
|
80
|
+
TEMPLATE_TOKEN_REGEX.lastIndex = 0;
|
|
81
|
+
for (const match of lineText.matchAll(TEMPLATE_TOKEN_REGEX)) {
|
|
82
|
+
const start = match.index ?? 0;
|
|
83
|
+
const end = start + match[0].length;
|
|
84
|
+
if (character < start || character > end) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
return { referenceRaw: match[1], tokenStart: start, tokenEnd: end };
|
|
88
|
+
}
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Builds a Markdown hover block for a `{{ref}}` resolving from the nearest `.nornenv`'s
|
|
93
|
+
* active environment. Shared between `.nornapi`, `.nornsql`, and `.norn` hover providers
|
|
94
|
+
* for the env-scope case.
|
|
95
|
+
*/
|
|
96
|
+
function renderTemplateReferenceHover(name, config, activeEnvironment) {
|
|
97
|
+
const lines = [`**\`${name}\`**`];
|
|
98
|
+
if (!config) {
|
|
99
|
+
lines.push(`No \`.nornenv\` file found in scope.`);
|
|
100
|
+
return new vscode.MarkdownString(lines.join('\n\n'));
|
|
101
|
+
}
|
|
102
|
+
const secret = config.secretNames.has(name);
|
|
103
|
+
if (!activeEnvironment) {
|
|
104
|
+
if (Object.prototype.hasOwnProperty.call(config.common, name)) {
|
|
105
|
+
lines.push('Defined in `common`.');
|
|
106
|
+
lines.push(secret
|
|
107
|
+
? 'No active env. Common value is a secret.'
|
|
108
|
+
: `No active env. Common value: \`${config.common[name]}\`.`);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
lines.push('Not defined in `common`. (No active env selected — only common vars are in scope.)');
|
|
112
|
+
}
|
|
113
|
+
return new vscode.MarkdownString(lines.join('\n\n'));
|
|
114
|
+
}
|
|
115
|
+
const details = (0, environmentParser_1.resolveEffectiveEnvVariableDetails)(activeEnvironment, config);
|
|
116
|
+
const detail = details.get(name);
|
|
117
|
+
if (!detail) {
|
|
118
|
+
lines.push(`Not defined in the active env \`${activeEnvironment}\` or its ancestor templates.`);
|
|
119
|
+
return new vscode.MarkdownString(lines.join('\n\n'));
|
|
120
|
+
}
|
|
121
|
+
const sourceLabel = detail.sourceKind === 'common'
|
|
122
|
+
? 'common'
|
|
123
|
+
: `${detail.sourceKind}:${detail.sourceName ?? ''}`;
|
|
124
|
+
lines.push(`Defined in \`${sourceLabel}\`.`);
|
|
125
|
+
lines.push(secret
|
|
126
|
+
? `Active env \`${activeEnvironment}\` resolves to a secret value.`
|
|
127
|
+
: `Active env \`${activeEnvironment}\` resolves to \`${detail.value}\`.`);
|
|
128
|
+
if (detail.inherited) {
|
|
129
|
+
lines.push(`Inherited by \`env:${activeEnvironment}\`.`);
|
|
130
|
+
}
|
|
131
|
+
const markdown = new vscode.MarkdownString(lines.join('\n\n'));
|
|
132
|
+
markdown.isTrusted = false;
|
|
133
|
+
return markdown;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=nornapiHoverProvider.js.map
|
|
@@ -0,0 +1,94 @@
|
|
|
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.NornapiInlayHintsProvider = void 0;
|
|
37
|
+
const vscode = __importStar(require("vscode"));
|
|
38
|
+
const environmentProvider_1 = require("./environmentProvider");
|
|
39
|
+
const inlayHintResolver_1 = require("./inlayHintResolver");
|
|
40
|
+
const TEMPLATE_TOKEN_REGEX = /\{\{([^{}]+)\}\}/g;
|
|
41
|
+
/**
|
|
42
|
+
* Inlay hints for `.nornapi` files — resolves every `{{...}}` token in the file
|
|
43
|
+
* against the nearest `.nornenv`'s active environment. No local-var scope.
|
|
44
|
+
*/
|
|
45
|
+
class NornapiInlayHintsProvider {
|
|
46
|
+
emitter = new vscode.EventEmitter();
|
|
47
|
+
environmentSubscription;
|
|
48
|
+
onDidChangeInlayHints = this.emitter.event;
|
|
49
|
+
constructor() {
|
|
50
|
+
this.environmentSubscription = (0, environmentProvider_1.onDidChangeActiveEnvironment)(() => {
|
|
51
|
+
this.emitter.fire();
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
provideInlayHints(document, range) {
|
|
55
|
+
const hints = [];
|
|
56
|
+
try {
|
|
57
|
+
const filePath = document.uri.scheme === 'file' ? document.uri.fsPath : undefined;
|
|
58
|
+
if (!filePath) {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
const config = (0, environmentProvider_1.loadEnvironmentConfig)(filePath);
|
|
62
|
+
if (!config) {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
const variables = (0, environmentProvider_1.getEnvironmentVariables)(filePath);
|
|
66
|
+
for (let lineNumber = range.start.line; lineNumber <= range.end.line; lineNumber++) {
|
|
67
|
+
const line = document.lineAt(lineNumber).text;
|
|
68
|
+
TEMPLATE_TOKEN_REGEX.lastIndex = 0;
|
|
69
|
+
for (const match of line.matchAll(TEMPLATE_TOKEN_REGEX)) {
|
|
70
|
+
const resolved = (0, inlayHintResolver_1.resolveInlayValueLabel)(match[1], variables, config.secretNames);
|
|
71
|
+
if (!resolved) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const tokenEnd = (match.index ?? 0) + match[0].length;
|
|
75
|
+
const hint = new vscode.InlayHint(new vscode.Position(lineNumber, tokenEnd), resolved.label, vscode.InlayHintKind.Parameter);
|
|
76
|
+
hint.tooltip = resolved.secret
|
|
77
|
+
? `'${match[1].trim()}' resolves from a secret value.`
|
|
78
|
+
: `'${match[1].trim()}' resolves to '${resolved.value}'.`;
|
|
79
|
+
hints.push(hint);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
return hints;
|
|
87
|
+
}
|
|
88
|
+
dispose() {
|
|
89
|
+
this.environmentSubscription.dispose();
|
|
90
|
+
this.emitter.dispose();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
exports.NornapiInlayHintsProvider = NornapiInlayHintsProvider;
|
|
94
|
+
//# sourceMappingURL=nornapiInlayHintsProvider.js.map
|