Skip to content

Commit aafa22e

Browse files
committed
Improved messages
1 parent 24b9140 commit aafa22e

File tree

3 files changed

+187
-140
lines changed

3 files changed

+187
-140
lines changed

src/Shared/diagnostics.ts

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -251,27 +251,31 @@ export const errors = {
251251
];
252252
}),
253253

254-
unityMacroExpectsAirshipComponentTypeArgument: errorWithContext((type: string, isUnityObjectType: boolean) => {
255-
if (isUnityObjectType) {
256-
return [
257-
`${type} is a Unity Component, not an Airship Component`,
258-
suggestion("Change GetAirshipComponent to GetComponent<" + type + ">()"),
259-
];
260-
} else {
261-
return [`${type} is not a derived type of AirshipBehaviour`];
262-
}
263-
}),
254+
unityMacroExpectsAirshipComponentTypeArgument: errorWithContext(
255+
(type: string, name: string, isUnityObjectType: boolean) => {
256+
if (isUnityObjectType) {
257+
return [
258+
`${type} is a Unity Component, not an Airship Component`,
259+
suggestion(`Change this call to ${name}<${type}>()`),
260+
];
261+
} else {
262+
return [`${type} is not a derived type of AirshipBehaviour`];
263+
}
264+
},
265+
),
264266

265-
unityMacroExpectsComponentTypeArgument: errorWithContext((type: string, isAirshipBehaviourType: boolean) => {
266-
if (isAirshipBehaviourType) {
267-
return [
268-
`${type} is an Airship Component, not a Unity Component`,
269-
suggestion("Change GetComponent to GetAirshipComponent<" + type + ">()"),
270-
];
271-
} else {
272-
return [`${type} is not a derived type of Component`];
273-
}
274-
}),
267+
unityMacroExpectsComponentTypeArgument: errorWithContext(
268+
(type: string, name: string, isAirshipBehaviourType: boolean) => {
269+
if (isAirshipBehaviourType) {
270+
return [
271+
`${type} is an Airship Component, not a Unity Component`,
272+
suggestion(`Change this call to ${name}<${type}>()`),
273+
];
274+
} else {
275+
return [`${type} is not a derived type of Component`];
276+
}
277+
},
278+
),
275279

276280
decoratorParamsLiteralsOnly: error(
277281
"Airship Behaviour decorators only accept literal `string`, `boolean` or `number` values",
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import luau from "@roblox-ts/luau-ast";
2+
import { errors, warnings } from "Shared/diagnostics";
3+
import { DiagnosticService } from "TSTransformer/classes/DiagnosticService";
4+
import { MacroList, PropertyCallMacro } from "TSTransformer/macros/types";
5+
import { isUnityObjectType } from "TSTransformer/util/airshipBehaviourUtils";
6+
import { convertToIndexableExpression } from "TSTransformer/util/convertToIndexableExpression";
7+
import { isAirshipBehaviourType, isAirshipBehaviourTypeNode } from "TSTransformer/util/extendsAirshipBehaviour";
8+
import ts from "typescript";
9+
10+
const expectAirshipComponentGeneric = (
11+
name: string,
12+
propertyCallMacro: PropertyCallMacro,
13+
index: 0 = 0,
14+
): PropertyCallMacro => {
15+
return (state, node, expression, args) => {
16+
if (node.typeArguments) {
17+
const typeNode = node.typeArguments[index];
18+
if (!isAirshipBehaviourTypeNode(state, typeNode)) {
19+
DiagnosticService.addDiagnostic(
20+
errors.unityMacroExpectsAirshipComponentTypeArgument(
21+
node,
22+
state.typeChecker.typeToString(state.typeChecker.getTypeFromTypeNode(node.typeArguments[0])),
23+
getAirshipMacroAlternativeName(propertyCallMacro)!,
24+
isUnityObjectType(state, state.getType(typeNode)),
25+
),
26+
);
27+
}
28+
}
29+
30+
return propertyCallMacro(state, node, expression, args);
31+
};
32+
};
33+
34+
const expectUnityComponentGeneric = (
35+
name: string,
36+
propertyCallMacro: PropertyCallMacro,
37+
index: 0 = 0,
38+
): PropertyCallMacro => {
39+
return (state, node, expression, args) => {
40+
if (node.typeArguments) {
41+
const type = state.getType(node.typeArguments[index]);
42+
if (!isUnityObjectType(state, type)) {
43+
DiagnosticService.addDiagnostic(
44+
errors.unityMacroExpectsComponentTypeArgument(
45+
node,
46+
state.typeChecker.typeToString(state.typeChecker.getTypeFromTypeNode(node.typeArguments[0])),
47+
getAirshipMacroAlternativeName(propertyCallMacro)!,
48+
isAirshipBehaviourType(state, type, true),
49+
),
50+
);
51+
}
52+
}
53+
54+
return propertyCallMacro(state, node, expression, args);
55+
};
56+
};
57+
58+
const makeTypeArgumentAsStringMacro =
59+
(method: string, requiresArgument = true, defaultTypeName?: string): PropertyCallMacro =>
60+
(state, node, expression, args) => {
61+
let type: ts.Type | undefined;
62+
63+
if (node.typeArguments) {
64+
type = state.getType(node.typeArguments[0]);
65+
} else if (ts.isAsExpression(node.parent)) {
66+
type = state.getType(node.parent.type);
67+
DiagnosticService.addDiagnostic(
68+
warnings.unityMacroAsExpressionWarning(method, state.typeChecker.typeToString(type))(node.parent),
69+
);
70+
}
71+
72+
if (requiresArgument && !defaultTypeName && !type && args.length === 0) {
73+
DiagnosticService.addSingleDiagnostic(errors.unityMacroTypeArgumentRequired(node, method));
74+
}
75+
76+
if (type) {
77+
args.unshift(luau.string(state.typeChecker.typeToString(type)));
78+
return luau.create(luau.SyntaxKind.MethodCallExpression, {
79+
expression: convertToIndexableExpression(expression),
80+
name: method,
81+
args: luau.list.make(...args),
82+
});
83+
} else {
84+
if (defaultTypeName !== undefined) {
85+
args.unshift(luau.string(defaultTypeName));
86+
}
87+
88+
return luau.create(luau.SyntaxKind.MethodCallExpression, {
89+
expression: convertToIndexableExpression(expression),
90+
name: method,
91+
args: luau.list.make(...args),
92+
});
93+
}
94+
};
95+
96+
const COMPONENT_MACROS = {
97+
GetComponent: makeTypeArgumentAsStringMacro("GetComponent"),
98+
GetComponents: makeTypeArgumentAsStringMacro("GetComponents"),
99+
AddComponent: makeTypeArgumentAsStringMacro("AddComponent"),
100+
GetComponentInChildren: makeTypeArgumentAsStringMacro("GetComponentInChildren"),
101+
GetComponentsInChildren: makeTypeArgumentAsStringMacro("GetComponentsInChildren"),
102+
GetComponentInParent: makeTypeArgumentAsStringMacro("GetComponentInParent"),
103+
GetComponentsInParent: makeTypeArgumentAsStringMacro("GetComponentsInParent"),
104+
} satisfies MacroList<PropertyCallMacro>;
105+
106+
const AIRSHIP_COMPONENT_MACROS = {
107+
GetAirshipComponent: makeTypeArgumentAsStringMacro("GetAirshipComponent"),
108+
GetAirshipComponents: makeTypeArgumentAsStringMacro("GetAirshipComponents"),
109+
AddAirshipComponent: makeTypeArgumentAsStringMacro("AddAirshipComponent"),
110+
GetAirshipComponentsInChildren: makeTypeArgumentAsStringMacro("GetAirshipComponentsInChildren"),
111+
GetAirshipComponentInChildren: makeTypeArgumentAsStringMacro("GetAirshipComponentInChildren"),
112+
GetAirshipComponentInParent: makeTypeArgumentAsStringMacro("GetAirshipComponentInParent"),
113+
GetAirshipComponentsInParent: makeTypeArgumentAsStringMacro("GetAirshipComponentsInParent"),
114+
} satisfies MacroList<PropertyCallMacro>;
115+
116+
const ALTERNATIVE_NAMES: ReadonlyArray<
117+
[airship: PropertyCallMacro, unityName: keyof typeof COMPONENT_MACROS | keyof typeof AIRSHIP_COMPONENT_MACROS]
118+
> = [
119+
[COMPONENT_MACROS.AddComponent, "AddAirshipComponent"],
120+
[COMPONENT_MACROS.GetComponent, "GetAirshipComponent"],
121+
[COMPONENT_MACROS.GetComponentInChildren, "GetAirshipComponentInChildren"],
122+
[COMPONENT_MACROS.GetComponentInParent, "GetAirshipComponentInParent"],
123+
[COMPONENT_MACROS.GetComponents, "GetAirshipComponents"],
124+
[COMPONENT_MACROS.GetComponentsInChildren, "GetAirshipComponentsInChildren"],
125+
[COMPONENT_MACROS.GetComponentsInParent, "GetAirshipComponentsInParent"],
126+
127+
[AIRSHIP_COMPONENT_MACROS.AddAirshipComponent, "AddComponent"],
128+
[AIRSHIP_COMPONENT_MACROS.GetAirshipComponent, "GetComponent"],
129+
[AIRSHIP_COMPONENT_MACROS.GetAirshipComponentInChildren, "GetComponentInChildren"],
130+
[AIRSHIP_COMPONENT_MACROS.GetAirshipComponentInParent, "GetComponentInParent"],
131+
[AIRSHIP_COMPONENT_MACROS.GetAirshipComponents, "GetComponents"],
132+
[AIRSHIP_COMPONENT_MACROS.GetAirshipComponentsInChildren, "GetComponentsInChildren"],
133+
[AIRSHIP_COMPONENT_MACROS.GetAirshipComponentsInParent, "GetComponentsInParent"],
134+
];
135+
136+
export const UNITY_GAMEOBJECT_METHODS: MacroList<PropertyCallMacro> = {};
137+
for (const [macro, call] of Object.entries(AIRSHIP_COMPONENT_MACROS)) {
138+
UNITY_GAMEOBJECT_METHODS[macro] = expectAirshipComponentGeneric(macro, call);
139+
}
140+
for (const [macro, call] of Object.entries(COMPONENT_MACROS)) {
141+
UNITY_GAMEOBJECT_METHODS[macro] = expectUnityComponentGeneric(macro, call);
142+
}
143+
144+
export const UNITY_STATIC_GAMEOBJECT_METHODS: MacroList<PropertyCallMacro> = {
145+
FindObjectOfType: makeTypeArgumentAsStringMacro("FindObjectOfType"),
146+
FindObjectsByType: makeTypeArgumentAsStringMacro("FindObjectsByType"),
147+
};
148+
export const UNITY_COMPONENT_METHODS: MacroList<PropertyCallMacro> = {
149+
GetComponent: COMPONENT_MACROS.GetComponent,
150+
GetComponents: COMPONENT_MACROS.GetComponents,
151+
};
152+
export const UNITY_OBJECT_METHODS: MacroList<PropertyCallMacro> = {
153+
IsA: makeTypeArgumentAsStringMacro("IsA"),
154+
};
155+
156+
function getAirshipMacroAlternativeName(propertyMacro: PropertyCallMacro): string | undefined {
157+
return ALTERNATIVE_NAMES.find(f => f[0] === propertyMacro)?.[1];
158+
}

src/TSTransformer/macros/propertyCallMacros.ts

Lines changed: 5 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import luau from "@roblox-ts/luau-ast";
2-
import { errors, warnings } from "Shared/diagnostics";
32
import { assert } from "Shared/util/assert";
4-
import { DiagnosticService } from "TSTransformer/classes/DiagnosticService";
53
import { TransformState } from "TSTransformer/classes/TransformState";
4+
import {
5+
UNITY_COMPONENT_METHODS,
6+
UNITY_GAMEOBJECT_METHODS,
7+
UNITY_STATIC_GAMEOBJECT_METHODS,
8+
} from "TSTransformer/macros/airship/propertyCallMacros";
69
import { MacroList, PropertyCallMacro } from "TSTransformer/macros/types";
7-
import { isUnityObjectType } from "TSTransformer/util/airshipBehaviourUtils";
810
import { convertToIndexableExpression } from "TSTransformer/util/convertToIndexableExpression";
9-
import { isAirshipBehaviourType, isAirshipBehaviourTypeNode } from "TSTransformer/util/extendsAirshipBehaviour";
1011
import { isUsedAsStatement } from "TSTransformer/util/isUsedAsStatement";
1112
import { offset } from "TSTransformer/util/offset";
1213
import { isDefinitelyType, isNumberType, isStringType } from "TSTransformer/util/types";
@@ -935,122 +936,6 @@ const PROMISE_METHODS: MacroList<PropertyCallMacro> = {
935936
}),
936937
};
937938

938-
const expectAirshipComponentGeneric = (propertyCallMacro: PropertyCallMacro, index: 0 = 0): PropertyCallMacro => {
939-
return (state, node, expression, args) => {
940-
if (node.typeArguments) {
941-
const typeNode = node.typeArguments[index];
942-
if (!isAirshipBehaviourTypeNode(state, typeNode)) {
943-
DiagnosticService.addDiagnostic(
944-
errors.unityMacroExpectsAirshipComponentTypeArgument(
945-
node,
946-
state.typeChecker.typeToString(state.typeChecker.getTypeFromTypeNode(node.typeArguments[0])),
947-
isUnityObjectType(state, state.getType(typeNode)),
948-
),
949-
);
950-
}
951-
}
952-
953-
return propertyCallMacro(state, node, expression, args);
954-
};
955-
};
956-
957-
const expectUnityComponentGeneric = (propertyCallMacro: PropertyCallMacro, index: 0 = 0): PropertyCallMacro => {
958-
return (state, node, expression, args) => {
959-
if (node.typeArguments) {
960-
const type = state.getType(node.typeArguments[index]);
961-
if (!isUnityObjectType(state, type)) {
962-
DiagnosticService.addDiagnostic(
963-
errors.unityMacroExpectsComponentTypeArgument(
964-
node,
965-
state.typeChecker.typeToString(state.typeChecker.getTypeFromTypeNode(node.typeArguments[0])),
966-
isAirshipBehaviourType(state, type, true),
967-
),
968-
);
969-
}
970-
}
971-
972-
return propertyCallMacro(state, node, expression, args);
973-
};
974-
};
975-
976-
const makeTypeArgumentAsStringMacro =
977-
(method: string, requiresArgument = true, defaultTypeName?: string): PropertyCallMacro =>
978-
(state, node, expression, args) => {
979-
let type: ts.Type | undefined;
980-
981-
if (node.typeArguments) {
982-
type = state.getType(node.typeArguments[0]);
983-
} else if (ts.isAsExpression(node.parent)) {
984-
type = state.getType(node.parent.type);
985-
DiagnosticService.addDiagnostic(
986-
warnings.unityMacroAsExpressionWarning(method, state.typeChecker.typeToString(type))(node.parent),
987-
);
988-
}
989-
990-
if (requiresArgument && !defaultTypeName && !type && args.length === 0) {
991-
DiagnosticService.addSingleDiagnostic(errors.unityMacroTypeArgumentRequired(node, method));
992-
}
993-
994-
if (type) {
995-
args.unshift(luau.string(state.typeChecker.typeToString(type)));
996-
return luau.create(luau.SyntaxKind.MethodCallExpression, {
997-
expression: convertToIndexableExpression(expression),
998-
name: method,
999-
args: luau.list.make(...args),
1000-
});
1001-
} else {
1002-
if (defaultTypeName !== undefined) {
1003-
args.unshift(luau.string(defaultTypeName));
1004-
}
1005-
1006-
return luau.create(luau.SyntaxKind.MethodCallExpression, {
1007-
expression: convertToIndexableExpression(expression),
1008-
name: method,
1009-
args: luau.list.make(...args),
1010-
});
1011-
}
1012-
};
1013-
1014-
const COMPONENT_MACROS: MacroList<PropertyCallMacro> = {
1015-
GetComponent: makeTypeArgumentAsStringMacro("GetComponent"),
1016-
GetComponents: makeTypeArgumentAsStringMacro("GetComponents"),
1017-
AddComponent: makeTypeArgumentAsStringMacro("AddComponent"),
1018-
GetComponentInChildren: makeTypeArgumentAsStringMacro("GetComponentInChildren"),
1019-
GetComponentsInChildren: makeTypeArgumentAsStringMacro("GetComponentsInChildren"),
1020-
GetComponentInParent: makeTypeArgumentAsStringMacro("GetComponentInParent"),
1021-
};
1022-
1023-
const AIRSHIP_COMPONENT_MACROS: MacroList<PropertyCallMacro> = {
1024-
GetAirshipComponent: makeTypeArgumentAsStringMacro("GetAirshipComponent"),
1025-
GetAirshipComponents: makeTypeArgumentAsStringMacro("GetAirshipComponents"),
1026-
AddAirshipComponent: makeTypeArgumentAsStringMacro("AddAirshipComponent"),
1027-
GetAirshipComponentsInChildren: makeTypeArgumentAsStringMacro("GetAirshipComponentsInChildren"),
1028-
GetAirshipComponentInChildren: makeTypeArgumentAsStringMacro("GetAirshipComponentInChildren"),
1029-
GetAirshipComponentInParent: makeTypeArgumentAsStringMacro("GetAirshipComponentInParent"),
1030-
GetAirshipComponentsInParent: makeTypeArgumentAsStringMacro("GetAirshipComponentsInParent"),
1031-
};
1032-
1033-
const UNITY_GAMEOBJECT_METHODS: MacroList<PropertyCallMacro> = {};
1034-
1035-
for (const [macro, call] of Object.entries(AIRSHIP_COMPONENT_MACROS)) {
1036-
UNITY_GAMEOBJECT_METHODS[macro] = expectAirshipComponentGeneric(call);
1037-
}
1038-
for (const [macro, call] of Object.entries(COMPONENT_MACROS)) {
1039-
UNITY_GAMEOBJECT_METHODS[macro] = expectUnityComponentGeneric(call);
1040-
}
1041-
1042-
const UNITY_STATIC_GAMEOBJECT_METHODS: MacroList<PropertyCallMacro> = {
1043-
FindObjectOfType: makeTypeArgumentAsStringMacro("FindObjectOfType"),
1044-
FindObjectsByType: makeTypeArgumentAsStringMacro("FindObjectsByType"),
1045-
};
1046-
const UNITY_COMPONENT_METHODS: MacroList<PropertyCallMacro> = {
1047-
GetComponent: makeTypeArgumentAsStringMacro("GetComponent"),
1048-
GetComponents: makeTypeArgumentAsStringMacro("GetComponents"),
1049-
};
1050-
const UNITY_OBJECT_METHODS: MacroList<PropertyCallMacro> = {
1051-
IsA: makeTypeArgumentAsStringMacro("IsA"),
1052-
};
1053-
1054939
export const PROPERTY_CALL_MACROS: { [className: string]: MacroList<PropertyCallMacro> } = {
1055940
// math classes
1056941
// CFrame: makeMathSet("+", "-", "*"),

0 commit comments

Comments
 (0)