mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-27 06:43:19 +08:00
Place a quoted name field among an error's fields
The position of an Error subclass's own `name` among its fields was found from identifier keys only, so a quoted `"name"` field, other quoted fields, and `this["name"] = ...` in a constructor were not seen, and `name` was listed last. Field keys and constructor assignments now read any statically spelled key: an identifier, a quoted string, a number in its canonical spelling, or a computed string literal.
This commit is contained in:
@@ -6,17 +6,27 @@ type ErrorClassLink = Pick<ClassInfo, "decl" | "ctor" | "paramProps"> & {
|
||||
base: ErrorClassLink | null;
|
||||
};
|
||||
|
||||
/** Whether `node` is an assignment to `this.<name>`, and the name. */
|
||||
/** The property key a member or element-access name spells statically:
|
||||
* an identifier, a quoted string, a number in its canonical spelling, or a
|
||||
* computed string literal. Null for other keys. */
|
||||
function staticKeyText(name: ts.Node): string | null {
|
||||
if (ts.isIdentifier(name) || ts.isStringLiteral(name)) return name.text;
|
||||
if (ts.isNumericLiteral(name)) return String(Number(name.text));
|
||||
if (ts.isComputedPropertyName(name)) return staticKeyText(name.expression);
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Whether `node` is an assignment to `this.<name>` or `this["<name>"]`,
|
||||
* and the name. */
|
||||
function thisAssignmentName(node: ts.Node): string | null {
|
||||
if (!ts.isBinaryExpression(node) || node.operatorToken.kind !== ts.SyntaxKind.EqualsToken)
|
||||
return null;
|
||||
const target = node.left;
|
||||
if (
|
||||
!ts.isPropertyAccessExpression(target) ||
|
||||
target.expression.kind !== ts.SyntaxKind.ThisKeyword
|
||||
)
|
||||
return null;
|
||||
return ts.isIdentifier(target.name) ? target.name.text : null;
|
||||
if (ts.isPropertyAccessExpression(target) && target.expression.kind === ts.SyntaxKind.ThisKeyword)
|
||||
return ts.isIdentifier(target.name) ? target.name.text : null;
|
||||
if (ts.isElementAccessExpression(target) && target.expression.kind === ts.SyntaxKind.ThisKeyword)
|
||||
return staticKeyText(target.argumentExpression);
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Where an Error subclass instance's own `name` sits among its fields when
|
||||
@@ -45,15 +55,17 @@ export function errorNameAfterField(
|
||||
for (const link of chain) {
|
||||
for (const property of link.paramProps ?? []) create(property.name);
|
||||
for (const member of link.decl!.members.nodes) {
|
||||
if (!ts.isPropertyDeclaration(member) || !ts.isIdentifier(member.name)) continue;
|
||||
if (!ts.isPropertyDeclaration(member)) continue;
|
||||
const key = staticKeyText(member.name);
|
||||
if (key === null) continue;
|
||||
if (
|
||||
member.modifiers?.nodes.some(
|
||||
(m) => m.kind === ts.SyntaxKind.StaticKeyword || m.kind === ts.SyntaxKind.DeclareKeyword,
|
||||
)
|
||||
)
|
||||
continue;
|
||||
if (member.name.text === "name") return last;
|
||||
create(member.name.text);
|
||||
if (key === "name") return last;
|
||||
create(key);
|
||||
}
|
||||
const body = link.ctor?.body;
|
||||
if (!body) continue;
|
||||
|
||||
@@ -57,6 +57,11 @@ class NamedChild extends FieldBase {
|
||||
}
|
||||
}
|
||||
|
||||
class QuotedName extends Error {
|
||||
override "name" = "QuotedName";
|
||||
"quoted-extra" = 1;
|
||||
}
|
||||
|
||||
class Unnamed extends Error {
|
||||
extra = 1;
|
||||
}
|
||||
@@ -83,6 +88,7 @@ show("later field", new LaterNameField("c"));
|
||||
show("code then name", new CodeThenName("d"));
|
||||
show("child of named", new ChildOfNamed("e"));
|
||||
show("named child", new NamedChild("f"));
|
||||
show("quoted name field", new QuotedName("q"));
|
||||
|
||||
const late = new Unnamed("g");
|
||||
late.name = "Late";
|
||||
|
||||
@@ -49,6 +49,15 @@ class Derived extends Base {
|
||||
}
|
||||
}
|
||||
|
||||
class ElementName extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
this.first = 1;
|
||||
this["name"] = "ElementName";
|
||||
this.second = 2;
|
||||
}
|
||||
}
|
||||
|
||||
class Unnamed extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
@@ -73,6 +82,7 @@ show("first", new AssignedFirst("b"));
|
||||
show("declared field", new DeclaredField("c"));
|
||||
show("name field", new NameField("d"));
|
||||
show("derived", new Derived("e"));
|
||||
show("element name", new ElementName("g"));
|
||||
|
||||
const late = new Unnamed("f");
|
||||
late.name = "Late";
|
||||
|
||||
Reference in New Issue
Block a user