Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
133 commits
Select commit Hold shift + click to select a range
d081726
web torture: independent oracle, runner and the first seven suites
swapnilpaliwal-sd Oct 10, 2026
0c43672
web torture: vendor animation shorthands, brace comments in values, k…
swapnilpaliwal-sd Oct 10, 2026
963c1f5
web torture: AXIOM_ROOT runs the suites against another checkout; ora…
swapnilpaliwal-sd Oct 10, 2026
587d3da
web torture: universal selectors were all unknown in the oracle
swapnilpaliwal-sd Oct 10, 2026
f03087f
web parser: read pages and stylesheets under dist/build/out; keep dec…
swapnilpaliwal-sd Oct 10, 2026
09720b4
web parser: an <ir>/web/ folder of its own; inline scripts and on* bo…
swapnilpaliwal-sd Oct 10, 2026
ee8b5d4
web torture: @scope is exact containment in the oracle (SPEC 3.2 iter1b)
swapnilpaliwal-sd Oct 10, 2026
9a5a828
web torture: var edges through the web_var view, with the SPEC 3.4a r…
swapnilpaliwal-sd Oct 10, 2026
8152e47
web torture: dynamic_attribute bindings, & specificity over a mixed p…
swapnilpaliwal-sd Oct 10, 2026
f4e4e80
web torture: one case per absorbed parser gap G10-G14, none known-mis…
swapnilpaliwal-sd Oct 10, 2026
e8d8476
web torture: nodes/04 names the parser gap it covers (G11)
swapnilpaliwal-sd Oct 10, 2026
85f996b
web torture: queries/ suite grading SPEC 6.4 templates through the CL…
swapnilpaliwal-sd Oct 10, 2026
2259550
web engine and bundle: wip checkpoint before merging torture suites
swapnilpaliwal-sd Oct 10, 2026
b6b1f21
web engine: selector matching to the oracle's contract; @scope, dynam…
swapnilpaliwal-sd Oct 10, 2026
c14a49d
web torture: commit the oracle (the root ignore rule for oracle/ had …
swapnilpaliwal-sd Oct 10, 2026
c54938f
web parser: a minified keyframe selector list (0%,20%,53%,to{) is one…
swapnilpaliwal-sd Oct 10, 2026
695c664
web engine: <div/> opens an element, declaration values without comme…
swapnilpaliwal-sd Oct 10, 2026
fab1c48
web: quoted @keyframes names, directory URLs, vendor animation value …
swapnilpaliwal-sd Oct 10, 2026
fda412d
web torture: the oracle's parser walk reads dist/, build/ and out/ fo…
swapnilpaliwal-sd Oct 10, 2026
e18dad5
web query verbs: impact, path and context answer on web nodes with th…
swapnilpaliwal-sd Oct 10, 2026
26ce665
web index: selectors have no end_line
swapnilpaliwal-sd Oct 10, 2026
5a352aa
JavaScript graph: ext_dom_touch, every site where script text names t…
swapnilpaliwal-sd Oct 10, 2026
530de42
JavaScript graph: ext_method_name, the binding an anonymous function …
swapnilpaliwal-sd Oct 10, 2026
7500196
JavaScript graph: module provenance and method->module; impact on a p…
swapnilpaliwal-sd Oct 10, 2026
3b5ce3b
JavaScript impact on a .js file: the answer says its language
swapnilpaliwal-sd Oct 10, 2026
59e02d0
web torture: js binding names via ext_method_name, minified functions…
swapnilpaliwal-sd Oct 10, 2026
eb95747
JavaScript graph: ext_module_provenance keyed by the module's file or…
swapnilpaliwal-sd Oct 10, 2026
f325d62
web: a link or @import to a file on disk the walk did not read is not…
swapnilpaliwal-sd Oct 11, 2026
4162653
Revert the inline-script JavaScript modules (scope: this layer is HTM…
swapnilpaliwal-sd Oct 11, 2026
37ee678
Revert the JavaScript-side DOM touches, binding names and JS impact a…
swapnilpaliwal-sd Oct 11, 2026
1abd84c
web torture: HTML and CSS only, the js suite and the oracle's JavaScr…
swapnilpaliwal-sd Oct 11, 2026
b82c24e
web parser: a bare on* attribute is no event handler; an XHTML page k…
swapnilpaliwal-sd Oct 11, 2026
42f7690
web: web_scripts carries each script's exact body text; web_handlers …
swapnilpaliwal-sd Oct 11, 2026
48e943f
web impact: a page's or element's scripts (body text, cut at 40 lines…
swapnilpaliwal-sd Oct 11, 2026
53da432
web §10: web_script and web_handler per SPEC (ordinal, attributes JSO…
swapnilpaliwal-sd Oct 11, 2026
bb13b33
web torture: scripts/ and handlers/ suites, verbatim HTML text per SP…
swapnilpaliwal-sd Oct 11, 2026
48911b5
web torture: unknown grain at the selector row, V1-21 font aliases, V…
swapnilpaliwal-sd Oct 11, 2026
d792d6f
web torture: oracle and normalizer for the SPEC 9 conversion layer
swapnilpaliwal-sd Oct 11, 2026
cdcb1c9
web torture: components/ suite (SPEC 9)
swapnilpaliwal-sd Oct 11, 2026
22a8b53
web torture: repeats/ suite (SPEC 9)
swapnilpaliwal-sd Oct 11, 2026
af3e338
web torture: computed/ suite (SPEC 9)
swapnilpaliwal-sd Oct 11, 2026
37df5d8
web torture: tokens/ suite (SPEC 9)
swapnilpaliwal-sd Oct 11, 2026
21ba3c3
web torture: breakpoints/ suite (SPEC 9)
swapnilpaliwal-sd Oct 11, 2026
931ea1c
web torture: forms/ suite (SPEC 9)
swapnilpaliwal-sd Oct 11, 2026
5f5f6f6
web torture: outline/ suite (SPEC 9)
swapnilpaliwal-sd Oct 11, 2026
18e835b
web torture: assets/ suite (SPEC 9)
swapnilpaliwal-sd Oct 11, 2026
75f031a
web torture: usage/ suite (SPEC 9)
swapnilpaliwal-sd Oct 11, 2026
5949d1c
web torture: queries Q38-Q48 for the conversion layer, scripts and ha…
swapnilpaliwal-sd Oct 11, 2026
3a3096e
web: no_static_carrier at selector grain (usage, unknown_reason, page…
swapnilpaliwal-sd Oct 11, 2026
4beeb83
web torture: An+B no longer TYPE parts, iterative tree walks, Stimulu…
swapnilpaliwal-sd Oct 11, 2026
690658c
web: end-to-end CLI smoke test (index --lang web, then impact/context…
swapnilpaliwal-sd Oct 11, 2026
c4c1a79
css parser: a custom property whose value is punctuation or braces (:…
swapnilpaliwal-sd Oct 11, 2026
cd5ea54
web parser: a relative url may climb out of the sub-project its page …
swapnilpaliwal-sd Oct 11, 2026
9e912e7
css parser: a block still open at the end of a sheet closes there as …
swapnilpaliwal-sd Oct 11, 2026
32fe221
web: one styles row per load of a sheet linked twice (the later load'…
swapnilpaliwal-sd Oct 11, 2026
fda72e3
web torture: read web_var_scope by the engine's column names; per-lan…
swapnilpaliwal-sd Oct 11, 2026
837fcac
web torture: a var defined only by @property gives var_scope reason p…
swapnilpaliwal-sd Oct 11, 2026
e14b0f4
web var tables: web_var_visible at (use, definition owner) grain with…
swapnilpaliwal-sd Oct 11, 2026
f3f0bab
web: unknown_reason explains usage (ruling c); property_initial scope…
swapnilpaliwal-sd Oct 11, 2026
21f893f
web §9 conversion layer: component candidates (exact/shape, maximal, …
swapnilpaliwal-sd Oct 11, 2026
ec1dbb4
web walk: .shtml and .shtm server-side-include pages are read as HTML…
swapnilpaliwal-sd Oct 11, 2026
1d5c63e
web answers for the conversion layer: impact component:<name> (occurr…
swapnilpaliwal-sd Oct 11, 2026
8076afb
parser: 0.2.1, HTML and CSS front-end fixes (Refs #1909)
swapnilpaliwal-sd Oct 11, 2026
f2d47ed
web torture: ORDER grades the full sequence with repeats; empty ::bef…
swapnilpaliwal-sd Oct 11, 2026
0d1a18e
wip: stream web relations to disk per file (V1-23)
swapnilpaliwal-sd Oct 11, 2026
7d39fd5
Parse only the requested languages; web relations stream to disk (V1-23)
swapnilpaliwal-sd Oct 11, 2026
4f2475c
web parser: spaced An+B, an IE filter's last paren, vendor animation …
swapnilpaliwal-sd Oct 11, 2026
af172eb
web engine: query-only links, whitespace and :empty, view-transition …
swapnilpaliwal-sd Oct 11, 2026
ffaebd8
web parser: INCLUDE references and SSI directives (G22, G23)
swapnilpaliwal-sd Oct 11, 2026
c9ac4f2
web engine: fragment hosts, web_includes, composition, asserted inclu…
swapnilpaliwal-sd Oct 11, 2026
329b6eb
web torture: oracle composes fragment hosts (SPEC 11.2), .shtml pages…
swapnilpaliwal-sd Oct 11, 2026
87c038a
web torture: includes/ suite, one case per include kind (SPEC 11.2)
swapnilpaliwal-sd Oct 11, 2026
92eaeb8
web parser: a `<` that opens no tag is text; xmp/plaintext are raw te…
swapnilpaliwal-sd Oct 11, 2026
5b7b4f0
web checks: C-01, C-02, C-03 (each fails at cce48aed)
swapnilpaliwal-sd Oct 11, 2026
aa477cc
web answers: impact .cls / #id always carries the selector's styled e…
swapnilpaliwal-sd Oct 11, 2026
e5d8002
web torture: an include that is not composed is a web_unknown row on …
swapnilpaliwal-sd Oct 11, 2026
8fcd814
web torture: Q36 graded through link, plus include questions Q36c, Q4…
swapnilpaliwal-sd Oct 11, 2026
a2959a4
web torture: SPEC 11.3 cost checks on scale/01 (time, RSS, bytes per …
swapnilpaliwal-sd Oct 11, 2026
7e4f245
web graph: 16-hex uids and no index nothing queries by (C-05)
swapnilpaliwal-sd Oct 11, 2026
7bab341
web torture: oracle and cases for the iteration-3 orchestrator rulings
swapnilpaliwal-sd Oct 11, 2026
23f3738
web parser: an include written in text is keyed by its page, not by a…
swapnilpaliwal-sd Oct 11, 2026
c902d20
web engine: include defects E1-E11 against the independent oracle; sc…
swapnilpaliwal-sd Oct 11, 2026
cc1d44e
web parser: a class token written with a template expression is kept …
swapnilpaliwal-sd Oct 11, 2026
0348dce
impact --json: a name that starts with -- is a name, not a flag
swapnilpaliwal-sd Oct 11, 2026
1a93a73
web engine: computed winners, tokens, styles grain, forms, references…
swapnilpaliwal-sd Oct 11, 2026
ced4ad2
web answers: `at` is the node's own start, `via_at` the matched token…
swapnilpaliwal-sd Oct 11, 2026
ff13bdc
web parser: a lone CR is a line break (V2-18)
swapnilpaliwal-sd Oct 11, 2026
14644fd
web engine: P3s V2-14/16/17/19, lone-CR lines, index share on element…
swapnilpaliwal-sd Oct 11, 2026
d182514
web parser: CSS values and preludes kept in full, as written, with th…
swapnilpaliwal-sd Oct 11, 2026
a28f96e
web engine: value/prelude sizes and the 64 KiB LIMIT row (V2-12); con…
swapnilpaliwal-sd Oct 11, 2026
bbd6a8c
web torture: V2-12 full prelude/value text with sizes and the 64 KiB …
swapnilpaliwal-sd Oct 11, 2026
381d852
web parser: root-relative URLs at the nearest ancestor, directory URL…
swapnilpaliwal-sd Oct 11, 2026
bd349b5
web engine: nearest-ancestor and directory-index resolution, SSI dire…
swapnilpaliwal-sd Oct 11, 2026
7eb30cf
web torture: iteration-4 oracle and grader rulings (V3-02, V3-07, V3-…
swapnilpaliwal-sd Oct 11, 2026
e49e93a
web answers: a templated class token or id is found by its written na…
swapnilpaliwal-sd Oct 11, 2026
1697e37
web parser: `/` from a page under the repository root resolves to the…
swapnilpaliwal-sd Oct 11, 2026
afe832d
web engine: fragment inline styles per host, top-level include occurr…
swapnilpaliwal-sd Oct 11, 2026
e3f6444
web parser: a body the browser implies before the written one takes t…
swapnilpaliwal-sd Oct 13, 2026
d81f7c6
web queries: a custom property is asked as var(--name); no flag-shape…
swapnilpaliwal-sd Oct 13, 2026
1c52eec
web torture: custom properties are asked as var(--name); a bare --nam…
swapnilpaliwal-sd Oct 13, 2026
d118638
web torture: quote var(--name) asks; an ask that does not parse fails…
swapnilpaliwal-sd Oct 13, 2026
e9e230e
web parser: a template tag inside a <style> keeps the rule whole
swapnilpaliwal-sd Oct 13, 2026
d6cf714
bundle schema: SCHEMA.md documents the web graph's tables and views
swapnilpaliwal-sd Oct 13, 2026
f66fd02
web cost: the bundle's heap is capped, IR hashes interned, unused ind…
swapnilpaliwal-sd Oct 13, 2026
ded0b73
web review 1: an undecidable contender is no certain winner; cascade,…
swapnilpaliwal-sd Oct 13, 2026
65ebb69
web torture: a fragment's own <style> applies in its host; commented …
swapnilpaliwal-sd Oct 13, 2026
6383fd9
skill: name the custom-property target without a flag-shaped token
swapnilpaliwal-sd Oct 13, 2026
19ebaca
web torture: a fragment's sheets are loaded by each host at the inclu…
swapnilpaliwal-sd Oct 13, 2026
a8cc043
web loads: a fragment's sheets are loaded by each host at the include…
swapnilpaliwal-sd Oct 13, 2026
bee45fe
web torture: key include references before the load edges; refuse raw…
swapnilpaliwal-sd Oct 13, 2026
2453498
web review 1, P3: data written whole, dropped IR rows declared, strin…
swapnilpaliwal-sd Oct 13, 2026
5d87818
web torture: iteration-5 rulings and the single-quote oracle regression
swapnilpaliwal-sd Oct 13, 2026
fd14927
web torture: keep nodes/27's CRLF fixture byte-exact (-text)
swapnilpaliwal-sd Oct 13, 2026
40b883e
web torture: SET and SET>= grade query answers as multisets (review-1…
swapnilpaliwal-sd Oct 13, 2026
28e57ba
web torture: element-styled answers graded per (element, rule) on at,…
swapnilpaliwal-sd Oct 13, 2026
5af91a0
web parser: every SSI directive, CSS text as written, whole url() bod…
swapnilpaliwal-sd Oct 13, 2026
78cac39
web: a later <include/> composes; no-op javascript: links; stored-tex…
swapnilpaliwal-sd Oct 13, 2026
62414b7
web resources: a fragment's url() resolves against each host, and eve…
swapnilpaliwal-sd Oct 13, 2026
e14a0f9
link: an asserted web include is taken and reported under --src
swapnilpaliwal-sd Oct 13, 2026
d9eebe2
Merge remote-tracking branch 'origin/dev' into feat/web-layer
swapnilpaliwal-sd Oct 13, 2026
8d526cc
build-engines: ship the web (HTML + CSS) engine, parallel like every …
swapnilpaliwal-sd Oct 13, 2026
9c80c30
web: style matching and var visibility cost what can match, not pages…
swapnilpaliwal-sd Oct 13, 2026
e79a0c4
web oracle: restore package-lock.json (an npm install during testing …
swapnilpaliwal-sd Oct 13, 2026
29dfb95
web engine: structural selector matching as Datalog relations (match.…
swapnilpaliwal-sd Oct 13, 2026
129f69b
web engine: the layout of every other engine — projections, containme…
swapnilpaliwal-sd Oct 13, 2026
2a33fcf
ci: gate the web engine like the other five — its suite in the matrix…
swapnilpaliwal-sd Oct 13, 2026
b7e639c
e2e: install and run the web engine as a user would, in CI's platform…
swapnilpaliwal-sd Oct 13, 2026
515375d
version 0.2.0: the web (HTML and CSS) engine is a new language users get
swapnilpaliwal-sd Oct 13, 2026
eb0688a
web verbs: impact with no name answers for edited pages and styleshee…
swapnilpaliwal-sd Oct 14, 2026
9c33955
web suite: one file per case (.case) and per query case's answers (.a…
swapnilpaliwal-sd Oct 14, 2026
1fe5212
e2e: every query verb on an installed package answers for a web site …
swapnilpaliwal-sd Oct 14, 2026
62fa711
version 0.1.11 (the web engine ships in 0.1.11, not 0.2.0)
swapnilpaliwal-sd Oct 14, 2026
7fc0f91
version 0.2.0: the web (HTML and CSS) engine is a new language users get
swapnilpaliwal-sd Oct 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 5 additions & 0 deletions .github/e2e/web/css/app.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import "base.css";
.nav a { color: navy; }
.btn { padding: 4px; }
.btn.primary { color: white; }
.ghost { opacity: 0.5; }
2 changes: 2 additions & 0 deletions .github/e2e/web/css/base.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
body { margin: 0; }
.lead { font-size: 1.2em; }
10 changes: 10 additions & 0 deletions .github/e2e/web/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet" href="css/app.css">
</head>
<body>
<nav class="nav"><a href="pages/about.html">About</a></nav>
<button class="btn primary" id="buy">Buy</button>
</body>
</html>
10 changes: 10 additions & 0 deletions .github/e2e/web/pages/about.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet" href="../css/app.css">
</head>
<body>
<p class="lead">About us</p>
<a class="btn" href="../index.html">Home</a>
</body>
</html>
18 changes: 18 additions & 0 deletions .github/scripts/e2e-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,24 @@ grep -q "using packaged engine" "$W/run.log" || fail "the run did not use the in

db="$(find "$W/out" -name graph.sqlite | head -1)"
[ -n "$db" ] || fail "no graph.sqlite was written"

# WEB (HTML + CSS) has no call graph: the installed package must have used its packaged web engine (checked above) and
# written pages, selectors and the rows that link them; then every query verb on .github/e2e/web (e2e-web-queries.sh).
if [ "$lang" = "web" ]; then
counts="$(node -e '
const { DatabaseSync } = require("node:sqlite");
const db = new DatabaseSync(process.argv[1], { readOnly: true });
const n = (t) => db.prepare(`SELECT COUNT(*) AS n FROM ${t}`).get().n;
console.log([n("web_pages"), n("web_selectors"), n("web_styles"), n("ext_web_selector_match")].join(" "));
' "$db" 2>/dev/null)"
read -r pages sels styles matches <<<"${counts:-0 0 0 0}"
[ "${pages:-0}" -gt 0 ] && [ "${sels:-0}" -gt 0 ] && [ "${styles:-0}" -gt 0 ] && [ "${matches:-0}" -gt 0 ] \
|| fail "the web graph is missing rows (pages ${pages:-?}, selectors ${sels:-?}, styles ${styles:-?}, engine matches ${matches:-?})"
echo "── every query verb on the web fixture, answers checked, no souffle"
PATH="$SANDBOX_PATH" bash "$root/.github/scripts/e2e-web-queries.sh" "$bin" "$root/.github/e2e/web" "$W/q" || fail "a web query verb answered wrongly (above)"
echo "e2e: ok — installed from the tarballs, used the packaged $platform web engine; $pages page(s), $sels selector(s), $styles style row(s), $matches engine match(es); every query verb answered correctly from the package"
exit 0
fi
edges="$(node -e '
const { DatabaseSync } = require("node:sqlite");
const db = new DatabaseSync(process.argv[1], { readOnly: true });
Expand Down
106 changes: 106 additions & 0 deletions .github/scripts/e2e-web-queries.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/usr/bin/env bash
# ─────────────────────────────────────────────────────────────────────────────
# Every query verb returns the RIGHT answer on a tiny site whose answers are known — the web (HTML + CSS) twin of
# e2e-queries.sh, which needs a call graph (entry → helper → leaf) a site does not have.
#
# e2e-web-queries.sh <axiomcode-bin> <fixture-dir> <work-dir>
#
# <fixture-dir> is .github/e2e/web/: index.html and pages/about.html load css/app.css, which @imports css/base.css;
# .btn is carried by an element on each page, .ghost by none. The site is copied to <work-dir>, committed, indexed,
# and asked:
#
# impact .btn the elements carrying it (one per page) and the selectors naming it
# impact css/app.css both pages load it; it imports base.css; .ghost matches nothing
# impact index.html about.html links to it; it loads base.css (import) and app.css (link), in that order
# path index.html css/base.css index.html → css/app.css → css/base.css
# context .ghost lands on css/app.css:5
# impact .btn --json one JSON document naming the class
# impact, path, context with os.exec* ending the caller at once, as Windows' exec does (#1640)
# padding 4px becomes 6px, then
# impact (no name) names the edited rule and the elements it styles
# tests says the web graph selects none (HTML and CSS have none), exit 3
#
# A path is matched with either separator; no answer may carry a Python traceback.
# ─────────────────────────────────────────────────────────────────────────────
set -uo pipefail
bin="${1:?usage: e2e-web-queries.sh <axiomcode-bin> <fixture-dir> <work-dir>}"; fx="${2:?fixture-dir}"; R="${3:?work-dir}"
fail() { echo "::error::e2e web queries: $*"; exit 1; }
native_path() { case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) cygpath -w "$1";; *) printf '%s' "$1";; esac; }
rm -rf "$R"; mkdir -p "$R"; cp -R "$fx"/. "$R"/
git -C "$R" init -q && git -C "$R" add -A && git -C "$R" -c user.email=e2e@axiomcode -c user.name=e2e commit -qm base \
|| fail "could not commit the fixture"

"$bin" index "$R" > "$R/.index.log" 2>&1 || { tail -20 "$R/.index.log"; fail "axiomcode index exited non-zero"; }

run() { # <env> <verb and args…>: the answer lands in $R/.q.log, a non-zero exit or a traceback fails
local env="$1"; shift; LABEL="$* ${env:+($env)}"
( cd "$R" && env $env "$bin" "$@" ) > "$R/.q.log" 2>&1; local rc=$?
if [ "$rc" -ne 0 ] || grep -q 'Traceback (most recent call last)' "$R/.q.log"; then
sed 's/^/ /' "$R/.q.log" | head -25; fail "$LABEL: rc=$rc"
fi
}
must() { # <extended regex> the last answer has to match, and why
grep -Eq -- "$1" "$R/.q.log" || { sed 's/^/ /' "$R/.q.log" | head -30; fail "$LABEL: expected /$1/ ($2)"; }
echo " ok $LABEL — $2"
}
S='[/\\]' # a path separator, either way round
btn_ok() { # <why>: the last answer is .btn's impact
must "^ +index\.html:8: button#buy\.btn\.primary" "$1 (the button on index.html)"
must "^ +pages${S}about\.html:8: a\.btn" "$1 (the link on about.html)"
must "css${S}app\.css:3: \.btn " "$1 (the selector naming it)"
}
path_ok() { # <why>: the last answer is the chain index.html → app.css → base.css
must "chain \(2 hop\(s\)\)" "$1 (two hops)"
must "^ +css${S}app\.css +loads " "$1 (index.html loads app.css)"
must "^ +css${S}base\.css +@import " "$1 (app.css imports base.css)"
}
ghost_ok() { must "css${S}app\.css:5: selector \.ghost" "$1 (.ghost is css/app.css:5)"; }

run "" impact .btn; btn_ok "the elements and selectors of .btn"
run "" impact css/app.css; must "^pages that load it: 2" "both pages load app.css"
must "^ +css${S}base\.css \[match\]" "app.css imports base.css"
must "css${S}app\.css:5: \.ghost +\[no_static_carrier\]" ".ghost matches nothing"
run "" impact index.html; must "^ +pages${S}about\.html:8: a\.btn \[href\]" "about.html links to it"
must "^ +1\. css${S}base\.css +\[import" "base.css first in cascade order"
must "^ +2\. css${S}app\.css +\[link\]" "app.css second"
run "" path index.html css/base.css; path_ok "the page reaches the imported sheet"
run "" context .ghost; ghost_ok "context lands on the selector"
run "" impact .btn --json; must '"target": "\.btn"' "the JSON names .btn"
node -e 'JSON.parse(require("fs").readFileSync(process.argv[1], "utf8"))' "$(native_path "$R/.q.log")" \
|| { head -c 600 "$R/.q.log"; fail "impact --json is not one JSON document"; }

# ── os.exec* that does not replace the process, as on Windows (#1640) ─────────────────────────
NOEXEC="$R.noexec"; mkdir -p "$NOEXEC"
cat > "$NOEXEC/sitecustomize.py" <<'PY'
import os, subprocess, sys
def _leave(path, args, *env):
subprocess.Popen(list(args), executable=path if os.sep in path else None, stdin=subprocess.DEVNULL,
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
os._exit(0)
for _n in ('execv', 'execve', 'execvp', 'execvpe'): setattr(os, _n, _leave)
for _n in ('execl', 'execle', 'execlp', 'execlpe'): setattr(os, _n, lambda path, *args: _leave(path, args))
sys.path.insert(0, os.environ.get('E2E_AX_SCRIPTS', ''))
try:
import ax_exec; ax_exec.REPLACES = False
except ImportError: pass
finally: sys.path.pop(0)
PY
SCR="$(cd "$(dirname "$bin")/../@axiomcode/code-graph/plugins/axiomcode/skills/axiomcode/scripts" 2>/dev/null && pwd)"
[ -n "$SCR" ] || fail "the installed package has no plugin scripts next to $bin"
NX="PYTHONPATH=$(native_path "$NOEXEC") E2E_AX_SCRIPTS=$(native_path "$SCR")"
run "$NX" impact .btn; btn_ok "impact answers where exec does not replace the process"
run "$NX" path index.html css/base.css; path_ok "path answers where exec does not replace the process"
run "$NX" context .ghost; ghost_ok "context answers where exec does not replace the process"

# a real edit to a rule: what changed, and what it styles
sed 's/padding: 4px/padding: 6px/' "$R/css/app.css" > "$R/.edit" && mv "$R/.edit" "$R/css/app.css"
git -C "$R" diff --quiet && fail "the edit to css/app.css changed nothing"
run "" impact; must "^web: your edits" "the edit is reported"
must "^ +css${S}app\.css: rule at line 3" "the edited rule is css/app.css:3"
must "^ +pages${S}about\.html:8: a\.btn \[match\]" "it styles the link on about.html"
# tests: an empty selection is exit 3 (as every verb's "nothing found"), never 0 and never a crash
LABEL="tests"; ( cd "$R" && "$bin" tests ) > "$R/.q.log" 2>&1; rc=$?
[ "$rc" -eq 3 ] && ! grep -q 'Traceback (most recent call last)' "$R/.q.log" \
|| { sed 's/^/ /' "$R/.q.log" | head -25; fail "tests: rc=$rc (expected 3, an empty selection)"; }
must "web graph selects no tests" "HTML and CSS have no tests to select"
echo "e2e web queries: every verb answered correctly"
12 changes: 8 additions & 4 deletions .github/workflows/build-engines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ on:
# for exactly the rules it was built from; the smoke step still runs every one.

env:
LANGUAGES: java typescript python javascript csharp
# web: the HTML + CSS engine (graph/web). It is built, marked .parallel and solved at -j 8 like every other.
LANGUAGES: java typescript python javascript csharp web
# Same pin and checksum as ci.yml: the tool that produces the published binaries is
# verified against what upstream published for that release.
SOUFFLE_SHA512: '6b86e554f6aa5abf8a8b55d8312ae37c0957c5bd6c9edeea89246db9406f645ec5e600b84fe6636b1c163da556f0da6c3d2dad46c1083413f2fcf4f95b9ac62c'
Expand Down Expand Up @@ -229,7 +230,7 @@ jobs:
if: startsWith(matrix.target.platform, 'win32')
shell: cmd
run: |
for %%L in (java typescript python javascript csharp) do (
for %%L in (java typescript python javascript csharp web) do (
fc /b gen\%%L.id engines\%%L\ENGINE_ID >nul 2>&1
if errorlevel 1 (
if not exist engines\%%L mkdir engines\%%L
Expand Down Expand Up @@ -298,9 +299,11 @@ jobs:
for lang in $LANGUAGES; do
# the binary itself, not the .parallel marker (or a DLL) beside it
bin="engines/$lang/axiomcode-engine-$lang"; [ -f "$bin.exe" ] && bin="$bin.exe"; chmod +x "$bin" 2>/dev/null || true
# every shipped engine is the parallel flavor: without the marker run-souffle.sh would solve it at -j 1
[ -f "$bin.parallel" ] || { echo "::error::$lang has no .parallel marker beside $bin"; exit 1; }
mkdir -p "facts-$lang" "out-$lang"
sed -n 's/^\.input \([A-Za-z0-9_]*\)(.*/\1/p' "gen/$lang.dl" | while read -r r; do : > "facts-$lang/$r.facts"; done
"./$bin" -F "facts-$lang" -D "out-$lang"
"./$bin" -j 8 -F "facts-$lang" -D "out-$lang"
echo "$lang: ok ($(ls out-$lang | wc -l) relations written)"
done
bash gen/queries/smoke.sh check gen/queries engines/queries
Expand Down Expand Up @@ -408,7 +411,8 @@ jobs:
for lang in $LANGUAGES; do
mkdir -p "facts-$lang" "out-$lang"
sed -n 's/^\.input \([A-Za-z0-9_]*\)(.*/\1/p' "gen/$lang.dl" | while read -r r; do : > "facts-$lang/$r.facts"; done
"./engines/$lang/axiomcode-engine-$lang" -F "facts-$lang" -D "out-$lang"
[ -f "engines/$lang/axiomcode-engine-$lang.parallel" ] || { echo "::error::$lang has no .parallel marker"; exit 1; }
"./engines/$lang/axiomcode-engine-$lang" -j 8 -F "facts-$lang" -D "out-$lang"
done
bash gen/queries/smoke.sh check gen/queries engines/queries
- name: save the engines for the next run
Expand Down
35 changes: 32 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ jobs:
- name: IR staging maps are consistent
run: |
fail=0
# web stages no library (graph/web/templates/staging.conf), so it has no maps to compare
for lang in java typescript python javascript csharp; do
echo "── $lang"
python3 graph/test/tools/check_staging.py --lang "$lang" || fail=1
Expand All @@ -183,7 +184,7 @@ jobs:
- name: engine declarations match the parser schema
run: |
fail=0
for pair in typescript:decls_base_ts.dl python:decls_base_py.dl javascript:decls_base_js.dl csharp:decls_base_cs.dl; do
for pair in typescript:decls_base_ts.dl python:decls_base_py.dl javascript:decls_base_js.dl csharp:decls_base_cs.dl web:decls_base_web.dl; do
lang="${pair%%:*}"; file="${pair#*:}"
if ! diff <(grep '^\.decl' "parser/src/schema/$lang/$file") \
<(grep '^\.decl' "graph/$lang/souffle/decls_base.dl"); then
Expand Down Expand Up @@ -309,6 +310,11 @@ jobs:
# .NET 8 SDK. No flag — scoring against the compiler is all it does.
- lang: csharp
oracle: ''
# Web (HTML + CSS): every case is gated against the oracle's rows (parse5, postcss, css-select,
# graph/test/web/oracle), reviewed by hand; no flag. Its query cases go through the plugin's
# front door, which reads AXIOMCODE_ENGINE (set below to this checkout).
- lang: web
oracle: ''
steps:
- uses: actions/checkout@v4

Expand Down Expand Up @@ -448,8 +454,14 @@ jobs:
path: .souffle-cache
key: souffle-engine-${{ matrix.lang }}-${{ steps.eid.outputs.id }}-${{ hashFiles('graph/pipeline/run-souffle.sh') }}-march-${{ env.AXIOM_ENGINE_MARCH }}

# the web suite records each build's peak memory with /usr/bin/time, which a runner image does not always carry
- name: install time (web)
if: matrix.lang == 'web'
run: sudo apt-get install -y --no-install-recommends time

- name: ${{ matrix.lang }} regression suite
env:
AXIOMCODE_ENGINE: ${{ github.workspace }}
AXIOM_PARSER: ${{ github.workspace }}/parser/dist/index.js
# The driver's default cache is ~/.cache/axiomcode/souffle; point it at the
# directory the cache step above saves and restores, or it never hits.
Expand All @@ -458,11 +470,23 @@ jobs:
# AXIOM_SUITE_JOBS=1 here would run them one at a time, as they used to.
run: bash .github/scripts/run-suite.sh ${{ matrix.lang }} ${{ matrix.oracle }}

- name: web CLI, violation and include checks
if: matrix.lang == 'web'
env:
AXIOMCODE_ENGINE: ${{ github.workspace }}
AXIOM_PARSER: ${{ github.workspace }}/parser/dist/index.js
AXIOM_SOUFFLE_CACHE: ${{ github.workspace }}/.souffle-cache
run: |
rc=0
for s in cli-smoke violations includes; do bash "graph/test/web/$s.sh" || rc=1; done
exit $rc

# THE QUERY LAYER'S CASES (tests/run.py): what impact, path, context, changed and test-impact answer on small
# projects written for one behaviour each. Every case must pass, and a case marked pending that now passes fails
# the run until the mark is removed, so a fix for one shape cannot quietly break another's answer. The suite
# calls the verbs directly, so it checks their own answers, not the front-door rendering (tests/front_door.py).
- name: ${{ matrix.lang }} query cases
if: matrix.lang != 'web'
env:
AXIOM_PARSER: ${{ github.workspace }}/parser/dist/index.js
AXIOM_SOUFFLE_CACHE: ${{ github.workspace }}/.souffle-cache
Expand Down Expand Up @@ -572,9 +596,14 @@ jobs:
set -euo pipefail
command -v souffle && { echo "::error::this runner has souffle; the gate would not prove anything"; exit 1; }
export CODEGRAPH_TGZ="$(ls "$PWD"/artifacts/tgz/*.tgz)"
for lang in java typescript python javascript csharp; do
for lang in java typescript python javascript csharp web; do
# A glob, not ls | head: under pipefail, head exiting early SIGPIPEs ls and fails the step.
cases=(graph/test/"$lang"/cases/*/src)
# a web case is one packed file (cases/<suite>/<case>.case) unpacked first; this one has selectors the engine matches
if [ "$lang" = web ]; then
packed=(graph/test/web/cases/cascade/01-*.case)
python3 graph/test/web/tools/cases.py unpack "${packed[0]}" "$RUNNER_TEMP/web-case"
cases=("$RUNNER_TEMP/web-case/src")
else cases=(graph/test/"$lang"/cases/*/src); fi
case_dir="${cases[0]}"
[ -d "$case_dir" ] || { echo "::error::no $lang case under graph/test/$lang/cases"; exit 1; }
echo "::group::$lang ($case_dir)"
Expand Down
9 changes: 7 additions & 2 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,15 @@ jobs:
- name: every language, installed from the tarballs, no Soufflé
run: |
set -euo pipefail
for pair in java:java typescript:typescript python:python javascript:javascript; do
for pair in java:java typescript:typescript python:python javascript:javascript web:web; do
lang="${pair%%:*}"
# A glob, not ls | head: under pipefail, head exiting early SIGPIPEs ls and fails the step.
cases=(graph/test/"$lang"/cases/*/src)
# a web case is one packed file (cases/<suite>/<case>.case) unpacked first; this one has selectors the engine matches
if [ "$lang" = web ]; then
packed=(graph/test/web/cases/cascade/01-*.case)
python3 graph/test/web/tools/cases.py unpack "${packed[0]}" "$RUNNER_TEMP/web-case"
cases=("$RUNNER_TEMP/web-case/src")
else cases=(graph/test/"$lang"/cases/*/src); fi
case_dir="${cases[0]}"
[ -d "$case_dir" ] || { echo "::error::no $lang case under graph/test/$lang/cases"; exit 1; }
bash .github/scripts/e2e-install.sh artifacts/engines-linux-x64 linux-x64 "$lang" "$case_dir"
Expand Down
Loading
Loading