mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-01 07:33:12 +08:00
- Preserve class property views, opaque record identity, and nullable structural conversions - Run package metadata transforms and TypeScript option merges as native code - Serialize live typed records with opaque payloads and JSON hooks
79 lines
4.0 KiB
TypeScript
79 lines
4.0 KiB
TypeScript
import type { AstFile } from "../../../packages/compiler/src/frontend/ts7/ast-node.js";
|
|
import type { Node, SourceFile, NodeArray, Statement } from "../../../packages/compiler/src/frontend/ts7/ast-types.js";
|
|
import * as ts from "../../../packages/compiler/src/frontend/ts7/ast-guards.generated.js";
|
|
import { KIND_NODE_LIST } from "../../../packages/compiler/src/frontend/ts7/ast-schema.generated.js";
|
|
import { tokenToString } from "../../../packages/compiler/src/frontend/ts7/ast-tokens.generated.js";
|
|
import { SyntaxKind } from "../../../packages/compiler/src/frontend/ts7/enums.js";
|
|
|
|
function check(value: boolean, message: string): void { if (!value) throw new Error(message); }
|
|
|
|
function checkStatements(nodes: NodeArray<Statement>, source: SourceFile): void {
|
|
check(nodes === source.statements, "typed statement array identity");
|
|
for (const statement of nodes) {
|
|
check(statement.parent === source && statement.getSourceFile() === source, "typed source identity");
|
|
check(ts.isStatement(statement), "statement kind predicate");
|
|
}
|
|
}
|
|
|
|
/** All narrowed values are consumed by native operations, so a structural
|
|
* record copy or a wrong getter ABI cannot pass as a mere successful load. */
|
|
export function checkAstViews(file: AstFile): void {
|
|
const source: SourceFile = file.sourceFile;
|
|
checkStatements(source.statements, source);
|
|
check(source.parent === undefined && !ts.isIdentifier(source.parent), "missing root parent");
|
|
let identifiers = 0;
|
|
let strings = 0;
|
|
let declarations = 0;
|
|
let methods = 0;
|
|
let calls = 0;
|
|
let binaries = 0;
|
|
let bodies = 0;
|
|
let names = 0;
|
|
let modifiers = 0;
|
|
for (let index = 1; index < file.wire.nodeCount; index++) {
|
|
if (file.wire.kind(index) === KIND_NODE_LIST) continue;
|
|
const node: Node = file.node(index);
|
|
// These are the structural views used by the production frontend.
|
|
// The cast changes the checker surface while the actual value remains
|
|
// one AstNode; reads must use its original lazy getters and caches.
|
|
const body = (node as { body?: Node }).body;
|
|
const name = (node as { name?: Node })["name"];
|
|
const flags = (node as { modifiers?: readonly Node[] }).modifiers;
|
|
check(body === node.body && name === node.name, "structural child getter identity");
|
|
check(flags === node.modifiers, "structural list getter identity");
|
|
if (body !== undefined) { bodies++; check(body.parent === node, "structural body parent"); }
|
|
if (name !== undefined) { names++; check(name.parent === node, "structural name parent"); }
|
|
if (flags !== undefined) {
|
|
modifiers += flags.length;
|
|
for (const modifier of flags) check(modifier.parent === node, "structural modifier parent");
|
|
}
|
|
if (ts.isIdentifier(node)) {
|
|
identifiers += node.text.length;
|
|
check(node.getSourceFile() === source, "identifier source identity");
|
|
check(!ts.isTypeNode(node), "identifier is not a type node");
|
|
}
|
|
if (ts.isStringLiteral(node)) strings += node.text.toUpperCase().length;
|
|
if (ts.isVariableDeclarationList(node)) {
|
|
declarations += node.declarations.length;
|
|
for (const declaration of node.declarations) check(declaration.parent === node, "declaration identity");
|
|
}
|
|
if (ts.isClassDeclaration(node)) {
|
|
for (const member of node.members) {
|
|
if (ts.isMethodDeclaration(member)) methods += member.parameters.length;
|
|
}
|
|
}
|
|
if (ts.isCallExpression(node)) {
|
|
calls += node.arguments.length;
|
|
check(node.expression.parent === node, "call callee identity");
|
|
}
|
|
if (ts.isBinaryExpression(node)) {
|
|
binaries++;
|
|
check(node.left === node.childNode("left") && node.right === node.childNode("right"), "binary child identity");
|
|
check(tokenToString(node.operatorToken.kind) !== undefined, "operator spelling");
|
|
}
|
|
}
|
|
check(identifiers > 10 && strings > 0 && declarations > 3 && methods > 0 && calls > 0 && binaries > 0, "typed AST paths executed");
|
|
check(bodies > 0 && names > 0 && modifiers > 0, "structural AST paths executed");
|
|
check(tokenToString(SyntaxKind.EqualsGreaterThanToken) === "=>", "native token lookup");
|
|
}
|