norn-cli 2.4.0 → 2.6.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 (96) hide show
  1. package/AGENTS.md +2 -2
  2. package/CHANGELOG.md +26 -1
  3. package/dist/cli.js +330 -85
  4. package/package.json +24 -5
  5. package/schemas/norn.config.schema.json +43 -1
  6. package/scripts/__pycache__/reddit_signal_miner.cpython-312.pyc +0 -0
  7. package/scripts/reddit_signal_miner.py +482 -0
  8. package/.claude/settings.local.json +0 -18
  9. package/.claude/skills/norn-social-campaign/SKILL.md +0 -70
  10. package/out/apiResponseIntellisenseCache.js +0 -394
  11. package/out/assertionRunner.js +0 -567
  12. package/out/cacheDir.js +0 -136
  13. package/out/chatParticipant.js +0 -763
  14. package/out/cli/colors.js +0 -127
  15. package/out/cli/formatters/assertion.js +0 -102
  16. package/out/cli/formatters/index.js +0 -23
  17. package/out/cli/formatters/response.js +0 -106
  18. package/out/cli/formatters/summary.js +0 -246
  19. package/out/cli/redaction.js +0 -237
  20. package/out/cli/reporters/html.js +0 -689
  21. package/out/cli/reporters/index.js +0 -22
  22. package/out/cli/reporters/junit.js +0 -226
  23. package/out/codeLensProvider.js +0 -351
  24. package/out/compareContentProvider.js +0 -85
  25. package/out/completionProvider.js +0 -3739
  26. package/out/contractAssertionSummary.js +0 -225
  27. package/out/contractDecorationProvider.js +0 -243
  28. package/out/coverageCalculator.js +0 -879
  29. package/out/coveragePanel.js +0 -597
  30. package/out/debug/breakpointResolver.js +0 -84
  31. package/out/debug/breakpoints.js +0 -52
  32. package/out/debug/nornDebugAdapter.js +0 -166
  33. package/out/debug/nornDebugSession.js +0 -613
  34. package/out/debug/sequenceLocationIndex.js +0 -77
  35. package/out/debug/types.js +0 -3
  36. package/out/deepClone.js +0 -21
  37. package/out/diagnosticProvider.js +0 -2554
  38. package/out/environmentParser.js +0 -736
  39. package/out/environmentProvider.js +0 -544
  40. package/out/environmentTemplates.js +0 -146
  41. package/out/errors/formatError.js +0 -113
  42. package/out/errors/nornError.js +0 -29
  43. package/out/formUrlEncoded.js +0 -89
  44. package/out/httpClient.js +0 -348
  45. package/out/httpRuntimeOptions.js +0 -16
  46. package/out/importErrors.js +0 -31
  47. package/out/inlayHintResolver.js +0 -70
  48. package/out/jsonFileReader.js +0 -323
  49. package/out/mcpClient.js +0 -193
  50. package/out/mcpConfig.js +0 -184
  51. package/out/mcpToolIntellisenseCache.js +0 -96
  52. package/out/mcpToolSchema.js +0 -50
  53. package/out/nornConfig.js +0 -132
  54. package/out/nornHoverProvider.js +0 -124
  55. package/out/nornInlayHintsProvider.js +0 -191
  56. package/out/nornPrompt.js +0 -755
  57. package/out/nornSqlParser.js +0 -286
  58. package/out/nornapiHoverProvider.js +0 -135
  59. package/out/nornapiInlayHintsProvider.js +0 -94
  60. package/out/nornapiParser.js +0 -324
  61. package/out/nornenvCodeActionProvider.js +0 -101
  62. package/out/nornenvDecorationProvider.js +0 -239
  63. package/out/nornenvFoldingProvider.js +0 -63
  64. package/out/nornenvHoverProvider.js +0 -114
  65. package/out/nornenvInlayHintsProvider.js +0 -99
  66. package/out/nornenvLanguageModel.js +0 -187
  67. package/out/nornenvRegionRefactor.js +0 -267
  68. package/out/nornsqlHoverProvider.js +0 -95
  69. package/out/nornsqlInlayHintsProvider.js +0 -114
  70. package/out/parser.js +0 -839
  71. package/out/pathAccess.js +0 -28
  72. package/out/postmanImportPanel.js +0 -732
  73. package/out/postmanImportPlanner.js +0 -1155
  74. package/out/postmanImportSidebarView.js +0 -532
  75. package/out/quotedString.js +0 -35
  76. package/out/requestPreparation.js +0 -179
  77. package/out/requestValidation.js +0 -146
  78. package/out/responsePanel.js +0 -7754
  79. package/out/schemaGenerator.js +0 -562
  80. package/out/scriptRunner.js +0 -419
  81. package/out/secrets/cliSecrets.js +0 -415
  82. package/out/secrets/crypto.js +0 -105
  83. package/out/secrets/envFileSecrets.js +0 -177
  84. package/out/secrets/keyStore.js +0 -259
  85. package/out/sequenceDeclaration.js +0 -15
  86. package/out/sequenceRunner.js +0 -3590
  87. package/out/sqlAdapterRunner.js +0 -122
  88. package/out/sqlBuiltInAdapters.js +0 -604
  89. package/out/sqlConfig.js +0 -184
  90. package/out/starterCatalog.js +0 -554
  91. package/out/stringUtils.js +0 -25
  92. package/out/swaggerBodyIntellisenseCache.js +0 -114
  93. package/out/swaggerParser.js +0 -464
  94. package/out/testProvider.js +0 -767
  95. package/out/theoryCaseLoader.js +0 -113
  96. package/out/validationCache.js +0 -211
@@ -1,179 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolveBareVariableRequestBody = resolveBareVariableRequestBody;
4
- exports.applyHeaderGroupsToRequest = applyHeaderGroupsToRequest;
5
- exports.prepareRequestFromContent = prepareRequestFromContent;
6
- const parser_1 = require("./parser");
7
- const nornapiParser_1 = require("./nornapiParser");
8
- const pathAccess_1 = require("./pathAccess");
9
- function escapeRegExp(value) {
10
- return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
11
- }
12
- function stringifyRequestValue(value) {
13
- if (typeof value === 'string') {
14
- return value;
15
- }
16
- if (typeof value === 'object' && value !== null) {
17
- return JSON.stringify(value);
18
- }
19
- return String(value);
20
- }
21
- function shouldResolveBareRequestValue(value, variables) {
22
- if (!Object.prototype.hasOwnProperty.call(variables, value)) {
23
- return false;
24
- }
25
- const envScope = variables['$env'];
26
- const isEnvOnlyValue = envScope
27
- && typeof envScope === 'object'
28
- && Object.prototype.hasOwnProperty.call(envScope, value)
29
- && variables[value] === envScope[value];
30
- return !isEnvOnlyValue;
31
- }
32
- function resolveRequestValueExpression(value, variables) {
33
- if (shouldResolveBareRequestValue(value, variables)) {
34
- return stringifyRequestValue(variables[value]);
35
- }
36
- const pathMatch = value.match(/^([a-zA-Z_][a-zA-Z0-9_]*)(\.\w[\w-]*(?:\.\w[\w-]*|\[\d+\])*|\[\d+\](?:\.\w[\w-]*|\[\d+\])*)$/);
37
- if (pathMatch && shouldResolveBareRequestValue(pathMatch[1], variables)) {
38
- const nestedValue = (0, pathAccess_1.getNestedPathValue)(variables[pathMatch[1]], pathMatch[2].replace(/^\./, ''));
39
- if (nestedValue !== undefined) {
40
- return stringifyRequestValue(nestedValue);
41
- }
42
- }
43
- return (0, parser_1.substituteVariables)(value, variables);
44
- }
45
- function resolveBareVariableRequestBody(request, variables) {
46
- if (!request.body) {
47
- return request;
48
- }
49
- const bareVariableMatch = request.body.trim().match(/^([a-zA-Z_][a-zA-Z0-9_]*)$/);
50
- if (!bareVariableMatch || !(bareVariableMatch[1] in variables)) {
51
- return request;
52
- }
53
- return {
54
- ...request,
55
- body: stringifyRequestValue(variables[bareVariableMatch[1]])
56
- };
57
- }
58
- function applyHeaderGroupsToRequest(parsed, requestText, headerGroups, variables) {
59
- const lines = requestText.split('\n');
60
- const headerGroupNames = headerGroups.map(hg => hg.name);
61
- const headerGroupHeaders = {};
62
- const foundGroups = [];
63
- const cleanedBodyLines = [];
64
- let sawRequestLine = false;
65
- let inBodySection = false;
66
- let sawBlankLineAfterRequest = false;
67
- for (const line of lines) {
68
- const trimmed = line.trim();
69
- if (trimmed.startsWith('#') || trimmed.startsWith('var ')) {
70
- continue;
71
- }
72
- if (!trimmed) {
73
- if (sawRequestLine && !inBodySection) {
74
- sawBlankLineAfterRequest = true;
75
- }
76
- continue;
77
- }
78
- const methodMatch = trimmed.match(/^(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s+(.+)$/i);
79
- if (!sawRequestLine && methodMatch) {
80
- sawRequestLine = true;
81
- const afterMethod = methodMatch[2];
82
- const tokens = afterMethod.split(/\s+/);
83
- for (let index = tokens.length - 1; index >= 0; index--) {
84
- if (headerGroupNames.includes(tokens[index])) {
85
- foundGroups.push(tokens[index]);
86
- }
87
- else {
88
- break;
89
- }
90
- }
91
- continue;
92
- }
93
- if (!sawRequestLine) {
94
- continue;
95
- }
96
- if (sawBlankLineAfterRequest) {
97
- inBodySection = true;
98
- }
99
- if (!inBodySection) {
100
- if (/^[A-Za-z0-9\-_]+\s*:\s*.+$/.test(trimmed)) {
101
- continue;
102
- }
103
- const potentialGroups = trimmed.split(/\s+/).filter(Boolean);
104
- const matchingGroups = potentialGroups.filter(groupName => headerGroupNames.includes(groupName));
105
- if (matchingGroups.length > 0 && matchingGroups.length === potentialGroups.length) {
106
- foundGroups.push(...matchingGroups);
107
- continue;
108
- }
109
- inBodySection = true;
110
- }
111
- cleanedBodyLines.push(trimmed);
112
- }
113
- for (const groupName of foundGroups) {
114
- const group = headerGroups.find(hg => hg.name === groupName);
115
- if (group) {
116
- Object.assign(headerGroupHeaders, (0, nornapiParser_1.resolveHeaderValues)(group, variables));
117
- }
118
- }
119
- let modifiedUrl = parsed.url;
120
- for (const groupName of foundGroups) {
121
- const endPattern = new RegExp(`\\s+${escapeRegExp(groupName)}$`);
122
- modifiedUrl = modifiedUrl.replace(endPattern, '');
123
- }
124
- modifiedUrl = modifiedUrl.trim();
125
- const result = {
126
- ...parsed,
127
- url: modifiedUrl,
128
- body: cleanedBodyLines.length > 0 ? (0, parser_1.substituteVariables)(cleanedBodyLines.join('\n'), variables) : undefined
129
- };
130
- if (Object.keys(headerGroupHeaders).length > 0) {
131
- result.headers = { ...headerGroupHeaders, ...parsed.headers };
132
- }
133
- return result;
134
- }
135
- function prepareRequestFromContent(requestContent, variables, apiDefinitions) {
136
- if (apiDefinitions && apiDefinitions.endpoints.length > 0 && (0, nornapiParser_1.isApiRequestLine)(requestContent, apiDefinitions.endpoints)) {
137
- const apiRequest = (0, nornapiParser_1.parseApiRequest)(requestContent, apiDefinitions.endpoints, apiDefinitions.headerGroups);
138
- if (apiRequest) {
139
- const endpoint = (0, nornapiParser_1.getEndpoint)(apiDefinitions, apiRequest.endpointName);
140
- if (!endpoint) {
141
- throw new Error(`Unknown endpoint: ${apiRequest.endpointName}`);
142
- }
143
- const resolvedParams = {};
144
- for (const [paramName, paramValue] of Object.entries(apiRequest.params)) {
145
- resolvedParams[paramName] = resolveRequestValueExpression(paramValue, variables);
146
- }
147
- const resolvedPath = (0, parser_1.substituteVariables)((0, nornapiParser_1.resolveEndpointPath)(endpoint, resolvedParams), variables);
148
- const combinedHeaders = {};
149
- for (const groupName of apiRequest.headerGroupNames) {
150
- const group = (0, nornapiParser_1.getHeaderGroup)(apiDefinitions, groupName);
151
- if (group) {
152
- Object.assign(combinedHeaders, (0, nornapiParser_1.resolveHeaderValues)(group, variables));
153
- }
154
- }
155
- for (const [headerName, headerValue] of Object.entries(apiRequest.inlineHeaders)) {
156
- combinedHeaders[headerName] = (0, parser_1.substituteVariables)(headerValue, variables);
157
- }
158
- const request = {
159
- method: apiRequest.method,
160
- url: resolvedPath,
161
- headers: combinedHeaders,
162
- body: apiRequest.body ? (0, parser_1.substituteVariables)(apiRequest.body, variables) : undefined
163
- };
164
- return {
165
- request,
166
- description: `${apiRequest.endpointName}(${Object.values(resolvedParams).join(', ')}) -> ${request.method} ${request.url}`
167
- };
168
- }
169
- }
170
- let request = (0, parser_1.parserHttpRequest)(requestContent, variables);
171
- if (apiDefinitions && apiDefinitions.headerGroups.length > 0) {
172
- request = applyHeaderGroupsToRequest(request, requestContent, apiDefinitions.headerGroups, variables);
173
- }
174
- return {
175
- request,
176
- description: `${request.method} ${request.url}`
177
- };
178
- }
179
- //# sourceMappingURL=requestPreparation.js.map
@@ -1,146 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.findPlaceholderReferences = findPlaceholderReferences;
4
- exports.validatePreparedRequest = validatePreparedRequest;
5
- const nornError_1 = require("./errors/nornError");
6
- const formUrlEncoded_1 = require("./formUrlEncoded");
7
- const PLACEHOLDER_REGEX = /\{\{(\$env|\$[0-9]+|[a-zA-Z_][a-zA-Z0-9_]*)((?:\.[a-zA-Z_][a-zA-Z0-9_-]*|\[\d+\])*)\}\}/g;
8
- function findPlaceholderReferences(text) {
9
- if (!text) {
10
- return [];
11
- }
12
- const references = [];
13
- let match;
14
- PLACEHOLDER_REGEX.lastIndex = 0;
15
- while ((match = PLACEHOLDER_REGEX.exec(text)) !== null) {
16
- references.push({
17
- text: match[0],
18
- name: match[1],
19
- pathPart: match[2] || '',
20
- index: match.index
21
- });
22
- }
23
- return references;
24
- }
25
- function collectUnresolvedPlaceholders(text) {
26
- if (!text) {
27
- return [];
28
- }
29
- const names = new Set();
30
- for (const reference of findPlaceholderReferences(text)) {
31
- names.add(reference.text);
32
- }
33
- return [...names];
34
- }
35
- function extractEnvScopedNames(placeholders) {
36
- return placeholders
37
- .filter(value => value.startsWith('{{$env.'))
38
- .map(value => value.slice('{{$env.'.length, -2).split(/[.[\]]/)[0])
39
- .filter(Boolean);
40
- }
41
- function buildMissingVariableHint(missingVars, context) {
42
- const env = context?.environment;
43
- const envScopedNames = extractEnvScopedNames(missingVars);
44
- const unscopedVars = missingVars.filter(value => !value.startsWith('{{$env.'));
45
- if (env?.hasEnvFile && env.availableEnvironments && env.availableEnvironments.length > 0 && !env.activeEnvironment) {
46
- return `A .nornenv file was found but no environment is selected. Select one of: ${env.availableEnvironments.join(', ')}.`;
47
- }
48
- if (env?.hasEnvFile && env.activeEnvironment && envScopedNames.length > 0 && unscopedVars.length === 0) {
49
- return `Check that ${envScopedNames.map(v => `'${v}'`).join(', ')} exist in the active environment '${env.activeEnvironment}'.`;
50
- }
51
- if (env?.hasEnvFile && env.activeEnvironment) {
52
- return `Check that ${missingVars.map(v => `'${v}'`).join(', ')} exist in the active environment '${env.activeEnvironment}' or as file-level variables.`;
53
- }
54
- return `Define ${missingVars.length === 1 ? 'the variable' : 'the variables'} ${missingVars.map(v => `'${v}'`).join(', ')} before sending the request.`;
55
- }
56
- function buildRequestContext(parsed, context) {
57
- return {
58
- ...context,
59
- method: context?.method || parsed.method,
60
- url: context?.url || parsed.url,
61
- environment: context?.environment
62
- };
63
- }
64
- function getHeaderValueCaseInsensitive(headers, headerName) {
65
- const targetName = headerName.toLowerCase();
66
- for (const [name, value] of Object.entries(headers)) {
67
- if (name.toLowerCase() === targetName) {
68
- return value;
69
- }
70
- }
71
- return undefined;
72
- }
73
- function describeUnresolvedLocation(label, vars) {
74
- if (vars.length === 0) {
75
- return undefined;
76
- }
77
- return `${label}: unresolved ${vars.length === 1 ? 'variable' : 'variables'} ${vars.join(', ')}`;
78
- }
79
- function shouldValidateBodyPlaceholders(parsed) {
80
- const method = String(parsed.method || '').toUpperCase();
81
- // Be conservative: GET/HEAD commonly ignore bodies and legacy Norn tests may contain
82
- // body-like trailing text that should not block execution for these methods.
83
- return method !== 'GET' && method !== 'HEAD';
84
- }
85
- function validatePreparedRequest(parsed, context) {
86
- const urlVars = collectUnresolvedPlaceholders(parsed.url);
87
- const headerVars = [...new Set(Object.values(parsed.headers).flatMap(value => collectUnresolvedPlaceholders(value)))];
88
- const bodyVars = shouldValidateBodyPlaceholders(parsed) ? collectUnresolvedPlaceholders(parsed.body) : [];
89
- const missingVars = [...new Set([...urlVars, ...headerVars, ...bodyVars])];
90
- if (missingVars.length > 0) {
91
- const details = [
92
- describeUnresolvedLocation('URL', urlVars),
93
- describeUnresolvedLocation('Headers', headerVars),
94
- describeUnresolvedLocation('Body', bodyVars)
95
- ].filter((d) => Boolean(d));
96
- throw new nornError_1.NornError({
97
- category: 'variable-resolution',
98
- code: 'unresolved-request-variables',
99
- message: `Request could not be prepared: unresolved ${missingVars.length === 1 ? 'variable' : 'variables'} ${missingVars.join(', ')}.`,
100
- details,
101
- hint: buildMissingVariableHint(missingVars, context),
102
- context: {
103
- ...buildRequestContext(parsed, context),
104
- unresolvedVariables: missingVars
105
- }
106
- });
107
- }
108
- if (!parsed.url || !parsed.url.trim()) {
109
- throw new nornError_1.NornError({
110
- category: 'url',
111
- code: 'missing-request-url',
112
- message: 'Request URL is missing.',
113
- hint: 'Add a URL after the HTTP method (for example: GET https://api.example.com/path).',
114
- context: buildRequestContext(parsed, context)
115
- });
116
- }
117
- try {
118
- new URL(parsed.url);
119
- }
120
- catch (error) {
121
- throw new nornError_1.NornError({
122
- category: 'url',
123
- code: 'invalid-request-url',
124
- message: `Invalid request URL: ${parsed.url}`,
125
- details: error instanceof Error ? error.message : String(error),
126
- hint: 'Check the URL format and any variables used to build it.',
127
- context: buildRequestContext(parsed, context),
128
- cause: error
129
- });
130
- }
131
- const contentType = getHeaderValueCaseInsensitive(parsed.headers, 'Content-Type');
132
- if ((0, formUrlEncoded_1.isFormUrlEncodedContentType)(contentType)) {
133
- const { errors } = (0, formUrlEncoded_1.parseFormUrlEncodedBody)(parsed.body);
134
- if (errors.length > 0) {
135
- throw new nornError_1.NornError({
136
- category: 'syntax',
137
- code: 'invalid-form-urlencoded-body',
138
- message: 'Request could not be prepared: invalid application/x-www-form-urlencoded body syntax.',
139
- details: errors.map(error => `Body line ${error.lineIndex + 1}: ${error.message} (${error.line})`),
140
- hint: 'Use key=value, key: value, or a single line like key1=value1&key2=value2.',
141
- context: buildRequestContext(parsed, context)
142
- });
143
- }
144
- }
145
- }
146
- //# sourceMappingURL=requestValidation.js.map