mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-07 17:28:23 +01:00
feat(diff-scope): template UI in .ts/.js counts as frontend; receipt records the static design pass (GST-1718) (#4112)
* feat(diff-scope): template UI in .ts/.js counts as frontend; receipt records the static design pass (GST-1718) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test: regenerate ship goldens for the static design-review line (GST-1718) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: pre-landing review fixes Review-Finding: p1/specialist-batched#1 reader=specialist Review-Finding: p1/red-team#1 reader=red-team Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: count edits inside tagged templates and spaced template tags as frontend Review-Finding: v1/outside-voice#1 reader=outside-voice Review-Finding: v1/adversarial-native#1 reader=adversarial-native Review-Finding: v1/outside-voice#2 reader=outside-voice Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: one set comparison per template file instead of a grep per changed line Review-Finding: p2/red-team#2 reader=red-team Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs(changelog): GST-1718 fragment covers edits inside tagged templates Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs(ship-policy): design record wording matches the in-template rule Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
40071a4237
commit
5862765a20
20 files changed
+273
-14
No files matched your search
@@ -349,6 +349,99 @@ for f in ${FILES_LIST[@]+"${FILES_LIST[@]}"}; do
|
||||
fi
|
||||
done
|
||||
|
||||
# Template UI (GST-1718): a screen written as a tagged template inside a .ts or
|
||||
# .js file (Lit, lit-html, htm, uhtml) is frontend when a changed line in that
|
||||
# file carries markup. qm#3186 rendered its persona page this way and read
|
||||
# SCOPE_FRONTEND=false, so /ship's design checks skipped it silently. This arm
|
||||
# sets FRONTEND only; the backend arm above already counted the file, so a Lit
|
||||
# edit reads both, as .dart does. lib/frontend-scope.ts stays path-only (the
|
||||
# design detector scans paths). A template file holds a tagged template at the
|
||||
# head or the base (a deleted screen counts). A changed line counts when it sits
|
||||
# inside a tagged template on its side of the diff (CSS declarations and ${}
|
||||
# bindings included), or carries markup: a tagged template, an element tag not
|
||||
# preceded by an identifier (Promise<void> is not markup), class= or style=;
|
||||
# comment lines never count as markup. Paths are NUL-delimited, as in _collect.
|
||||
# Every git call tolerates failure under set -e.
|
||||
TEMPLATE_TAG_RE='(^|[^A-Za-z0-9_$.])(html|css|svg)[[:space:]]*`'
|
||||
MARKUP_LINE_RE="${TEMPLATE_TAG_RE}|(^|[^A-Za-z0-9_$])</?[a-z][a-z0-9-]*([[:space:]/>]|$)|(^|[^A-Za-z0-9_-])(class|style)="
|
||||
if [ "$FRONTEND" = false ]; then
|
||||
TPL_CANDIDATES=()
|
||||
for f in "${FILES_LIST[@]}"; do
|
||||
case "$f" in
|
||||
*.test.*|*.spec.*|test/*|tests/*|spec/*|__tests__/*|cypress/*|e2e/*) continue ;;
|
||||
*.ts|*.js|*.mjs|*.cjs|*.mts|*.cts) [[ "$f" =~ $TEST_PATH_RE ]] || TPL_CANDIDATES+=("$f") ;;
|
||||
esac
|
||||
done
|
||||
if [ "${#TPL_CANDIDATES[@]}" -gt 0 ]; then
|
||||
_root=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
|
||||
_g() { git --literal-pathspecs -C "$_root" "$@" 2>/dev/null || true; }
|
||||
_tpl_lines() {
|
||||
awk '
|
||||
function top() { return sp ? st[sp] : "" }
|
||||
{
|
||||
line = $0; n = length(line); hit = (tags > 0); i = 1
|
||||
while (i <= n) {
|
||||
c = substr(line, i, 1); t = top()
|
||||
if (blk) { if (substr(line, i, 2) == "*/") { blk = 0; i += 2 } else i++; continue }
|
||||
if (t == "T" || t == "U") {
|
||||
if (c == "\\") { i += 2; continue }
|
||||
if (c == "`") { if (t == "T") tags--; sp--; i++; continue }
|
||||
if (substr(line, i, 2) == "${") { st[++sp] = "E"; dep[sp] = 0; i += 2; continue }
|
||||
i++; continue
|
||||
}
|
||||
if (c == "\"" || c == "'\''") { q = c; i++; while (i <= n && substr(line, i, 1) != q) { if (substr(line, i, 1) == "\\") i++; i++ } i++; continue }
|
||||
if (substr(line, i, 2) == "//") break
|
||||
if (substr(line, i, 2) == "/*") { blk = 1; i += 2; continue }
|
||||
if (c == "{" && t == "E") { dep[sp]++; i++; continue }
|
||||
if (c == "}" && t == "E") { if (dep[sp] == 0) sp--; else dep[sp]--; i++; continue }
|
||||
if (c == "`") {
|
||||
if (substr(line, 1, i - 1) ~ /(^|[^A-Za-z0-9_$.])(html|css|svg)[ \t]*$/) { st[++sp] = "T"; tags++; hit = 1 } else st[++sp] = "U"
|
||||
i++; continue
|
||||
}
|
||||
i++
|
||||
}
|
||||
if (hit) print NR
|
||||
}'
|
||||
}
|
||||
_hunk_lines() {
|
||||
awk '/^@@ /{ split($2, o, ","); split($3, a, ","); os = substr(o[1], 2) + 0; oc = (o[2] == "") ? 1 : o[2] + 0; ns = substr(a[1], 2) + 0; nc = (a[2] == "") ? 1 : a[2] + 0
|
||||
for (k = 0; k < oc; k++) print "o " os + k; for (k = 0; k < nc; k++) print "n " ns + k }'
|
||||
}
|
||||
_mb=$(git merge-base "$BASE_SHA" "${HEAD_REF:-HEAD}" 2>/dev/null || echo "$BASE_SHA")
|
||||
TPL_FILES=()
|
||||
if [ -n "$HEAD_REF" ]; then
|
||||
while IFS= read -r -d '' f; do [ -n "$f" ] && TPL_FILES+=("${f#"$HEAD_REF":}"); done < <(_g grep -l -z -E -e "$TEMPLATE_TAG_RE" "$HEAD_REF" -- "${TPL_CANDIDATES[@]}")
|
||||
else
|
||||
while IFS= read -r -d '' f; do [ -n "$f" ] && TPL_FILES+=("$f"); done < <(_g grep -l -z -E --untracked -e "$TEMPLATE_TAG_RE" -- "${TPL_CANDIDATES[@]}")
|
||||
fi
|
||||
while IFS= read -r -d '' f; do [ -n "$f" ] && TPL_FILES+=("${f#"$_mb":}"); done < <(_g grep -l -z -E -e "$TEMPLATE_TAG_RE" "$_mb" -- "${TPL_CANDIDATES[@]}")
|
||||
if [ "${#TPL_FILES[@]}" -gt 0 ]; then
|
||||
if [ -n "$HEAD_REF" ]; then
|
||||
_d=$(_g diff -U0 "$BASE_SHA...$HEAD_REF" -- "${TPL_FILES[@]}")
|
||||
else
|
||||
_d=$(_g diff -U0 "$_mb" -- "${TPL_FILES[@]}")
|
||||
[ -n "$(_g ls-files --others --exclude-standard -- "${TPL_FILES[@]}")" ] && FRONTEND=true
|
||||
fi
|
||||
_changed=$(grep -E '^[+-]' <<<"$_d" | grep -v -E '^(\+\+\+|---) (a/|b/|/dev/null)' | grep -v -E '^[+-][[:space:]]*(//|/\*|\*)' || true)
|
||||
if [ "$FRONTEND" = false ] && [ -n "$_changed" ] && grep -q -E -e "$MARKUP_LINE_RE" <<<"$_changed"; then FRONTEND=true; fi
|
||||
for f in "${TPL_FILES[@]}"; do
|
||||
[ "$FRONTEND" = true ] && break
|
||||
_old=$(_g show "$_mb:$f" | _tpl_lines)
|
||||
if [ -n "$HEAD_REF" ]; then
|
||||
_fd=$(_g diff -U0 "$BASE_SHA...$HEAD_REF" -- "$f")
|
||||
_new=$(_g show "$HEAD_REF:$f" | _tpl_lines)
|
||||
else
|
||||
_fd=$(_g diff -U0 "$_mb" -- "$f")
|
||||
_new=
|
||||
if [ -f "$_root/$f" ]; then _new=$(_tpl_lines < "$_root/$f"); fi
|
||||
fi
|
||||
if awk 'FNR == NR { s[$0] = 1; next } ($0 in s) { f = 1; exit } END { exit !f }' \
|
||||
<(sed 's/^/o /' <<<"$_old"; sed 's/^/n /' <<<"$_new") <(_hunk_lines <<<"$_fd"); then FRONTEND=true; fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
_print_flags
|
||||
|
||||
# Changed files but ZERO category matches (#2526): a classifier bug, an
|
||||
|
||||
Reference in new issue
Block a user