@kernlang/test 3.4.2 → 3.4.3-canary.10.1.eb490d3e
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.
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safety-checks.js","sourceRoot":"","sources":["../../src/generated/safety-checks.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,MAAM,CAAC,MAAM,eAAe,GAAW,4BAA4B,CAAC;AAEpE,gCAAgC;AAChC,MAAM,UAAU,oBAAoB,CAAC,KAAa;IAChD,OAAO,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACrC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { decompile, generateCoreNode, importTypeScript, parseDocumentWithDiagnostics, validateSchema, validateSemantics, } from '@kernlang/core';
|
|
1
|
+
import { decompile, emitNativeKernBodyTS, generateCoreNode, importTypeScript, parseDocumentWithDiagnostics, validateSchema, validateSemantics, } from '@kernlang/core';
|
|
2
2
|
import { execFileSync } from 'child_process';
|
|
3
3
|
import { existsSync, readdirSync, readFileSync, statSync } from 'fs';
|
|
4
4
|
import { dirname, join, relative, resolve } from 'path';
|
|
@@ -426,6 +426,39 @@ function handlerText(node) {
|
|
|
426
426
|
.filter(Boolean)
|
|
427
427
|
.join('\n');
|
|
428
428
|
}
|
|
429
|
+
// `handlerText` returns the verbatim `props.code` from each handler child,
|
|
430
|
+
// which is what most callers (reach analysis, length checks, regex sniffing)
|
|
431
|
+
// want. The runtime-eval path is different: a handler with `lang="kern"`
|
|
432
|
+
// stores raw KERN source in `props.code`, not JS. Feeding that to V8 yields
|
|
433
|
+
// ReferenceErrors when tests reference symbols whose body is kern-native.
|
|
434
|
+
// `runtimeHandlerSource` lowers each kern handler through the same emitter
|
|
435
|
+
// the codegen path uses (`emitNativeKernBodyTS`), giving the runner a
|
|
436
|
+
// JS body it can wrap and execute.
|
|
437
|
+
//
|
|
438
|
+
// On lowering failure we warn and inject a `throw new Error(...)` body so
|
|
439
|
+
// the binding compiles cleanly but blows up at invocation with the actual
|
|
440
|
+
// emitter error — instead of degrading to an empty body that surfaces as a
|
|
441
|
+
// misleading downstream ReferenceError.
|
|
442
|
+
function runtimeHandlerSource(node) {
|
|
443
|
+
return getChildren(node, 'handler')
|
|
444
|
+
.map((handler) => {
|
|
445
|
+
if (str(getProps(handler).lang) === 'kern') {
|
|
446
|
+
try {
|
|
447
|
+
return emitNativeKernBodyTS(handler);
|
|
448
|
+
}
|
|
449
|
+
catch (error) {
|
|
450
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
451
|
+
const ownerName = str(getProps(node).name) || node.type;
|
|
452
|
+
console.warn(`[kern-test] kern handler lowering failed for '${ownerName}': ${message}`);
|
|
453
|
+
const literal = JSON.stringify(`kern handler lowering failed for '${ownerName}': ${message}`);
|
|
454
|
+
return `throw new Error(${literal});`;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
return str(getProps(handler).code);
|
|
458
|
+
})
|
|
459
|
+
.filter(Boolean)
|
|
460
|
+
.join('\n');
|
|
461
|
+
}
|
|
429
462
|
function collectNamedHandlerBodies(root) {
|
|
430
463
|
const bodies = new Map();
|
|
431
464
|
for (const fn of collectNodes(root, 'fn')) {
|
|
@@ -1980,7 +2013,13 @@ function evaluateImportedKernRoundtrip(kern, options = {}) {
|
|
|
1980
2013
|
message: `Imported KERN does not reparse at ${parseError.line}:${parseError.col}: ${parseError.message}`,
|
|
1981
2014
|
};
|
|
1982
2015
|
}
|
|
1983
|
-
|
|
2016
|
+
// Slice α-4: NATIVE_KERN_ELIGIBLE is an opt-in suggestion, not a roundtrip
|
|
2017
|
+
// defect. Imported KERN with raw `<<<…>>>` handler bodies that the
|
|
2018
|
+
// classifier accepts will trigger this code at warning level — that is the
|
|
2019
|
+
// intended IDE/LSP signal, not a contract violation. Filter it here the
|
|
2020
|
+
// same way `shared.ts`, `review/src/index.ts`, and `import.ts` do at their
|
|
2021
|
+
// consumer sites.
|
|
2022
|
+
const parseWarning = reparsed.diagnostics.find((diagnostic) => diagnostic.severity === 'warning' && diagnostic.code !== 'NATIVE_KERN_ELIGIBLE');
|
|
1984
2023
|
if (parseWarning && !options.allowWarnings) {
|
|
1985
2024
|
return {
|
|
1986
2025
|
passed: false,
|
|
@@ -2069,8 +2108,35 @@ function evaluateImportAssertion(node, context) {
|
|
|
2069
2108
|
}
|
|
2070
2109
|
return { passed: true };
|
|
2071
2110
|
}
|
|
2072
|
-
|
|
2073
|
-
const
|
|
2111
|
+
function readPositiveIntEnv(name, fallback) {
|
|
2112
|
+
const raw = process.env[name];
|
|
2113
|
+
if (raw === undefined || raw === '')
|
|
2114
|
+
return fallback;
|
|
2115
|
+
const parsed = Number.parseInt(raw, 10);
|
|
2116
|
+
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
2117
|
+
return fallback;
|
|
2118
|
+
return parsed;
|
|
2119
|
+
}
|
|
2120
|
+
// V8 enforces wall-clock time on `script.runInContext`. Under CPU contention
|
|
2121
|
+
// cold-compile + JIT can blow tight budgets — a 100ms default produced flaky
|
|
2122
|
+
// non-deterministic failures across runs. 1s is the new floor; override via
|
|
2123
|
+
// `KERN_TEST_RUNTIME_TIMEOUT_MS` for slow CI or expensive evals.
|
|
2124
|
+
const RUNTIME_EXPR_TIMEOUT_MS = readPositiveIntEnv('KERN_TEST_RUNTIME_TIMEOUT_MS', 1000);
|
|
2125
|
+
// Outer process timeout for the async eval path — must comfortably exceed
|
|
2126
|
+
// `RUNTIME_EXPR_TIMEOUT_MS` plus Node spawn cost (~200-400ms on busy machines).
|
|
2127
|
+
// We enforce a 2s safety margin even when the user overrides the env var: a
|
|
2128
|
+
// shorter outer timeout would kill the worker before V8 can report a real
|
|
2129
|
+
// inner timeout, surfacing as an opaque "process timed out" instead of the
|
|
2130
|
+
// actionable script-execution-timed-out error.
|
|
2131
|
+
const RUNTIME_ASYNC_PROCESS_FLOOR_MS = Math.max(5000, RUNTIME_EXPR_TIMEOUT_MS + 2000);
|
|
2132
|
+
const RUNTIME_ASYNC_PROCESS_TIMEOUT_MS = (() => {
|
|
2133
|
+
const requested = readPositiveIntEnv('KERN_TEST_ASYNC_PROCESS_TIMEOUT_MS', RUNTIME_ASYNC_PROCESS_FLOOR_MS);
|
|
2134
|
+
if (requested < RUNTIME_ASYNC_PROCESS_FLOOR_MS) {
|
|
2135
|
+
console.warn(`[kern-test] KERN_TEST_ASYNC_PROCESS_TIMEOUT_MS=${requested} is below the required floor (${RUNTIME_ASYNC_PROCESS_FLOOR_MS}ms = max(5000, RUNTIME_EXPR_TIMEOUT_MS+2000)); using the floor instead.`);
|
|
2136
|
+
return RUNTIME_ASYNC_PROCESS_FLOOR_MS;
|
|
2137
|
+
}
|
|
2138
|
+
return requested;
|
|
2139
|
+
})();
|
|
2074
2140
|
const RUNTIME_EXPR_UNSAFE_TOKEN = /\b(?:async|class|constructor|Date|delete|do|eval|fetch|for|Function|global|globalThis|import|process|prototype|require|setInterval|setTimeout|switch|this|throw|try|while|with|WebSocket|XMLHttpRequest|__proto__)\b/;
|
|
2075
2141
|
const RUNTIME_FN_UNSAFE_TOKEN = /\b(?:class|constructor|Date|delete|do|eval|fetch|Function|global|globalThis|import|process|prototype|require|setInterval|setTimeout|switch|this|with|WebSocket|XMLHttpRequest|__proto__)\b/;
|
|
2076
2142
|
const RUNTIME_CLASS_UNSAFE_TOKEN = /\b(?:Date|delete|do|eval|fetch|Function|global|globalThis|import|process|prototype|require|setInterval|setTimeout|switch|with|WebSocket|XMLHttpRequest|__proto__)\b/;
|
|
@@ -2187,7 +2253,7 @@ function runtimeJsSource(source) {
|
|
|
2187
2253
|
.replace(/\bfunction\s+([A-Za-z_$][\w$]*)\s*\(([^)]*)\)\s*:\s*[^{]+{/g, 'function $1($2) {'));
|
|
2188
2254
|
}
|
|
2189
2255
|
function runtimeConstHandlerExpr(node) {
|
|
2190
|
-
const code = runtimeJsSource(
|
|
2256
|
+
const code = runtimeJsSource(runtimeHandlerSource(node).trim());
|
|
2191
2257
|
if (!code)
|
|
2192
2258
|
return '';
|
|
2193
2259
|
if (/^\s*(?:return|const|let|var|if|for|while|try|throw)\b/.test(code) || /;\s*$/.test(code)) {
|
|
@@ -2238,7 +2304,7 @@ function runtimeParamNames(node) {
|
|
|
2238
2304
|
return parseLegacyParamNames(str(getProps(node).params));
|
|
2239
2305
|
}
|
|
2240
2306
|
function runtimeFunctionExpr(node) {
|
|
2241
|
-
const code = runtimeJsSource(
|
|
2307
|
+
const code = runtimeJsSource(runtimeHandlerSource(node));
|
|
2242
2308
|
if (!code)
|
|
2243
2309
|
return '';
|
|
2244
2310
|
const params = runtimeParamNames(node);
|
|
@@ -2249,7 +2315,7 @@ function runtimeFunctionExpr(node) {
|
|
|
2249
2315
|
}
|
|
2250
2316
|
function runtimeHandlerLines(node, spaces = 4) {
|
|
2251
2317
|
const prefix = ' '.repeat(spaces);
|
|
2252
|
-
const code = runtimeJsSource(
|
|
2318
|
+
const code = runtimeJsSource(runtimeHandlerSource(node).trim());
|
|
2253
2319
|
if (!code)
|
|
2254
2320
|
return [];
|
|
2255
2321
|
return code.split('\n').map((line) => `${prefix}${line}`);
|