pi-lens
Version:
Real-time code feedback for pi — LSP, linters, formatters, type-checking, structural analysis & booboo
178 lines (176 loc) • 7.36 kB
YAML
id: require-safety-comment-for-as-unknown-as
valid:
- |
// SAFETY: checked above
const a = x as unknown as Foo;
- |
const b = /* SAFETY: inline */ x as unknown as Foo;
- |
// SAFETY: arg is validated upstream
foo(x as unknown as Foo);
# 2026-08-20 (#1727/#1777): this rule now owns the `as unknown as` shape
# alone, so a single concrete `as` and a concrete CHAIN are both out of scope
# here (the chain belongs to no-chained-type-assertions.yml). Widening the
# pattern back to any assertion reds both.
- 'const c = x as Foo;'
- 'const d = x as A as B;'
# #1847: the `inside:` kind list omitted `export_statement`, so a
# SAFETY: comment above an EXPORTED cast could not satisfy the valve.
# Dropping `export_statement` from the rule's kind list reds this case.
- |
// SAFETY: node exposes this at runtime, absent from @types/node
export const b = (globalThis as unknown as { z: number }).z;
# #1847: same gap for a class-field cast — the kind list omitted
# `public_field_definition`. Dropping it from the rule's kind list
# reds this case.
- |
class Foo {
// SAFETY: server always sends this field at runtime
bar: unknown = (globalThis as unknown as { z: number }).z;
}
# #1852 review (F1): same gap for an enum member's initializer cast —
# the kind list omitted `enum_assignment`. Dropping it from the
# rule's kind list reds this case. Covers plain, `const`, and
# `export` enum alike — `enum_assignment` is the member node itself,
# unaffected by keywords on the enclosing `enum_declaration`.
# (`declare enum` members have no initializer expression to cast, so
# there is nothing to probe for that flavor.)
- |
enum Direction {
// SAFETY: node exposes this at runtime, absent from @types/node
Up = (globalThis as unknown as { z: number }).z,
}
- |
const enum Direction {
// SAFETY: node exposes this at runtime, absent from @types/node
Up = (globalThis as unknown as { z: number }).z,
}
- |
export enum Direction {
// SAFETY: node exposes this at runtime, absent from @types/number
Up = (globalThis as unknown as { z: number }).z,
}
# #1852 review over-suppression probe: two casts inside ONE exported
# declaration under a single SAFETY: comment. This is pre-existing
# behavior, not new — the same one-comment-covers-the-whole-statement
# trade already applied to `lexical_declaration`/`variable_declaration`
# before #1847 (verified: an unexported `const pair = {a: x as unknown
# as Foo, b: y as unknown as Foo}` under one SAFETY: comment was
# already 0 findings on master). The "Scope and known gap" note above
# states the valve is statement-scoped, not cast-scoped, by design:
# "a comment is accepted if it directly precedes... the assertion's
# containing... statement." `export_statement` inherits that same
# trade; it does not introduce a new one. Locked in here so a future
# narrowing of the scope is a deliberate choice, not an accident.
- |
// SAFETY: both fields document the same upstream payload shape
export const pair = { a: x as unknown as Foo, b: y as unknown as Foo };
# #1870: tree-sitter-typescript calls an object-literal member a `pair`.
# A comment directly above that pair is the natural local anchor.
- |
const config = {
// SAFETY: input is validated by the config loader
value: input as unknown as string,
};
- |
configure({
// SAFETY: input is validated by the config loader
value: input as unknown as string,
});
# Direct comments immediately above casts in array elements and call
# arguments are supported by the direct-cast arm.
- |
const values = [
// SAFETY: input is validated by the config loader
input as unknown as string,
];
- |
configure(
// SAFETY: input is validated by the config loader
input as unknown as string,
);
invalid:
- "const a = x as unknown as Foo;"
- |
const b = x as unknown as Foo; // no safety note
- |
// some other comment
const c = x as unknown as Foo;
# The comment must actually claim safety. A comment mentioning the word in
# prose without the `SAFETY:` marker does not clear it — deleting the
# `SAFETY\s*:` regex from the rule reds this case.
- |
// this cast is safe, trust me
const d = x as unknown as Foo;
# #1834: the `follows: {stopBy: end}` scan is unbounded — it must not walk
# past the contiguous comment block into an EARLIER statement's SAFETY:
# comment. A stray SAFETY: comment anywhere earlier in the same block must
# not exempt a later, undocumented cast.
- |
function f(x: unknown, y: unknown) {
// SAFETY: this comment documents a DIFFERENT assertion below.
const a = (y as unknown as string).length;
const b = (x as unknown as string).length;
return a + b;
}
# SAFETY: on cast A must not bleed to cast B directly below it, even with
# no other statement in between.
- |
// SAFETY: documents castA only
const castA = a as unknown as Foo;
const castB = b as unknown as Foo;
# #1847: an exported cast with no SAFETY: comment must still flag —
# adding `export_statement` to the valve must not turn it into a
# blanket exemption for every exported cast.
- "export const b = (globalThis as unknown as { z: number }).z;"
# #1847: an undocumented class-field cast must still flag — adding
# `public_field_definition` to the valve must not exempt every field
# cast regardless of a SAFETY: comment.
- |
class Foo {
bar: unknown = (globalThis as unknown as { z: number }).z;
}
# #1852 review (F1): an undocumented enum-member cast must still flag
# — adding `enum_assignment` to the valve must not exempt every enum
# member cast regardless of a SAFETY: comment.
- |
enum Direction {
Up = (globalThis as unknown as { z: number }).z,
}
# #1852 review over-suppression probe: a SAFETY: comment separated
# from the cast by an unrelated statement must NOT suppress. This is
# already enforced by #1834's `stopBy: {not: {kind: comment}}` bound
# (the comment is no longer the statement's immediate preceding
# sibling once another statement sits between them), but it had no
# dedicated minimal fixture — the existing #1834 cases both pair the
# comment with a DIFFERENT documented cast, not a bare intervening
# statement.
- |
// SAFETY: documents nothing below — an unrelated call sits between
doSomethingUnrelated();
const b = x as unknown as Foo;
# A comment on an unrelated sibling pair must not reach a later pair.
- |
const config = {
unrelated: 1,
// SAFETY: this documents a different property
other: 2,
target: input as unknown as string,
};
# An outer pair comment must not cross into a nested pair.
- |
const config = {
// SAFETY: only the parent property is validated
parent: {
nestedTarget: value as unknown as string,
},
};
# A nested pair comment must not travel outward to a parent cast.
- |
const config = {
parent: value as unknown as string,
// SAFETY: only the nested property is validated
nested: {
child: value as unknown as string,
},
};