@needle-tools/needle-component-compiler 3.0.16 → 3.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Changelog.md +11 -0
- package/dist/Compiler.js +14 -0
- package/dist/cli.js +42 -1
- package/dist/impl/blender-compiler.js +44 -11
- package/dist/impl/csharp-compiler.js +3 -0
- package/package.json +1 -1
package/Changelog.md
CHANGED
|
@@ -4,6 +4,17 @@ All notable changes to this package will be documented in this file.
|
|
|
4
4
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
5
5
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [3.0.17] - 2026-04-17
|
|
8
|
+
### Added
|
|
9
|
+
- Support for string literal union types (e.g. `axis: "x" | "y" | "z" = "y"`)
|
|
10
|
+
- C#: emits as `string` field with default value
|
|
11
|
+
- Blender: emits as `enum` with string options and correct default value
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- Blender: emit default values for `new` expressions with arguments (e.g. `new Vector3(0, 1, 0)` now emits `"value": [0, 1, 0]`)
|
|
15
|
+
- Blender: emit actual values for primitive array initializers (e.g. `speeds: number[] = [1, 2, 3]` now emits `"value": [1, 2, 3]` instead of `[]`)
|
|
16
|
+
- Blender: format enum `options` array with one entry per line, matching `builtin.component.json` style
|
|
17
|
+
|
|
7
18
|
## [3.0.16] - 2026-03-24
|
|
8
19
|
### Fixed
|
|
9
20
|
- Fix array literal initializers (`= []`, `= [1, 2, 3]`) emitting C# 12 collection expressions not supported by Unity
|
package/dist/Compiler.js
CHANGED
|
@@ -392,6 +392,20 @@ var Compiler = /** @class */ (function () {
|
|
|
392
392
|
}
|
|
393
393
|
// Union types: Object3D | null | undefined → resolve the first concrete member
|
|
394
394
|
if (ts.isUnionTypeNode(typeNode)) {
|
|
395
|
+
// Check if all non-null/undefined members are string literals (e.g. "none" | "XY" | "XZ")
|
|
396
|
+
var concreteMembers = typeNode.types.filter(function (m) {
|
|
397
|
+
return m.kind !== ts.SyntaxKind.NullKeyword &&
|
|
398
|
+
m.kind !== ts.SyntaxKind.UndefinedKeyword &&
|
|
399
|
+
m.kind !== ts.SyntaxKind.VoidKeyword;
|
|
400
|
+
});
|
|
401
|
+
if (concreteMembers.length > 0 && concreteMembers.every(function (m) { return ts.isLiteralTypeNode(m) && ts.isStringLiteral(m.literal); })) {
|
|
402
|
+
// Synthesize a virtual enum from the string literal values
|
|
403
|
+
var options = concreteMembers.map(function (m) { return m.literal.getText().replace(/^['"]|['"]$/g, ""); });
|
|
404
|
+
var syntheticName = "__strlit_" + options.join("_");
|
|
405
|
+
var members = options.map(function (o) { return ({ name: o, value: o }); });
|
|
406
|
+
writer.registerEnum(syntheticName, members);
|
|
407
|
+
return this.resolveTypeFromString(syntheticName, writer);
|
|
408
|
+
}
|
|
395
409
|
for (var _b = 0, _c = typeNode.types; _b < _c.length; _b++) {
|
|
396
410
|
var member = _c[_b];
|
|
397
411
|
if (member.kind !== ts.SyntaxKind.NullKeyword &&
|
package/dist/cli.js
CHANGED
|
@@ -8,6 +8,7 @@ var base_compiler_1 = require("./base-compiler");
|
|
|
8
8
|
var csharp_compiler_1 = require("./impl/csharp-compiler");
|
|
9
9
|
var blender_compiler_1 = require("./impl/blender-compiler");
|
|
10
10
|
var log_1 = require("./log");
|
|
11
|
+
var register_types_1 = require("./register-types");
|
|
11
12
|
var pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf-8"));
|
|
12
13
|
var rawArgs = process.argv.slice(2);
|
|
13
14
|
if (rawArgs.includes("--version") || rawArgs.includes("-v")) {
|
|
@@ -24,7 +25,8 @@ if (rawArgs.includes("--help") || rawArgs.includes("-h") || rawArgs.length < 3)
|
|
|
24
25
|
console.log(" input_files one or more .ts source files");
|
|
25
26
|
console.log("");
|
|
26
27
|
console.log("Options:");
|
|
27
|
-
console.log(" --types <path>
|
|
28
|
+
console.log(" --types <path> path to Types.json with extra type mappings");
|
|
29
|
+
console.log(" --register-types <bool> auto-generate register-types (default: true)");
|
|
28
30
|
console.log("");
|
|
29
31
|
console.log("Flags:");
|
|
30
32
|
console.log(" --silent, -s only output errors and CMD: lines");
|
|
@@ -38,11 +40,16 @@ if (rawArgs.includes("--help") || rawArgs.includes("-h") || rawArgs.length < 3)
|
|
|
38
40
|
// Extract flags from anywhere in the args
|
|
39
41
|
var typesPath;
|
|
40
42
|
var silent = false;
|
|
43
|
+
var registerTypes = true;
|
|
41
44
|
var positionalArgs = [];
|
|
42
45
|
for (var i = 0; i < rawArgs.length; i++) {
|
|
43
46
|
if (rawArgs[i] === "--types" && i + 1 < rawArgs.length) {
|
|
44
47
|
typesPath = rawArgs[++i];
|
|
45
48
|
}
|
|
49
|
+
else if (rawArgs[i] === "--register-types" && i + 1 < rawArgs.length) {
|
|
50
|
+
var val = rawArgs[++i].toLowerCase();
|
|
51
|
+
registerTypes = val !== "false" && val !== "0";
|
|
52
|
+
}
|
|
46
53
|
else if (rawArgs[i] === "--silent" || rawArgs[i] === "-s") {
|
|
47
54
|
silent = true;
|
|
48
55
|
}
|
|
@@ -98,6 +105,40 @@ for (var _i = 0, inputFiles_1 = inputFiles; _i < inputFiles_1.length; _i++) {
|
|
|
98
105
|
hasErrors = true;
|
|
99
106
|
}
|
|
100
107
|
}
|
|
108
|
+
// Auto-detect and write register-types files using needle.config.json
|
|
109
|
+
if (registerTypes && target === "blender") {
|
|
110
|
+
var codegenDir = void 0;
|
|
111
|
+
// Search upward from outputDir for needle.config.json
|
|
112
|
+
var searchDir = path.resolve(outputDir);
|
|
113
|
+
while (searchDir !== path.dirname(searchDir)) {
|
|
114
|
+
var configPath = path.join(searchDir, "needle.config.json");
|
|
115
|
+
if (fs.existsSync(configPath)) {
|
|
116
|
+
try {
|
|
117
|
+
var config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
118
|
+
if (config.codegenDirectory) {
|
|
119
|
+
codegenDir = path.resolve(searchDir, config.codegenDirectory);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch (_e) { }
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
searchDir = path.dirname(searchDir);
|
|
126
|
+
}
|
|
127
|
+
if (codegenDir) {
|
|
128
|
+
var candidates = [
|
|
129
|
+
path.join(codegenDir, "register-types.js"),
|
|
130
|
+
path.join(codegenDir, "register-types.ts"),
|
|
131
|
+
path.join(codegenDir, "register_types.ts"),
|
|
132
|
+
path.join(codegenDir, "register_types.js"),
|
|
133
|
+
];
|
|
134
|
+
for (var _a = 0, candidates_1 = candidates; _a < candidates_1.length; _a++) {
|
|
135
|
+
var candidate = candidates_1[_a];
|
|
136
|
+
if (fs.existsSync(candidate)) {
|
|
137
|
+
(0, register_types_1.writeTypeRegistry)(writer.outputInfo, candidate);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
101
142
|
if (hasErrors) {
|
|
102
143
|
process.exit(1);
|
|
103
144
|
}
|
|
@@ -136,17 +136,29 @@ var BlenderWriter = /** @class */ (function (_super) {
|
|
|
136
136
|
if (enumMembers && enumMembers.length > 0) {
|
|
137
137
|
this.writer.beginBlock("\"" + name + "\": {");
|
|
138
138
|
this.writer.writeLine("\"type\": \"enum\",");
|
|
139
|
-
// Resolve default value: try to match explicit initializer (e.g. "lighttype.spot")
|
|
139
|
+
// Resolve default value: try to match explicit initializer (e.g. "lighttype.spot" or bare "none")
|
|
140
140
|
var enumValue = enumMembers[0].value;
|
|
141
|
-
if (initialValue
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
141
|
+
if (initialValue) {
|
|
142
|
+
if (initialValue.includes(".")) {
|
|
143
|
+
var memberKey_1 = initialValue.split(".").pop();
|
|
144
|
+
var found = enumMembers.find(function (m) { return m.name.toLowerCase() === memberKey_1; });
|
|
145
|
+
if (found !== undefined)
|
|
146
|
+
enumValue = found.value;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
// Bare value (string literal union default, e.g. "none")
|
|
150
|
+
var found = enumMembers.find(function (m) { return m.name.toLowerCase() === initialValue.toLowerCase() || String(m.value).toLowerCase() === initialValue.toLowerCase(); });
|
|
151
|
+
if (found !== undefined)
|
|
152
|
+
enumValue = found.value;
|
|
153
|
+
}
|
|
146
154
|
}
|
|
147
155
|
this.writer.writeLine("\"value\": " + JSON.stringify(enumValue) + ",");
|
|
148
156
|
var options = enumMembers.map(function (m) { return m.name; });
|
|
149
|
-
this.writer.
|
|
157
|
+
this.writer.beginBlock("\"options\": [");
|
|
158
|
+
for (var i = 0; i < options.length; i++) {
|
|
159
|
+
this.writer.writeLine(JSON.stringify(options[i]) + ",");
|
|
160
|
+
}
|
|
161
|
+
this.writer.endBlock("]");
|
|
150
162
|
this.writer.endBlock("},");
|
|
151
163
|
return;
|
|
152
164
|
}
|
|
@@ -160,20 +172,41 @@ var BlenderWriter = /** @class */ (function (_super) {
|
|
|
160
172
|
this.writer.beginBlock("\"" + name + "\": {");
|
|
161
173
|
this.writer.writeLine("\"type\": \"" + type + "\",");
|
|
162
174
|
if (initialValue && !isArray) {
|
|
163
|
-
if (initialValue.startsWith("new "))
|
|
175
|
+
if (initialValue.startsWith("new ")) {
|
|
176
|
+
// Extract constructor args: "new Vector3(1, 2, 3)" → [1, 2, 3]
|
|
177
|
+
var argsMatch = initialValue.match(/\(([^)]*)\)/);
|
|
178
|
+
var argsStr = argsMatch ? argsMatch[1].trim() : "";
|
|
179
|
+
if (argsStr.length > 0) {
|
|
180
|
+
var args = argsStr.split(",").map(function (a) { return a.trim(); });
|
|
181
|
+
this.writer.writeLine("\"value\": [" + args.join(", ") + "],");
|
|
182
|
+
}
|
|
164
183
|
initialValue = undefined;
|
|
184
|
+
}
|
|
165
185
|
switch (type) {
|
|
166
186
|
case "bool":
|
|
167
|
-
initialValue = initialValue.toLowerCase();
|
|
187
|
+
initialValue = initialValue === null || initialValue === void 0 ? void 0 : initialValue.toLowerCase();
|
|
168
188
|
break;
|
|
169
189
|
case "string":
|
|
170
|
-
initialValue = "\"" + initialValue + "\"";
|
|
190
|
+
initialValue = initialValue ? "\"" + initialValue + "\"" : undefined;
|
|
171
191
|
}
|
|
172
192
|
if (initialValue)
|
|
173
193
|
this.writer.writeLine("\"value\": " + initialValue + ",");
|
|
174
194
|
}
|
|
175
195
|
if (isArray) {
|
|
176
|
-
|
|
196
|
+
if (initialValue && initialValue.startsWith("[") && initialValue !== "[]") {
|
|
197
|
+
// For string arrays, re-quote each element: [a, b, c] → ["a", "b", "c"]
|
|
198
|
+
if (type === "string") {
|
|
199
|
+
var inner = initialValue.slice(1, -1);
|
|
200
|
+
var elements = inner.split(",").map(function (e) { return "\"" + e.trim() + "\""; });
|
|
201
|
+
this.writer.writeLine("\"value\": [" + elements.join(", ") + "],");
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
this.writer.writeLine("\"value\": " + initialValue + ",");
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
this.writer.writeLine("\"value\": [],");
|
|
209
|
+
}
|
|
177
210
|
}
|
|
178
211
|
if (tooltip) {
|
|
179
212
|
this.writer.writeLine("\"description\": \"" + tooltip.replace(/"/g, "'") + "\"");
|
|
@@ -133,6 +133,9 @@ var CSharpWriter = /** @class */ (function (_super) {
|
|
|
133
133
|
var _a, _b, _c, _d, _e;
|
|
134
134
|
if (!typescriptTypeName)
|
|
135
135
|
return undefined;
|
|
136
|
+
// String literal union synthetic enums (e.g. __strlit_none_XY_XZ) → string
|
|
137
|
+
if (typescriptTypeName.startsWith("__strlit_"))
|
|
138
|
+
return "string";
|
|
136
139
|
// Strip THREE. prefix for lookup fallback
|
|
137
140
|
var stripped = typescriptTypeName.startsWith("THREE.") ? typescriptTypeName.substring(6) : typescriptTypeName;
|
|
138
141
|
// Check built-in TYPE_MAP first (TS→C# mapping)
|