Fix async lifecycle ordering, add _spa_init boot phase, update to jqhtml _load_only/_load_render_only flags

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2026-03-06 22:33:38 +00:00
parent 11c95a2886
commit d1ac456279
2718 changed files with 70593 additions and 6320 deletions

View File

@@ -64,6 +64,10 @@ function resolveKey(path, computed = false) {
if (typeof value === "string") return value;
}
}
function resolveInstance(obj) {
const source = resolveSource(obj);
return source.placement === "prototype" ? source.id : null;
}
function resolveSource(obj) {
if (obj.isMemberExpression() && obj.get("property").isIdentifier({
name: "prototype"
@@ -89,22 +93,23 @@ function resolveSource(obj) {
}
const path = resolve$1(obj);
switch (path == null ? void 0 : path.type) {
case "NullLiteral":
return {
id: null,
placement: null
};
case "RegExpLiteral":
return {
id: "RegExp",
placement: "prototype"
};
case "FunctionExpression":
return {
id: "Function",
placement: "prototype"
};
case "StringLiteral":
case "TemplateLiteral":
return {
id: "String",
placement: "prototype"
};
case "NumberLiteral":
case "NumericLiteral":
return {
id: "Number",
placement: "prototype"
@@ -114,6 +119,11 @@ function resolveSource(obj) {
id: "Boolean",
placement: "prototype"
};
case "BigIntLiteral":
return {
id: "BigInt",
placement: "prototype"
};
case "ObjectExpression":
return {
id: "Object",
@@ -124,6 +134,192 @@ function resolveSource(obj) {
id: "Array",
placement: "prototype"
};
case "FunctionExpression":
case "ArrowFunctionExpression":
case "ClassExpression":
return {
id: "Function",
placement: "prototype"
};
// new Constructor() -> resolve the constructor name
case "NewExpression":
{
const calleeId = resolveId(path.get("callee"));
if (calleeId) return {
id: calleeId,
placement: "prototype"
};
return {
id: null,
placement: null
};
}
// Unary expressions -> result type depends on operator
case "UnaryExpression":
{
const {
operator
} = path.node;
if (operator === "typeof") return {
id: "String",
placement: "prototype"
};
if (operator === "!" || operator === "delete") return {
id: "Boolean",
placement: "prototype"
};
// Unary + always produces Number (throws on BigInt)
if (operator === "+") return {
id: "Number",
placement: "prototype"
};
// Unary - and ~ can produce Number or BigInt depending on operand
if (operator === "-" || operator === "~") {
const arg = resolveInstance(path.get("argument"));
if (arg === "BigInt") return {
id: "BigInt",
placement: "prototype"
};
if (arg !== null) return {
id: "Number",
placement: "prototype"
};
return {
id: null,
placement: null
};
}
return {
id: null,
placement: null
};
}
// ++i, i++ produce Number or BigInt depending on the argument
case "UpdateExpression":
{
const arg = resolveInstance(path.get("argument"));
if (arg === "BigInt") return {
id: "BigInt",
placement: "prototype"
};
if (arg !== null) return {
id: "Number",
placement: "prototype"
};
return {
id: null,
placement: null
};
}
// Binary expressions -> result type depends on operator
case "BinaryExpression":
{
const {
operator
} = path.node;
if (operator === "==" || operator === "!=" || operator === "===" || operator === "!==" || operator === "<" || operator === ">" || operator === "<=" || operator === ">=" || operator === "instanceof" || operator === "in") {
return {
id: "Boolean",
placement: "prototype"
};
}
// >>> always produces Number
if (operator === ">>>") {
return {
id: "Number",
placement: "prototype"
};
}
// Arithmetic and bitwise operators can produce Number or BigInt
if (operator === "-" || operator === "*" || operator === "/" || operator === "%" || operator === "**" || operator === "&" || operator === "|" || operator === "^" || operator === "<<" || operator === ">>") {
const left = resolveInstance(path.get("left"));
const right = resolveInstance(path.get("right"));
if (left === "BigInt" && right === "BigInt") {
return {
id: "BigInt",
placement: "prototype"
};
}
if (left !== null && right !== null) {
return {
id: "Number",
placement: "prototype"
};
}
return {
id: null,
placement: null
};
}
// + depends on operand types: string wins, otherwise number or bigint
if (operator === "+") {
const left = resolveInstance(path.get("left"));
const right = resolveInstance(path.get("right"));
if (left === "String" || right === "String") {
return {
id: "String",
placement: "prototype"
};
}
if (left === "Number" && right === "Number") {
return {
id: "Number",
placement: "prototype"
};
}
if (left === "BigInt" && right === "BigInt") {
return {
id: "BigInt",
placement: "prototype"
};
}
}
return {
id: null,
placement: null
};
}
// (a, b, c) -> the result is the last expression
case "SequenceExpression":
{
const expressions = path.get("expressions");
return resolveSource(expressions[expressions.length - 1]);
}
// a = b -> the result is the right side
case "AssignmentExpression":
{
if (path.node.operator === "=") {
return resolveSource(path.get("right"));
}
return {
id: null,
placement: null
};
}
// a ? b : c -> if both branches resolve to the same type, use it
case "ConditionalExpression":
{
const consequent = resolveSource(path.get("consequent"));
const alternate = resolveSource(path.get("alternate"));
if (consequent.id && consequent.id === alternate.id) {
return consequent;
}
return {
id: null,
placement: null
};
}
// (expr) -> unwrap parenthesized expressions
case "ParenthesizedExpression":
return resolveSource(path.get("expression"));
// TypeScript / Flow type wrappers -> unwrap to the inner expression
case "TSAsExpression":
case "TSSatisfiesExpression":
case "TSNonNullExpression":
case "TSInstantiationExpression":
case "TSTypeAssertion":
case "TypeCastExpression":
return resolveSource(path.get("expression"));
}
return {
id: null,