pi-apexlang 0.2.2 → 0.3.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/README.md
CHANGED
|
@@ -76,6 +76,11 @@ The registered `apexlang` tool supports:
|
|
|
76
76
|
| `runtime_doctor` | Diagnoses runtime configuration. |
|
|
77
77
|
| `runtime_validate` | Runs Oracle's live check gate, then offers an interactive check-only or same-session validate-and-import choice. |
|
|
78
78
|
|
|
79
|
+
`local_validate` preserves Oracle's complete validator and report semantics.
|
|
80
|
+
The extension accelerates its repeated block and nesting queries in a
|
|
81
|
+
process-local cache; the vendored Oracle skill remains unchanged and no checks
|
|
82
|
+
are skipped.
|
|
83
|
+
|
|
79
84
|
The model cannot request import as a standalone action. Oracle's skill defaults
|
|
80
85
|
to checking code; only after authoritative live validation passes does the
|
|
81
86
|
extension offer a separate GUI choice. Selecting **Check and import APEXlang
|
|
@@ -21,6 +21,7 @@ export const APEXLANG_ACTIONS = Object.freeze([
|
|
|
21
21
|
|
|
22
22
|
const apexctlPath = resolve(APEXLANG_SKILL_ROOT, "tools/apexctl.mjs");
|
|
23
23
|
const queryValidPropsPath = resolve(APEXLANG_SKILL_ROOT, "tools/query-valid-props.mjs");
|
|
24
|
+
const localValidatePath = resolve(moduleDirectory, "apexlang-local-validate.mjs");
|
|
24
25
|
const runtimeRoundtripPath = resolve(moduleDirectory, "apexlang-runtime-roundtrip.mjs");
|
|
25
26
|
const sqlclPtyProxyPath = resolve(moduleDirectory, "apexlang-sqlcl-pty.py");
|
|
26
27
|
const CONTROL_CHARACTER_PATTERN = /[\u0000-\u001f\u007f]/;
|
|
@@ -214,9 +215,9 @@ export function buildApexlangCommand(input) {
|
|
|
214
215
|
}
|
|
215
216
|
|
|
216
217
|
if (action === "local_validate") {
|
|
217
|
-
const args = ["
|
|
218
|
+
const args = ["--app-path", requirePath(input, "app_path", action)];
|
|
218
219
|
addFlag(args, "--fix-vocab", input.fix_vocab);
|
|
219
|
-
return
|
|
220
|
+
return { scriptPath: localValidatePath, args, prelude: [] };
|
|
220
221
|
}
|
|
221
222
|
|
|
222
223
|
if (action === "compiler_truth_audit") {
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
import { mkdirSync } from "node:fs";
|
|
5
|
+
import { dirname, join, resolve } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
const moduleDirectory = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const skillRoot = resolve(moduleDirectory, "../../skills/apexlang");
|
|
10
|
+
const runtimeRoot = resolve(skillRoot, "runtime");
|
|
11
|
+
const pythonRoot = resolve(runtimeRoot, "internal/python");
|
|
12
|
+
const optimizedDslValidator = resolve(moduleDirectory, "apexlang-local-validator.py");
|
|
13
|
+
|
|
14
|
+
function readOption(args, name) {
|
|
15
|
+
const index = args.indexOf(name);
|
|
16
|
+
return index >= 0 && index + 1 < args.length ? String(args[index + 1]).trim() : "";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function main() {
|
|
20
|
+
const args = process.argv.slice(2);
|
|
21
|
+
const appPath = readOption(args, "--app-path");
|
|
22
|
+
if (!appPath) {
|
|
23
|
+
console.error("Missing required --app-path");
|
|
24
|
+
return 1;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const outputRoot = String(process.env.APEXLANG_OUTPUT_ROOT ?? "").trim();
|
|
28
|
+
if (!outputRoot) {
|
|
29
|
+
console.error("APEXLANG_OUTPUT_ROOT is required in packaged apexlang runtime");
|
|
30
|
+
return 1;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const reportDir = resolve(outputRoot, "logs");
|
|
34
|
+
mkdirSync(reportDir, { recursive: true });
|
|
35
|
+
const fixVocab = args.includes("--fix-vocab");
|
|
36
|
+
const commands = [
|
|
37
|
+
[
|
|
38
|
+
resolve(pythonRoot, "validate_apexlang_vocab.py"),
|
|
39
|
+
[
|
|
40
|
+
"--app-path",
|
|
41
|
+
appPath,
|
|
42
|
+
"--report-path",
|
|
43
|
+
join(reportDir, "apexlang-vocab-report.json"),
|
|
44
|
+
fixVocab ? "--rewrite" : "--check-only"
|
|
45
|
+
]
|
|
46
|
+
],
|
|
47
|
+
[
|
|
48
|
+
optimizedDslValidator,
|
|
49
|
+
["--report-path", join(reportDir, "apexlang-dsl-report.json"), appPath]
|
|
50
|
+
],
|
|
51
|
+
[
|
|
52
|
+
resolve(pythonRoot, "validate_validations.py"),
|
|
53
|
+
["--report-path", join(reportDir, "apexlang-validations-report.json"), appPath]
|
|
54
|
+
]
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
let failures = 0;
|
|
58
|
+
for (const [scriptPath, scriptArgs] of commands) {
|
|
59
|
+
const result = spawnSync("python3", [scriptPath, ...scriptArgs], {
|
|
60
|
+
cwd: process.cwd(),
|
|
61
|
+
encoding: "utf8",
|
|
62
|
+
env: {
|
|
63
|
+
...process.env,
|
|
64
|
+
APEXLANG_EMBEDDED_TOOLS_ROOT: resolve(skillRoot, "tools"),
|
|
65
|
+
APEXLANG_PACKAGE_ROOT: skillRoot,
|
|
66
|
+
APEXLANG_RUNTIME_ROOT: runtimeRoot,
|
|
67
|
+
PYTHONDONTWRITEBYTECODE: "1"
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
if (result.stdout) process.stdout.write(result.stdout);
|
|
71
|
+
if (result.stderr) process.stderr.write(result.stderr);
|
|
72
|
+
if (typeof result.status !== "number" || result.status !== 0) failures += 1;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (failures > 0) {
|
|
76
|
+
console.log("APEXLANG_LOCAL_CHECK_FAILED");
|
|
77
|
+
return 1;
|
|
78
|
+
}
|
|
79
|
+
console.log("APEXLANG_LOCAL_CHECK_OK");
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
process.exitCode = main();
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Run Oracle's DSL validator with per-process parser acceleration.
|
|
3
|
+
|
|
4
|
+
The vendored Oracle skill stays byte-for-byte unchanged. This launcher imports
|
|
5
|
+
its validator, replaces only pure parsing helpers with equivalent cached
|
|
6
|
+
implementations, and then calls the original command-line entry point.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from bisect import bisect_right
|
|
12
|
+
from functools import lru_cache, wraps
|
|
13
|
+
import importlib.util
|
|
14
|
+
import os
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
import sys
|
|
17
|
+
from types import ModuleType
|
|
18
|
+
from typing import Any, Callable
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class _SparseDepthIndex:
|
|
22
|
+
"""Store lexical depth checkpoints only at offsets requested by validators."""
|
|
23
|
+
|
|
24
|
+
__slots__ = ("positions", "states")
|
|
25
|
+
|
|
26
|
+
def __init__(self) -> None:
|
|
27
|
+
self.positions: list[int] = [0]
|
|
28
|
+
self.states: list[tuple[int, int, bool]] = [(0, 0, False)]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
_DEPTH_INDEXES: dict[str, _SparseDepthIndex] = {}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _sparse_nesting_depth(text: str, idx: int) -> tuple[int, int]:
|
|
35
|
+
"""Return Oracle-compatible nesting depth using the closest prior checkpoint."""
|
|
36
|
+
target_idx = min(len(text), idx) if idx >= 0 else max(0, len(text) + idx)
|
|
37
|
+
index = _DEPTH_INDEXES.setdefault(text, _SparseDepthIndex())
|
|
38
|
+
checkpoint_slot = bisect_right(index.positions, target_idx) - 1
|
|
39
|
+
start = index.positions[checkpoint_slot]
|
|
40
|
+
paren_depth, brace_depth, in_string = index.states[checkpoint_slot]
|
|
41
|
+
|
|
42
|
+
for pos in range(start, target_idx):
|
|
43
|
+
ch = text[pos]
|
|
44
|
+
if ch == '"' and (pos == 0 or text[pos - 1] != "\\"):
|
|
45
|
+
in_string = not in_string
|
|
46
|
+
continue
|
|
47
|
+
if in_string:
|
|
48
|
+
continue
|
|
49
|
+
if ch == "(":
|
|
50
|
+
paren_depth += 1
|
|
51
|
+
elif ch == ")":
|
|
52
|
+
paren_depth = max(0, paren_depth - 1)
|
|
53
|
+
elif ch == "{":
|
|
54
|
+
brace_depth += 1
|
|
55
|
+
elif ch == "}":
|
|
56
|
+
brace_depth = max(0, brace_depth - 1)
|
|
57
|
+
|
|
58
|
+
if start != target_idx:
|
|
59
|
+
insert_at = checkpoint_slot + 1
|
|
60
|
+
index.positions.insert(insert_at, target_idx)
|
|
61
|
+
index.states.insert(insert_at, (paren_depth, brace_depth, in_string))
|
|
62
|
+
return paren_depth, brace_depth
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _validator_path() -> Path:
|
|
66
|
+
runtime_override = os.environ.get("APEXLANG_RUNTIME_ROOT", "").strip()
|
|
67
|
+
runtime_root = (
|
|
68
|
+
Path(runtime_override).resolve()
|
|
69
|
+
if runtime_override
|
|
70
|
+
else Path(__file__).resolve().parents[2] / "skills" / "apexlang" / "runtime"
|
|
71
|
+
)
|
|
72
|
+
return runtime_root / "internal" / "python" / "validate_apexlang.py"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _load_oracle_validator(path: Path) -> ModuleType:
|
|
76
|
+
sys.path.insert(0, str(path.parent))
|
|
77
|
+
spec = importlib.util.spec_from_file_location("_pi_apexlang_oracle_validator", path)
|
|
78
|
+
if spec is None or spec.loader is None:
|
|
79
|
+
raise RuntimeError(f"Cannot load Oracle APEXlang validator: {path}")
|
|
80
|
+
module = importlib.util.module_from_spec(spec)
|
|
81
|
+
sys.modules[spec.name] = module
|
|
82
|
+
spec.loader.exec_module(module)
|
|
83
|
+
return module
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _cache_list_function(function: Callable[..., list[Any]]) -> Callable[..., list[Any]]:
|
|
87
|
+
"""Cache immutable results while preserving Oracle's fresh-list return type."""
|
|
88
|
+
cached = lru_cache(maxsize=None)(lambda *args: tuple(function(*args)))
|
|
89
|
+
|
|
90
|
+
@wraps(function)
|
|
91
|
+
def wrapper(*args: Any) -> list[Any]:
|
|
92
|
+
return list(cached(*args))
|
|
93
|
+
|
|
94
|
+
return wrapper
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _accelerate(module: ModuleType) -> None:
|
|
98
|
+
module.nesting_depth = _sparse_nesting_depth
|
|
99
|
+
for name in (
|
|
100
|
+
"find_component_blocks",
|
|
101
|
+
"find_named_brace_blocks",
|
|
102
|
+
"find_immediate_component_blocks",
|
|
103
|
+
"find_immediate_named_brace_blocks",
|
|
104
|
+
):
|
|
105
|
+
setattr(module, name, _cache_list_function(getattr(module, name)))
|
|
106
|
+
module.block_body = lru_cache(maxsize=None)(module.block_body)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def main(argv: list[str]) -> int:
|
|
110
|
+
validator = _load_oracle_validator(_validator_path())
|
|
111
|
+
_accelerate(validator)
|
|
112
|
+
return int(validator.main(argv))
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
if __name__ == "__main__":
|
|
116
|
+
sys.exit(main(sys.argv[1:]))
|