mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 14:24:53 +08:00
[ts] Use correct typescript-formatter package
This commit is contained in:
parent
8972ba5dc8
commit
46e38c0356
@ -1,18 +1,18 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Format TypeScript files with Biome
|
||||
# Format TypeScript files with tsfmt
|
||||
echo "Formatting TypeScript files..."
|
||||
|
||||
dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
|
||||
|
||||
# Check if biome.json files match
|
||||
if ! cmp -s ../spine-ts/biome.json ../tests/biome.json; then
|
||||
echo -e "\033[1;31mERROR: spine-ts/biome.json and tests/biome.json differ!\033[0m"
|
||||
# Check if tsfmt.json files match
|
||||
if ! cmp -s ../spine-ts/tsfmt.json ../tests/tsfmt.json; then
|
||||
echo -e "\033[1;31mERROR: spine-ts/tsfmt.json and tests/tsfmt.json differ!\033[0m"
|
||||
echo -e "\033[1;31mPlease sync them to ensure consistent formatting.\033[0m"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Format TypeScript files
|
||||
cd ../spine-ts && npx biome format --write . && cd ../formatters
|
||||
cd ../tests && npx biome format --write --config-path ../spine-ts . && cd ../formatters
|
||||
cd ../spine-ts && npm run format && cd ../formatters
|
||||
cd ../tests && npm run format -r && cd ../formatters
|
||||
@ -2,37 +2,37 @@ import { execSync } from 'node:child_process';
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
|
||||
function findTypeScriptFiles(dir: string, files: string[] = []): string[] {
|
||||
if (!fs.existsSync(dir)) return files;
|
||||
|
||||
fs.readdirSync(dir).forEach(name => {
|
||||
const filePath = path.join(dir, name);
|
||||
const stat = fs.statSync(filePath);
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
// Skip node_modules and dist directories
|
||||
if (name !== 'node_modules' && name !== 'dist') {
|
||||
findTypeScriptFiles(filePath, files);
|
||||
}
|
||||
} else if (name.endsWith('.ts') && !name.endsWith('.d.ts')) {
|
||||
files.push(filePath);
|
||||
}
|
||||
});
|
||||
|
||||
return files;
|
||||
function findTypeScriptFiles (dir: string, files: string[] = []): string[] {
|
||||
if (!fs.existsSync(dir)) return files;
|
||||
|
||||
fs.readdirSync(dir).forEach(name => {
|
||||
const filePath = path.join(dir, name);
|
||||
const stat = fs.statSync(filePath);
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
// Skip node_modules and dist directories
|
||||
if (name !== 'node_modules' && name !== 'dist') {
|
||||
findTypeScriptFiles(filePath, files);
|
||||
}
|
||||
} else if (name.endsWith('.ts') && !name.endsWith('.d.ts')) {
|
||||
files.push(filePath);
|
||||
}
|
||||
});
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
// Find all TypeScript files in spine-* directories
|
||||
const allFiles: string[] = [];
|
||||
fs.readdirSync('.').forEach(name => {
|
||||
if (name.startsWith('spine-') && fs.statSync(name).isDirectory()) {
|
||||
findTypeScriptFiles(name, allFiles);
|
||||
}
|
||||
if (name.startsWith('spine-') && fs.statSync(name).isDirectory()) {
|
||||
findTypeScriptFiles(name, allFiles);
|
||||
}
|
||||
});
|
||||
|
||||
if (allFiles.length > 0) {
|
||||
console.log(`Formatting ${allFiles.length} TypeScript files...`);
|
||||
execSync(`npx tsfmt -r ${allFiles.join(' ')}`, { stdio: 'inherit' });
|
||||
console.log(`Formatting ${allFiles.length} TypeScript files...`);
|
||||
execSync(`npx -y typescript-formatter -r ${allFiles.join(' ')}`, { stdio: 'inherit' });
|
||||
} else {
|
||||
console.log('No TypeScript files found to format.');
|
||||
console.log('No TypeScript files found to format.');
|
||||
}
|
||||
@ -4,7 +4,7 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"compare": "tsx compare-with-reference-impl.ts",
|
||||
"format": "npx tsfmt -r ./**/*.ts",
|
||||
"format": "npx -y typescript-formatter -r ./**/*.ts",
|
||||
"lint": "npx biome lint ."
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -7,454 +7,454 @@ import type { Property, SerializerIR } from './generate-serializer-ir';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
function transformType(javaType: string): string {
|
||||
// Remove package prefixes
|
||||
const simpleName = javaType.includes('.') ? javaType.split('.').pop()! : javaType;
|
||||
function transformType (javaType: string): string {
|
||||
// Remove package prefixes
|
||||
const simpleName = javaType.includes('.') ? javaType.split('.').pop()! : javaType;
|
||||
|
||||
// Handle primitive types
|
||||
if (simpleName === 'String') return 'const String&';
|
||||
if (simpleName === 'int') return 'int';
|
||||
if (simpleName === 'float') return 'float';
|
||||
if (simpleName === 'boolean') return 'bool';
|
||||
if (simpleName === 'short') return 'short';
|
||||
// Handle primitive types
|
||||
if (simpleName === 'String') return 'const String&';
|
||||
if (simpleName === 'int') return 'int';
|
||||
if (simpleName === 'float') return 'float';
|
||||
if (simpleName === 'boolean') return 'bool';
|
||||
if (simpleName === 'short') return 'short';
|
||||
|
||||
// Handle arrays
|
||||
if (simpleName.endsWith('[]')) {
|
||||
const baseType = simpleName.slice(0, -2);
|
||||
return `Array<${transformType(baseType)}>`;
|
||||
}
|
||||
// Handle arrays
|
||||
if (simpleName.endsWith('[]')) {
|
||||
const baseType = simpleName.slice(0, -2);
|
||||
return `Array<${transformType(baseType)}>`;
|
||||
}
|
||||
|
||||
// Object types become pointers
|
||||
return simpleName;
|
||||
// Object types become pointers
|
||||
return simpleName;
|
||||
}
|
||||
|
||||
function generatePropertyCode(property: Property, indent: string, enumMappings: { [enumName: string]: { [javaValue: string]: string } }): string[] {
|
||||
const lines: string[] = [];
|
||||
function generatePropertyCode (property: Property, indent: string, enumMappings: { [enumName: string]: { [javaValue: string]: string } }): string[] {
|
||||
const lines: string[] = [];
|
||||
|
||||
// Transform field access for C++: add _ prefix except for Color fields
|
||||
let accessor = `obj->${property.getter}`;
|
||||
if (!property.getter.includes('()')) {
|
||||
// This is a field access, not a method call
|
||||
const fieldName = property.getter;
|
||||
// Color fields (r, g, b, a) don't get _ prefix, all others do
|
||||
const isColorField = ['r', 'g', 'b', 'a'].includes(fieldName);
|
||||
if (!isColorField) {
|
||||
accessor = `obj->_${fieldName}`;
|
||||
} else {
|
||||
accessor = `obj->${fieldName}`;
|
||||
}
|
||||
}
|
||||
// Transform field access for C++: add _ prefix except for Color fields
|
||||
let accessor = `obj->${property.getter}`;
|
||||
if (!property.getter.includes('()')) {
|
||||
// This is a field access, not a method call
|
||||
const fieldName = property.getter;
|
||||
// Color fields (r, g, b, a) don't get _ prefix, all others do
|
||||
const isColorField = ['r', 'g', 'b', 'a'].includes(fieldName);
|
||||
if (!isColorField) {
|
||||
accessor = `obj->_${fieldName}`;
|
||||
} else {
|
||||
accessor = `obj->${fieldName}`;
|
||||
}
|
||||
}
|
||||
|
||||
// C++-specific: darkColor specifically has hasDarkColor() method
|
||||
const isDarkColor = property.kind === "object" &&
|
||||
property.valueType === "Color" &&
|
||||
property.getter === "getDarkColor()";
|
||||
// C++-specific: darkColor specifically has hasDarkColor() method
|
||||
const isDarkColor = property.kind === "object" &&
|
||||
property.valueType === "Color" &&
|
||||
property.getter === "getDarkColor()";
|
||||
|
||||
if (isDarkColor) {
|
||||
const colorAccessor = `&${accessor}`;
|
||||
if (isDarkColor) {
|
||||
const colorAccessor = `&${accessor}`;
|
||||
|
||||
lines.push(`${indent}if (obj->hasDarkColor()) {`);
|
||||
lines.push(`${indent} ${property.writeMethodCall}(${colorAccessor});`);
|
||||
lines.push(`${indent}} else {`);
|
||||
lines.push(`${indent} _json.writeNull();`);
|
||||
lines.push(`${indent}}`);
|
||||
return lines;
|
||||
}
|
||||
lines.push(`${indent}if (obj->hasDarkColor()) {`);
|
||||
lines.push(`${indent} ${property.writeMethodCall}(${colorAccessor});`);
|
||||
lines.push(`${indent}} else {`);
|
||||
lines.push(`${indent} _json.writeNull();`);
|
||||
lines.push(`${indent}}`);
|
||||
return lines;
|
||||
}
|
||||
|
||||
switch (property.kind) {
|
||||
case "primitive":
|
||||
lines.push(`${indent}_json.writeValue(${accessor});`);
|
||||
break;
|
||||
switch (property.kind) {
|
||||
case "primitive":
|
||||
lines.push(`${indent}_json.writeValue(${accessor});`);
|
||||
break;
|
||||
|
||||
case "object":
|
||||
if (property.isNullable) {
|
||||
lines.push(`${indent}if (${accessor} == nullptr) {`);
|
||||
lines.push(`${indent} _json.writeNull();`);
|
||||
lines.push(`${indent}} else {`);
|
||||
lines.push(`${indent} ${property.writeMethodCall}(${accessor});`);
|
||||
lines.push(`${indent}}`);
|
||||
} else {
|
||||
lines.push(`${indent}${property.writeMethodCall}(${accessor});`);
|
||||
}
|
||||
break;
|
||||
case "object":
|
||||
if (property.isNullable) {
|
||||
lines.push(`${indent}if (${accessor} == nullptr) {`);
|
||||
lines.push(`${indent} _json.writeNull();`);
|
||||
lines.push(`${indent}} else {`);
|
||||
lines.push(`${indent} ${property.writeMethodCall}(${accessor});`);
|
||||
lines.push(`${indent}}`);
|
||||
} else {
|
||||
lines.push(`${indent}${property.writeMethodCall}(${accessor});`);
|
||||
}
|
||||
break;
|
||||
|
||||
case "enum":
|
||||
const enumName = property.enumName;
|
||||
const enumMap = enumMappings[enumName];
|
||||
case "enum":
|
||||
const enumName = property.enumName;
|
||||
const enumMap = enumMappings[enumName];
|
||||
|
||||
if (enumMap && Object.keys(enumMap).length > 0) {
|
||||
// Generate switch statement for enum
|
||||
lines.push(`${indent}_json.writeValue([&]() -> String {`);
|
||||
lines.push(`${indent} switch(${accessor}) {`);
|
||||
if (enumMap && Object.keys(enumMap).length > 0) {
|
||||
// Generate switch statement for enum
|
||||
lines.push(`${indent}_json.writeValue([&]() -> String {`);
|
||||
lines.push(`${indent} switch(${accessor}) {`);
|
||||
|
||||
for (const [javaValue, cppValue] of Object.entries(enumMap)) {
|
||||
lines.push(`${indent} case ${cppValue}: return "${javaValue}";`);
|
||||
}
|
||||
for (const [javaValue, cppValue] of Object.entries(enumMap)) {
|
||||
lines.push(`${indent} case ${cppValue}: return "${javaValue}";`);
|
||||
}
|
||||
|
||||
lines.push(`${indent} default: return "unknown";`);
|
||||
lines.push(`${indent} }`);
|
||||
lines.push(`${indent}}());`);
|
||||
} else {
|
||||
// Fallback if no enum mapping
|
||||
lines.push(`${indent}_json.writeValue(String::valueOf((int)${accessor}));`);
|
||||
}
|
||||
break;
|
||||
lines.push(`${indent} default: return "unknown";`);
|
||||
lines.push(`${indent} }`);
|
||||
lines.push(`${indent}}());`);
|
||||
} else {
|
||||
// Fallback if no enum mapping
|
||||
lines.push(`${indent}_json.writeValue(String::valueOf((int)${accessor}));`);
|
||||
}
|
||||
break;
|
||||
|
||||
case "array":
|
||||
// In C++, arrays are never null - empty arrays (size() == 0) are equivalent to Java null
|
||||
lines.push(`${indent}_json.writeArrayStart();`);
|
||||
lines.push(`${indent}for (size_t i = 0; i < ${accessor}.size(); i++) {`);
|
||||
const elementAccess = `${accessor}[i]`;
|
||||
if (property.elementKind === "primitive") {
|
||||
lines.push(`${indent} _json.writeValue(${elementAccess});`);
|
||||
} else {
|
||||
lines.push(`${indent} ${property.writeMethodCall}(${elementAccess});`);
|
||||
}
|
||||
lines.push(`${indent}}`);
|
||||
lines.push(`${indent}_json.writeArrayEnd();`);
|
||||
break;
|
||||
case "array":
|
||||
// In C++, arrays are never null - empty arrays (size() == 0) are equivalent to Java null
|
||||
lines.push(`${indent}_json.writeArrayStart();`);
|
||||
lines.push(`${indent}for (size_t i = 0; i < ${accessor}.size(); i++) {`);
|
||||
const elementAccess = `${accessor}[i]`;
|
||||
if (property.elementKind === "primitive") {
|
||||
lines.push(`${indent} _json.writeValue(${elementAccess});`);
|
||||
} else {
|
||||
lines.push(`${indent} ${property.writeMethodCall}(${elementAccess});`);
|
||||
}
|
||||
lines.push(`${indent}}`);
|
||||
lines.push(`${indent}_json.writeArrayEnd();`);
|
||||
break;
|
||||
|
||||
case "nestedArray":
|
||||
// Nested arrays are always considered non-null in both Java and C++
|
||||
lines.push(`${indent}_json.writeArrayStart();`);
|
||||
lines.push(`${indent}for (size_t i = 0; i < ${accessor}.size(); i++) {`);
|
||||
lines.push(`${indent} Array<${property.elementType}>& nestedArray = ${accessor}[i];`);
|
||||
lines.push(`${indent} _json.writeArrayStart();`);
|
||||
lines.push(`${indent} for (size_t j = 0; j < nestedArray.size(); j++) {`);
|
||||
lines.push(`${indent} _json.writeValue(nestedArray[j]);`);
|
||||
lines.push(`${indent} }`);
|
||||
lines.push(`${indent} _json.writeArrayEnd();`);
|
||||
lines.push(`${indent}}`);
|
||||
lines.push(`${indent}_json.writeArrayEnd();`);
|
||||
break;
|
||||
}
|
||||
case "nestedArray":
|
||||
// Nested arrays are always considered non-null in both Java and C++
|
||||
lines.push(`${indent}_json.writeArrayStart();`);
|
||||
lines.push(`${indent}for (size_t i = 0; i < ${accessor}.size(); i++) {`);
|
||||
lines.push(`${indent} Array<${property.elementType}>& nestedArray = ${accessor}[i];`);
|
||||
lines.push(`${indent} _json.writeArrayStart();`);
|
||||
lines.push(`${indent} for (size_t j = 0; j < nestedArray.size(); j++) {`);
|
||||
lines.push(`${indent} _json.writeValue(nestedArray[j]);`);
|
||||
lines.push(`${indent} }`);
|
||||
lines.push(`${indent} _json.writeArrayEnd();`);
|
||||
lines.push(`${indent}}`);
|
||||
lines.push(`${indent}_json.writeArrayEnd();`);
|
||||
break;
|
||||
}
|
||||
|
||||
return lines;
|
||||
return lines;
|
||||
}
|
||||
|
||||
function generateCppFromIR(ir: SerializerIR): string {
|
||||
const cppOutput: string[] = [];
|
||||
function generateCppFromIR (ir: SerializerIR): string {
|
||||
const cppOutput: string[] = [];
|
||||
|
||||
// Generate C++ file header
|
||||
cppOutput.push('#ifndef Spine_SkeletonSerializer_h');
|
||||
cppOutput.push('#define Spine_SkeletonSerializer_h');
|
||||
cppOutput.push('');
|
||||
cppOutput.push('#include <spine/spine.h>');
|
||||
cppOutput.push('#include "JsonWriter.h"');
|
||||
cppOutput.push('#include <stdio.h>');
|
||||
cppOutput.push('#include <stdlib.h>');
|
||||
cppOutput.push('');
|
||||
cppOutput.push('namespace spine {');
|
||||
cppOutput.push('');
|
||||
cppOutput.push('class SkeletonSerializer {');
|
||||
cppOutput.push('private:');
|
||||
cppOutput.push(' HashMap<void*, bool> _visitedObjects;');
|
||||
cppOutput.push(' JsonWriter _json;');
|
||||
cppOutput.push('');
|
||||
cppOutput.push('public:');
|
||||
cppOutput.push(' SkeletonSerializer() {}');
|
||||
cppOutput.push(' ~SkeletonSerializer() {}');
|
||||
cppOutput.push('');
|
||||
// Generate C++ file header
|
||||
cppOutput.push('#ifndef Spine_SkeletonSerializer_h');
|
||||
cppOutput.push('#define Spine_SkeletonSerializer_h');
|
||||
cppOutput.push('');
|
||||
cppOutput.push('#include <spine/spine.h>');
|
||||
cppOutput.push('#include "JsonWriter.h"');
|
||||
cppOutput.push('#include <stdio.h>');
|
||||
cppOutput.push('#include <stdlib.h>');
|
||||
cppOutput.push('');
|
||||
cppOutput.push('namespace spine {');
|
||||
cppOutput.push('');
|
||||
cppOutput.push('class SkeletonSerializer {');
|
||||
cppOutput.push('private:');
|
||||
cppOutput.push(' HashMap<void*, bool> _visitedObjects;');
|
||||
cppOutput.push(' JsonWriter _json;');
|
||||
cppOutput.push('');
|
||||
cppOutput.push('public:');
|
||||
cppOutput.push(' SkeletonSerializer() {}');
|
||||
cppOutput.push(' ~SkeletonSerializer() {}');
|
||||
cppOutput.push('');
|
||||
|
||||
// Generate public methods
|
||||
for (const method of ir.publicMethods) {
|
||||
const cppParamType = transformType(method.paramType);
|
||||
cppOutput.push(` String ${method.name}(${cppParamType}* ${method.paramName}) {`);
|
||||
cppOutput.push(' _visitedObjects.clear();');
|
||||
cppOutput.push(' _json = JsonWriter();');
|
||||
cppOutput.push(` ${method.writeMethodCall}(${method.paramName});`);
|
||||
cppOutput.push(' return _json.getString();');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push('');
|
||||
}
|
||||
// Generate public methods
|
||||
for (const method of ir.publicMethods) {
|
||||
const cppParamType = transformType(method.paramType);
|
||||
cppOutput.push(` String ${method.name}(${cppParamType}* ${method.paramName}) {`);
|
||||
cppOutput.push(' _visitedObjects.clear();');
|
||||
cppOutput.push(' _json = JsonWriter();');
|
||||
cppOutput.push(` ${method.writeMethodCall}(${method.paramName});`);
|
||||
cppOutput.push(' return _json.getString();');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push('');
|
||||
}
|
||||
|
||||
cppOutput.push('private:');
|
||||
cppOutput.push('private:');
|
||||
|
||||
// Generate write methods
|
||||
for (const method of ir.writeMethods) {
|
||||
const shortName = method.paramType.split('.').pop()!;
|
||||
const cppType = transformType(method.paramType);
|
||||
// Generate write methods
|
||||
for (const method of ir.writeMethods) {
|
||||
const shortName = method.paramType.split('.').pop()!;
|
||||
const cppType = transformType(method.paramType);
|
||||
|
||||
// Custom writeSkin and writeSkinEntry implementations
|
||||
if (method.name === 'writeSkin') {
|
||||
cppOutput.push(' void writeSkin(Skin* obj) {');
|
||||
cppOutput.push(' if (_visitedObjects.containsKey(obj)) {');
|
||||
cppOutput.push(' _json.writeValue("<circular>");');
|
||||
cppOutput.push(' return;');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push(' _visitedObjects.put(obj, true);');
|
||||
cppOutput.push('');
|
||||
cppOutput.push(' _json.writeObjectStart();');
|
||||
cppOutput.push(' _json.writeName("type");');
|
||||
cppOutput.push(' _json.writeValue("Skin");');
|
||||
cppOutput.push('');
|
||||
cppOutput.push(' _json.writeName("attachments");');
|
||||
cppOutput.push(' _json.writeArrayStart();');
|
||||
cppOutput.push(' Skin::AttachmentMap::Entries entries = obj->getAttachments();');
|
||||
cppOutput.push(' while (entries.hasNext()) {');
|
||||
cppOutput.push(' Skin::AttachmentMap::Entry& entry = entries.next();');
|
||||
cppOutput.push(' writeSkinEntry(&entry);');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push(' _json.writeArrayEnd();');
|
||||
cppOutput.push('');
|
||||
cppOutput.push(' _json.writeName("bones");');
|
||||
cppOutput.push(' _json.writeArrayStart();');
|
||||
cppOutput.push(' for (size_t i = 0; i < obj->getBones().size(); i++) {');
|
||||
cppOutput.push(' BoneData* item = obj->getBones()[i];');
|
||||
cppOutput.push(' writeBoneData(item);');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push(' _json.writeArrayEnd();');
|
||||
cppOutput.push('');
|
||||
cppOutput.push(' _json.writeName("constraints");');
|
||||
cppOutput.push(' _json.writeArrayStart();');
|
||||
cppOutput.push(' for (size_t i = 0; i < obj->getConstraints().size(); i++) {');
|
||||
cppOutput.push(' ConstraintData* item = obj->getConstraints()[i];');
|
||||
cppOutput.push(' writeConstraintData(item);');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push(' _json.writeArrayEnd();');
|
||||
cppOutput.push('');
|
||||
cppOutput.push(' _json.writeName("name");');
|
||||
cppOutput.push(' _json.writeValue(obj->getName());');
|
||||
cppOutput.push('');
|
||||
cppOutput.push(' _json.writeName("color");');
|
||||
cppOutput.push(' writeColor(&obj->getColor());');
|
||||
cppOutput.push('');
|
||||
cppOutput.push(' _json.writeObjectEnd();');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push('');
|
||||
continue;
|
||||
}
|
||||
// Custom writeSkin and writeSkinEntry implementations
|
||||
if (method.name === 'writeSkin') {
|
||||
cppOutput.push(' void writeSkin(Skin* obj) {');
|
||||
cppOutput.push(' if (_visitedObjects.containsKey(obj)) {');
|
||||
cppOutput.push(' _json.writeValue("<circular>");');
|
||||
cppOutput.push(' return;');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push(' _visitedObjects.put(obj, true);');
|
||||
cppOutput.push('');
|
||||
cppOutput.push(' _json.writeObjectStart();');
|
||||
cppOutput.push(' _json.writeName("type");');
|
||||
cppOutput.push(' _json.writeValue("Skin");');
|
||||
cppOutput.push('');
|
||||
cppOutput.push(' _json.writeName("attachments");');
|
||||
cppOutput.push(' _json.writeArrayStart();');
|
||||
cppOutput.push(' Skin::AttachmentMap::Entries entries = obj->getAttachments();');
|
||||
cppOutput.push(' while (entries.hasNext()) {');
|
||||
cppOutput.push(' Skin::AttachmentMap::Entry& entry = entries.next();');
|
||||
cppOutput.push(' writeSkinEntry(&entry);');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push(' _json.writeArrayEnd();');
|
||||
cppOutput.push('');
|
||||
cppOutput.push(' _json.writeName("bones");');
|
||||
cppOutput.push(' _json.writeArrayStart();');
|
||||
cppOutput.push(' for (size_t i = 0; i < obj->getBones().size(); i++) {');
|
||||
cppOutput.push(' BoneData* item = obj->getBones()[i];');
|
||||
cppOutput.push(' writeBoneData(item);');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push(' _json.writeArrayEnd();');
|
||||
cppOutput.push('');
|
||||
cppOutput.push(' _json.writeName("constraints");');
|
||||
cppOutput.push(' _json.writeArrayStart();');
|
||||
cppOutput.push(' for (size_t i = 0; i < obj->getConstraints().size(); i++) {');
|
||||
cppOutput.push(' ConstraintData* item = obj->getConstraints()[i];');
|
||||
cppOutput.push(' writeConstraintData(item);');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push(' _json.writeArrayEnd();');
|
||||
cppOutput.push('');
|
||||
cppOutput.push(' _json.writeName("name");');
|
||||
cppOutput.push(' _json.writeValue(obj->getName());');
|
||||
cppOutput.push('');
|
||||
cppOutput.push(' _json.writeName("color");');
|
||||
cppOutput.push(' writeColor(&obj->getColor());');
|
||||
cppOutput.push('');
|
||||
cppOutput.push(' _json.writeObjectEnd();');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push('');
|
||||
continue;
|
||||
}
|
||||
|
||||
// Custom writeSkinEntry
|
||||
if (method.name === 'writeSkinEntry') {
|
||||
// Custom writeSkinEntry implementation
|
||||
cppOutput.push(' void writeSkinEntry(Skin::AttachmentMap::Entry* obj) {');
|
||||
cppOutput.push(' _json.writeObjectStart();');
|
||||
cppOutput.push(' _json.writeName("type");');
|
||||
cppOutput.push(' _json.writeValue("SkinEntry");');
|
||||
cppOutput.push(' _json.writeName("slotIndex");');
|
||||
cppOutput.push(' _json.writeValue((int)obj->_slotIndex);');
|
||||
cppOutput.push(' _json.writeName("name");');
|
||||
cppOutput.push(' _json.writeValue(obj->_name);');
|
||||
cppOutput.push(' _json.writeName("attachment");');
|
||||
cppOutput.push(' writeAttachment(obj->_attachment);');
|
||||
cppOutput.push(' _json.writeObjectEnd();');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push('');
|
||||
continue;
|
||||
}
|
||||
// Custom writeSkinEntry
|
||||
if (method.name === 'writeSkinEntry') {
|
||||
// Custom writeSkinEntry implementation
|
||||
cppOutput.push(' void writeSkinEntry(Skin::AttachmentMap::Entry* obj) {');
|
||||
cppOutput.push(' _json.writeObjectStart();');
|
||||
cppOutput.push(' _json.writeName("type");');
|
||||
cppOutput.push(' _json.writeValue("SkinEntry");');
|
||||
cppOutput.push(' _json.writeName("slotIndex");');
|
||||
cppOutput.push(' _json.writeValue((int)obj->_slotIndex);');
|
||||
cppOutput.push(' _json.writeName("name");');
|
||||
cppOutput.push(' _json.writeValue(obj->_name);');
|
||||
cppOutput.push(' _json.writeName("attachment");');
|
||||
cppOutput.push(' writeAttachment(obj->_attachment);');
|
||||
cppOutput.push(' _json.writeObjectEnd();');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push('');
|
||||
continue;
|
||||
}
|
||||
|
||||
cppOutput.push(` void ${method.name}(${cppType}* obj) {`);
|
||||
cppOutput.push(` void ${method.name}(${cppType}* obj) {`);
|
||||
|
||||
if (method.isAbstractType) {
|
||||
// Handle abstract types with instanceof chain
|
||||
if (method.subtypeChecks && method.subtypeChecks.length > 0) {
|
||||
let first = true;
|
||||
for (const subtype of method.subtypeChecks) {
|
||||
const subtypeShortName = subtype.typeName.split('.').pop()!;
|
||||
if (method.isAbstractType) {
|
||||
// Handle abstract types with instanceof chain
|
||||
if (method.subtypeChecks && method.subtypeChecks.length > 0) {
|
||||
let first = true;
|
||||
for (const subtype of method.subtypeChecks) {
|
||||
const subtypeShortName = subtype.typeName.split('.').pop()!;
|
||||
|
||||
if (first) {
|
||||
cppOutput.push(` if (obj->getRTTI().instanceOf(${subtypeShortName}::rtti)) {`);
|
||||
first = false;
|
||||
} else {
|
||||
cppOutput.push(` } else if (obj->getRTTI().instanceOf(${subtypeShortName}::rtti)) {`);
|
||||
}
|
||||
cppOutput.push(` ${subtype.writeMethodCall}((${subtypeShortName}*)obj);`);
|
||||
}
|
||||
cppOutput.push(' } else {');
|
||||
cppOutput.push(` fprintf(stderr, "Error: Unknown ${shortName} type\\n"); exit(1);`);
|
||||
cppOutput.push(' }');
|
||||
} else {
|
||||
cppOutput.push(' _json.writeNull(); // No concrete implementations after filtering exclusions');
|
||||
}
|
||||
} else {
|
||||
// Handle concrete types
|
||||
// Add cycle detection
|
||||
cppOutput.push(' if (_visitedObjects.containsKey(obj)) {');
|
||||
cppOutput.push(' _json.writeValue("<circular>");');
|
||||
cppOutput.push(' return;');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push(' _visitedObjects.put(obj, true);');
|
||||
cppOutput.push('');
|
||||
if (first) {
|
||||
cppOutput.push(` if (obj->getRTTI().instanceOf(${subtypeShortName}::rtti)) {`);
|
||||
first = false;
|
||||
} else {
|
||||
cppOutput.push(` } else if (obj->getRTTI().instanceOf(${subtypeShortName}::rtti)) {`);
|
||||
}
|
||||
cppOutput.push(` ${subtype.writeMethodCall}((${subtypeShortName}*)obj);`);
|
||||
}
|
||||
cppOutput.push(' } else {');
|
||||
cppOutput.push(` fprintf(stderr, "Error: Unknown ${shortName} type\\n"); exit(1);`);
|
||||
cppOutput.push(' }');
|
||||
} else {
|
||||
cppOutput.push(' _json.writeNull(); // No concrete implementations after filtering exclusions');
|
||||
}
|
||||
} else {
|
||||
// Handle concrete types
|
||||
// Add cycle detection
|
||||
cppOutput.push(' if (_visitedObjects.containsKey(obj)) {');
|
||||
cppOutput.push(' _json.writeValue("<circular>");');
|
||||
cppOutput.push(' return;');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push(' _visitedObjects.put(obj, true);');
|
||||
cppOutput.push('');
|
||||
|
||||
cppOutput.push(' _json.writeObjectStart();');
|
||||
cppOutput.push(' _json.writeObjectStart();');
|
||||
|
||||
// Write type field
|
||||
cppOutput.push(' _json.writeName("type");');
|
||||
cppOutput.push(` _json.writeValue("${shortName}");`);
|
||||
// Write type field
|
||||
cppOutput.push(' _json.writeName("type");');
|
||||
cppOutput.push(` _json.writeValue("${shortName}");`);
|
||||
|
||||
// Write properties
|
||||
for (const property of method.properties) {
|
||||
cppOutput.push('');
|
||||
cppOutput.push(` _json.writeName("${property.name}");`);
|
||||
const propertyLines = generatePropertyCode(property, ' ', ir.enumMappings);
|
||||
cppOutput.push(...propertyLines);
|
||||
}
|
||||
// Write properties
|
||||
for (const property of method.properties) {
|
||||
cppOutput.push('');
|
||||
cppOutput.push(` _json.writeName("${property.name}");`);
|
||||
const propertyLines = generatePropertyCode(property, ' ', ir.enumMappings);
|
||||
cppOutput.push(...propertyLines);
|
||||
}
|
||||
|
||||
cppOutput.push('');
|
||||
cppOutput.push(' _json.writeObjectEnd();');
|
||||
}
|
||||
cppOutput.push('');
|
||||
cppOutput.push(' _json.writeObjectEnd();');
|
||||
}
|
||||
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push('');
|
||||
}
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push('');
|
||||
}
|
||||
|
||||
// Add custom helper methods for special types
|
||||
cppOutput.push(' // Custom helper methods');
|
||||
cppOutput.push(' void writeColor(Color* obj) {');
|
||||
cppOutput.push(' if (obj == nullptr) {');
|
||||
cppOutput.push(' _json.writeNull();');
|
||||
cppOutput.push(' } else {');
|
||||
cppOutput.push(' _json.writeObjectStart();');
|
||||
cppOutput.push(' _json.writeName("r");');
|
||||
cppOutput.push(' _json.writeValue(obj->r);');
|
||||
cppOutput.push(' _json.writeName("g");');
|
||||
cppOutput.push(' _json.writeValue(obj->g);');
|
||||
cppOutput.push(' _json.writeName("b");');
|
||||
cppOutput.push(' _json.writeValue(obj->b);');
|
||||
cppOutput.push(' _json.writeName("a");');
|
||||
cppOutput.push(' _json.writeValue(obj->a);');
|
||||
cppOutput.push(' _json.writeObjectEnd();');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push('');
|
||||
// Add custom helper methods for special types
|
||||
cppOutput.push(' // Custom helper methods');
|
||||
cppOutput.push(' void writeColor(Color* obj) {');
|
||||
cppOutput.push(' if (obj == nullptr) {');
|
||||
cppOutput.push(' _json.writeNull();');
|
||||
cppOutput.push(' } else {');
|
||||
cppOutput.push(' _json.writeObjectStart();');
|
||||
cppOutput.push(' _json.writeName("r");');
|
||||
cppOutput.push(' _json.writeValue(obj->r);');
|
||||
cppOutput.push(' _json.writeName("g");');
|
||||
cppOutput.push(' _json.writeValue(obj->g);');
|
||||
cppOutput.push(' _json.writeName("b");');
|
||||
cppOutput.push(' _json.writeValue(obj->b);');
|
||||
cppOutput.push(' _json.writeName("a");');
|
||||
cppOutput.push(' _json.writeValue(obj->a);');
|
||||
cppOutput.push(' _json.writeObjectEnd();');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push('');
|
||||
|
||||
cppOutput.push(' void writeColor(const Color& obj) {');
|
||||
cppOutput.push(' _json.writeObjectStart();');
|
||||
cppOutput.push(' _json.writeName("r");');
|
||||
cppOutput.push(' _json.writeValue(obj.r);');
|
||||
cppOutput.push(' _json.writeName("g");');
|
||||
cppOutput.push(' _json.writeValue(obj.g);');
|
||||
cppOutput.push(' _json.writeName("b");');
|
||||
cppOutput.push(' _json.writeValue(obj.b);');
|
||||
cppOutput.push(' _json.writeName("a");');
|
||||
cppOutput.push(' _json.writeValue(obj.a);');
|
||||
cppOutput.push(' _json.writeObjectEnd();');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push('');
|
||||
cppOutput.push(' void writeColor(const Color& obj) {');
|
||||
cppOutput.push(' _json.writeObjectStart();');
|
||||
cppOutput.push(' _json.writeName("r");');
|
||||
cppOutput.push(' _json.writeValue(obj.r);');
|
||||
cppOutput.push(' _json.writeName("g");');
|
||||
cppOutput.push(' _json.writeValue(obj.g);');
|
||||
cppOutput.push(' _json.writeName("b");');
|
||||
cppOutput.push(' _json.writeValue(obj.b);');
|
||||
cppOutput.push(' _json.writeName("a");');
|
||||
cppOutput.push(' _json.writeValue(obj.a);');
|
||||
cppOutput.push(' _json.writeObjectEnd();');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push('');
|
||||
|
||||
cppOutput.push(' void writeTextureRegion(TextureRegion* obj) {');
|
||||
cppOutput.push(' if (obj == nullptr) {');
|
||||
cppOutput.push(' _json.writeNull();');
|
||||
cppOutput.push(' } else {');
|
||||
cppOutput.push(' _json.writeObjectStart();');
|
||||
cppOutput.push(' _json.writeName("u");');
|
||||
cppOutput.push(' _json.writeValue(obj->getU());');
|
||||
cppOutput.push(' _json.writeName("v");');
|
||||
cppOutput.push(' _json.writeValue(obj->getV());');
|
||||
cppOutput.push(' _json.writeName("u2");');
|
||||
cppOutput.push(' _json.writeValue(obj->getU2());');
|
||||
cppOutput.push(' _json.writeName("v2");');
|
||||
cppOutput.push(' _json.writeValue(obj->getV2());');
|
||||
cppOutput.push(' _json.writeName("width");');
|
||||
cppOutput.push(' _json.writeValue(obj->getRegionWidth());');
|
||||
cppOutput.push(' _json.writeName("height");');
|
||||
cppOutput.push(' _json.writeValue(obj->getRegionHeight());');
|
||||
cppOutput.push(' _json.writeObjectEnd();');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push('');
|
||||
cppOutput.push(' void writeTextureRegion(TextureRegion* obj) {');
|
||||
cppOutput.push(' if (obj == nullptr) {');
|
||||
cppOutput.push(' _json.writeNull();');
|
||||
cppOutput.push(' } else {');
|
||||
cppOutput.push(' _json.writeObjectStart();');
|
||||
cppOutput.push(' _json.writeName("u");');
|
||||
cppOutput.push(' _json.writeValue(obj->getU());');
|
||||
cppOutput.push(' _json.writeName("v");');
|
||||
cppOutput.push(' _json.writeValue(obj->getV());');
|
||||
cppOutput.push(' _json.writeName("u2");');
|
||||
cppOutput.push(' _json.writeValue(obj->getU2());');
|
||||
cppOutput.push(' _json.writeName("v2");');
|
||||
cppOutput.push(' _json.writeValue(obj->getV2());');
|
||||
cppOutput.push(' _json.writeName("width");');
|
||||
cppOutput.push(' _json.writeValue(obj->getRegionWidth());');
|
||||
cppOutput.push(' _json.writeName("height");');
|
||||
cppOutput.push(' _json.writeValue(obj->getRegionHeight());');
|
||||
cppOutput.push(' _json.writeObjectEnd();');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push('');
|
||||
|
||||
cppOutput.push(' void writeTextureRegion(const TextureRegion& obj) {');
|
||||
cppOutput.push(' _json.writeObjectStart();');
|
||||
cppOutput.push(' _json.writeName("u");');
|
||||
cppOutput.push(' _json.writeValue(obj.getU());');
|
||||
cppOutput.push(' _json.writeName("v");');
|
||||
cppOutput.push(' _json.writeValue(obj.getV());');
|
||||
cppOutput.push(' _json.writeName("u2");');
|
||||
cppOutput.push(' _json.writeValue(obj.getU2());');
|
||||
cppOutput.push(' _json.writeName("v2");');
|
||||
cppOutput.push(' _json.writeValue(obj.getV2());');
|
||||
cppOutput.push(' _json.writeName("width");');
|
||||
cppOutput.push(' _json.writeValue(obj.getRegionWidth());');
|
||||
cppOutput.push(' _json.writeName("height");');
|
||||
cppOutput.push(' _json.writeValue(obj.getRegionHeight());');
|
||||
cppOutput.push(' _json.writeObjectEnd();');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push('');
|
||||
cppOutput.push(' void writeTextureRegion(const TextureRegion& obj) {');
|
||||
cppOutput.push(' _json.writeObjectStart();');
|
||||
cppOutput.push(' _json.writeName("u");');
|
||||
cppOutput.push(' _json.writeValue(obj.getU());');
|
||||
cppOutput.push(' _json.writeName("v");');
|
||||
cppOutput.push(' _json.writeValue(obj.getV());');
|
||||
cppOutput.push(' _json.writeName("u2");');
|
||||
cppOutput.push(' _json.writeValue(obj.getU2());');
|
||||
cppOutput.push(' _json.writeName("v2");');
|
||||
cppOutput.push(' _json.writeValue(obj.getV2());');
|
||||
cppOutput.push(' _json.writeName("width");');
|
||||
cppOutput.push(' _json.writeValue(obj.getRegionWidth());');
|
||||
cppOutput.push(' _json.writeName("height");');
|
||||
cppOutput.push(' _json.writeValue(obj.getRegionHeight());');
|
||||
cppOutput.push(' _json.writeObjectEnd();');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push('');
|
||||
|
||||
cppOutput.push(' void writeIntArray(const Array<int>& obj) {');
|
||||
cppOutput.push(' _json.writeArrayStart();');
|
||||
cppOutput.push(' for (size_t i = 0; i < obj.size(); i++) {');
|
||||
cppOutput.push(' _json.writeValue(obj[i]);');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push(' _json.writeArrayEnd();');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push('');
|
||||
cppOutput.push(' void writeIntArray(const Array<int>& obj) {');
|
||||
cppOutput.push(' _json.writeArrayStart();');
|
||||
cppOutput.push(' for (size_t i = 0; i < obj.size(); i++) {');
|
||||
cppOutput.push(' _json.writeValue(obj[i]);');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push(' _json.writeArrayEnd();');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push('');
|
||||
|
||||
cppOutput.push(' void writeFloatArray(const Array<float>& obj) {');
|
||||
cppOutput.push(' _json.writeArrayStart();');
|
||||
cppOutput.push(' for (size_t i = 0; i < obj.size(); i++) {');
|
||||
cppOutput.push(' _json.writeValue(obj[i]);');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push(' _json.writeArrayEnd();');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push('');
|
||||
cppOutput.push(' void writeFloatArray(const Array<float>& obj) {');
|
||||
cppOutput.push(' _json.writeArrayStart();');
|
||||
cppOutput.push(' for (size_t i = 0; i < obj.size(); i++) {');
|
||||
cppOutput.push(' _json.writeValue(obj[i]);');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push(' _json.writeArrayEnd();');
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push('');
|
||||
|
||||
// Add reference versions for write methods (excluding custom implementations)
|
||||
cppOutput.push(' // Reference versions of write methods');
|
||||
const writeMethods = ir.writeMethods.filter(m =>
|
||||
!m.isAbstractType &&
|
||||
m.name !== 'writeSkin' &&
|
||||
m.name !== 'writeSkinEntry'
|
||||
);
|
||||
for (const method of writeMethods) {
|
||||
const cppType = transformType(method.paramType);
|
||||
cppOutput.push(` void ${method.name}(const ${cppType}& obj) {`);
|
||||
cppOutput.push(` ${method.name}(const_cast<${cppType}*>(&obj));`);
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push('');
|
||||
}
|
||||
// Add reference versions for write methods (excluding custom implementations)
|
||||
cppOutput.push(' // Reference versions of write methods');
|
||||
const writeMethods = ir.writeMethods.filter(m =>
|
||||
!m.isAbstractType &&
|
||||
m.name !== 'writeSkin' &&
|
||||
m.name !== 'writeSkinEntry'
|
||||
);
|
||||
for (const method of writeMethods) {
|
||||
const cppType = transformType(method.paramType);
|
||||
cppOutput.push(` void ${method.name}(const ${cppType}& obj) {`);
|
||||
cppOutput.push(` ${method.name}(const_cast<${cppType}*>(&obj));`);
|
||||
cppOutput.push(' }');
|
||||
cppOutput.push('');
|
||||
}
|
||||
|
||||
|
||||
// C++ footer
|
||||
cppOutput.push('};');
|
||||
cppOutput.push('');
|
||||
cppOutput.push('} // namespace spine');
|
||||
cppOutput.push('');
|
||||
cppOutput.push('#endif');
|
||||
// C++ footer
|
||||
cppOutput.push('};');
|
||||
cppOutput.push('');
|
||||
cppOutput.push('} // namespace spine');
|
||||
cppOutput.push('');
|
||||
cppOutput.push('#endif');
|
||||
|
||||
return cppOutput.join('\n');
|
||||
return cppOutput.join('\n');
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
// Read the IR file
|
||||
const irFile = path.resolve(__dirname, '../output/serializer-ir.json');
|
||||
if (!fs.existsSync(irFile)) {
|
||||
console.error('Serializer IR not found. Run generate-serializer-ir.ts first.');
|
||||
process.exit(1);
|
||||
}
|
||||
async function main () {
|
||||
try {
|
||||
// Read the IR file
|
||||
const irFile = path.resolve(__dirname, '../output/serializer-ir.json');
|
||||
if (!fs.existsSync(irFile)) {
|
||||
console.error('Serializer IR not found. Run generate-serializer-ir.ts first.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const ir: SerializerIR = JSON.parse(fs.readFileSync(irFile, 'utf8'));
|
||||
const ir: SerializerIR = JSON.parse(fs.readFileSync(irFile, 'utf8'));
|
||||
|
||||
// Generate C++ serializer from IR
|
||||
const cppCode = generateCppFromIR(ir);
|
||||
// Generate C++ serializer from IR
|
||||
const cppCode = generateCppFromIR(ir);
|
||||
|
||||
// Write the C++ file
|
||||
const cppFile = path.resolve(
|
||||
__dirname,
|
||||
'../../spine-cpp/tests/SkeletonSerializer.h'
|
||||
);
|
||||
// Write the C++ file
|
||||
const cppFile = path.resolve(
|
||||
__dirname,
|
||||
'../../spine-cpp/tests/SkeletonSerializer.h'
|
||||
);
|
||||
|
||||
fs.mkdirSync(path.dirname(cppFile), { recursive: true });
|
||||
fs.writeFileSync(cppFile, cppCode);
|
||||
fs.mkdirSync(path.dirname(cppFile), { recursive: true });
|
||||
fs.writeFileSync(cppFile, cppCode);
|
||||
|
||||
console.log(`Generated C++ serializer from IR: ${cppFile}`);
|
||||
console.log(`- ${ir.publicMethods.length} public methods`);
|
||||
console.log(`- ${ir.writeMethods.length} write methods`);
|
||||
console.log(`- ${Object.keys(ir.enumMappings).length} enum mappings`);
|
||||
console.log(`Generated C++ serializer from IR: ${cppFile}`);
|
||||
console.log(`- ${ir.publicMethods.length} public methods`);
|
||||
console.log(`- ${ir.writeMethods.length} write methods`);
|
||||
console.log(`- ${Object.keys(ir.enumMappings).length} enum mappings`);
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('Error:', error.message);
|
||||
console.error('Stack:', error.stack);
|
||||
process.exit(1);
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('Error:', error.message);
|
||||
console.error('Stack:', error.stack);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Allow running as a script or importing the function
|
||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
main();
|
||||
main();
|
||||
}
|
||||
|
||||
export { generateCppFromIR };
|
||||
|
||||
@ -7,323 +7,323 @@ import type { Property, SerializerIR, WriteMethod } from './generate-serializer-
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
function generatePropertyCode(property: Property, indent: string, method?: WriteMethod): string[] {
|
||||
const lines: string[] = [];
|
||||
const accessor = `obj.${property.getter}`;
|
||||
function generatePropertyCode (property: Property, indent: string, method?: WriteMethod): string[] {
|
||||
const lines: string[] = [];
|
||||
const accessor = `obj.${property.getter}`;
|
||||
|
||||
switch (property.kind) {
|
||||
case "primitive":
|
||||
lines.push(`${indent}json.writeValue(${accessor});`);
|
||||
break;
|
||||
switch (property.kind) {
|
||||
case "primitive":
|
||||
lines.push(`${indent}json.writeValue(${accessor});`);
|
||||
break;
|
||||
|
||||
case "object":
|
||||
if (property.isNullable) {
|
||||
lines.push(`${indent}if (${accessor} == null) {`);
|
||||
lines.push(`${indent} json.writeNull();`);
|
||||
lines.push(`${indent}} else {`);
|
||||
lines.push(`${indent} ${property.writeMethodCall}(${accessor});`);
|
||||
lines.push(`${indent}}`);
|
||||
} else {
|
||||
lines.push(`${indent}${property.writeMethodCall}(${accessor});`);
|
||||
}
|
||||
break;
|
||||
case "object":
|
||||
if (property.isNullable) {
|
||||
lines.push(`${indent}if (${accessor} == null) {`);
|
||||
lines.push(`${indent} json.writeNull();`);
|
||||
lines.push(`${indent}} else {`);
|
||||
lines.push(`${indent} ${property.writeMethodCall}(${accessor});`);
|
||||
lines.push(`${indent}}`);
|
||||
} else {
|
||||
lines.push(`${indent}${property.writeMethodCall}(${accessor});`);
|
||||
}
|
||||
break;
|
||||
|
||||
case "enum":
|
||||
if (property.isNullable) {
|
||||
lines.push(`${indent}if (${accessor} == null) {`);
|
||||
lines.push(`${indent} json.writeNull();`);
|
||||
lines.push(`${indent}} else {`);
|
||||
lines.push(`${indent} json.writeValue(${accessor}.name());`);
|
||||
lines.push(`${indent}}`);
|
||||
} else {
|
||||
lines.push(`${indent}json.writeValue(${accessor}.name());`);
|
||||
}
|
||||
break;
|
||||
case "enum":
|
||||
if (property.isNullable) {
|
||||
lines.push(`${indent}if (${accessor} == null) {`);
|
||||
lines.push(`${indent} json.writeNull();`);
|
||||
lines.push(`${indent}} else {`);
|
||||
lines.push(`${indent} json.writeValue(${accessor}.name());`);
|
||||
lines.push(`${indent}}`);
|
||||
} else {
|
||||
lines.push(`${indent}json.writeValue(${accessor}.name());`);
|
||||
}
|
||||
break;
|
||||
|
||||
case "array":
|
||||
// Special handling for Skin attachments - sort by slot index
|
||||
const isSkinAttachments = method?.paramType === 'Skin' && property.name === 'attachments' && property.elementType === 'SkinEntry';
|
||||
const sortedAccessor = isSkinAttachments ? 'sortedAttachments' : accessor;
|
||||
case "array":
|
||||
// Special handling for Skin attachments - sort by slot index
|
||||
const isSkinAttachments = method?.paramType === 'Skin' && property.name === 'attachments' && property.elementType === 'SkinEntry';
|
||||
const sortedAccessor = isSkinAttachments ? 'sortedAttachments' : accessor;
|
||||
|
||||
if (isSkinAttachments) {
|
||||
lines.push(`${indent}Array<${property.elementType}> sortedAttachments = new Array<>(${accessor});`);
|
||||
lines.push(`${indent}sortedAttachments.sort((a, b) -> Integer.compare(a.getSlotIndex(), b.getSlotIndex()));`);
|
||||
}
|
||||
if (isSkinAttachments) {
|
||||
lines.push(`${indent}Array<${property.elementType}> sortedAttachments = new Array<>(${accessor});`);
|
||||
lines.push(`${indent}sortedAttachments.sort((a, b) -> Integer.compare(a.getSlotIndex(), b.getSlotIndex()));`);
|
||||
}
|
||||
|
||||
if (property.isNullable) {
|
||||
lines.push(`${indent}if (${accessor} == null) {`);
|
||||
lines.push(`${indent} json.writeNull();`);
|
||||
lines.push(`${indent}} else {`);
|
||||
lines.push(`${indent} json.writeArrayStart();`);
|
||||
lines.push(`${indent} for (${property.elementType} item : ${sortedAccessor}) {`);
|
||||
if (property.elementKind === "primitive") {
|
||||
lines.push(`${indent} json.writeValue(item);`);
|
||||
} else {
|
||||
lines.push(`${indent} ${property.writeMethodCall}(item);`);
|
||||
}
|
||||
lines.push(`${indent} }`);
|
||||
lines.push(`${indent} json.writeArrayEnd();`);
|
||||
lines.push(`${indent}}`);
|
||||
} else {
|
||||
lines.push(`${indent}json.writeArrayStart();`);
|
||||
lines.push(`${indent}for (${property.elementType} item : ${sortedAccessor}) {`);
|
||||
if (property.elementKind === "primitive") {
|
||||
lines.push(`${indent} json.writeValue(item);`);
|
||||
} else {
|
||||
lines.push(`${indent} ${property.writeMethodCall}(item);`);
|
||||
}
|
||||
lines.push(`${indent}}`);
|
||||
lines.push(`${indent}json.writeArrayEnd();`);
|
||||
}
|
||||
break;
|
||||
if (property.isNullable) {
|
||||
lines.push(`${indent}if (${accessor} == null) {`);
|
||||
lines.push(`${indent} json.writeNull();`);
|
||||
lines.push(`${indent}} else {`);
|
||||
lines.push(`${indent} json.writeArrayStart();`);
|
||||
lines.push(`${indent} for (${property.elementType} item : ${sortedAccessor}) {`);
|
||||
if (property.elementKind === "primitive") {
|
||||
lines.push(`${indent} json.writeValue(item);`);
|
||||
} else {
|
||||
lines.push(`${indent} ${property.writeMethodCall}(item);`);
|
||||
}
|
||||
lines.push(`${indent} }`);
|
||||
lines.push(`${indent} json.writeArrayEnd();`);
|
||||
lines.push(`${indent}}`);
|
||||
} else {
|
||||
lines.push(`${indent}json.writeArrayStart();`);
|
||||
lines.push(`${indent}for (${property.elementType} item : ${sortedAccessor}) {`);
|
||||
if (property.elementKind === "primitive") {
|
||||
lines.push(`${indent} json.writeValue(item);`);
|
||||
} else {
|
||||
lines.push(`${indent} ${property.writeMethodCall}(item);`);
|
||||
}
|
||||
lines.push(`${indent}}`);
|
||||
lines.push(`${indent}json.writeArrayEnd();`);
|
||||
}
|
||||
break;
|
||||
|
||||
case "nestedArray":
|
||||
if (property.isNullable) {
|
||||
lines.push(`${indent}if (${accessor} == null) {`);
|
||||
lines.push(`${indent} json.writeNull();`);
|
||||
lines.push(`${indent}} else {`);
|
||||
lines.push(`${indent} json.writeArrayStart();`);
|
||||
lines.push(`${indent} for (${property.elementType}[] nestedArray : ${accessor}) {`);
|
||||
lines.push(`${indent} if (nestedArray == null) {`);
|
||||
lines.push(`${indent} json.writeNull();`);
|
||||
lines.push(`${indent} } else {`);
|
||||
lines.push(`${indent} json.writeArrayStart();`);
|
||||
lines.push(`${indent} for (${property.elementType} elem : nestedArray) {`);
|
||||
lines.push(`${indent} json.writeValue(elem);`);
|
||||
lines.push(`${indent} }`);
|
||||
lines.push(`${indent} json.writeArrayEnd();`);
|
||||
lines.push(`${indent} }`);
|
||||
lines.push(`${indent} }`);
|
||||
lines.push(`${indent} json.writeArrayEnd();`);
|
||||
lines.push(`${indent}}`);
|
||||
} else {
|
||||
lines.push(`${indent}json.writeArrayStart();`);
|
||||
lines.push(`${indent}for (${property.elementType}[] nestedArray : ${accessor}) {`);
|
||||
lines.push(`${indent} json.writeArrayStart();`);
|
||||
lines.push(`${indent} for (${property.elementType} elem : nestedArray) {`);
|
||||
lines.push(`${indent} json.writeValue(elem);`);
|
||||
lines.push(`${indent} }`);
|
||||
lines.push(`${indent} json.writeArrayEnd();`);
|
||||
lines.push(`${indent}}`);
|
||||
lines.push(`${indent}json.writeArrayEnd();`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "nestedArray":
|
||||
if (property.isNullable) {
|
||||
lines.push(`${indent}if (${accessor} == null) {`);
|
||||
lines.push(`${indent} json.writeNull();`);
|
||||
lines.push(`${indent}} else {`);
|
||||
lines.push(`${indent} json.writeArrayStart();`);
|
||||
lines.push(`${indent} for (${property.elementType}[] nestedArray : ${accessor}) {`);
|
||||
lines.push(`${indent} if (nestedArray == null) {`);
|
||||
lines.push(`${indent} json.writeNull();`);
|
||||
lines.push(`${indent} } else {`);
|
||||
lines.push(`${indent} json.writeArrayStart();`);
|
||||
lines.push(`${indent} for (${property.elementType} elem : nestedArray) {`);
|
||||
lines.push(`${indent} json.writeValue(elem);`);
|
||||
lines.push(`${indent} }`);
|
||||
lines.push(`${indent} json.writeArrayEnd();`);
|
||||
lines.push(`${indent} }`);
|
||||
lines.push(`${indent} }`);
|
||||
lines.push(`${indent} json.writeArrayEnd();`);
|
||||
lines.push(`${indent}}`);
|
||||
} else {
|
||||
lines.push(`${indent}json.writeArrayStart();`);
|
||||
lines.push(`${indent}for (${property.elementType}[] nestedArray : ${accessor}) {`);
|
||||
lines.push(`${indent} json.writeArrayStart();`);
|
||||
lines.push(`${indent} for (${property.elementType} elem : nestedArray) {`);
|
||||
lines.push(`${indent} json.writeValue(elem);`);
|
||||
lines.push(`${indent} }`);
|
||||
lines.push(`${indent} json.writeArrayEnd();`);
|
||||
lines.push(`${indent}}`);
|
||||
lines.push(`${indent}json.writeArrayEnd();`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return lines;
|
||||
return lines;
|
||||
}
|
||||
|
||||
function generateJavaFromIR(ir: SerializerIR): string {
|
||||
const javaOutput: string[] = [];
|
||||
function generateJavaFromIR (ir: SerializerIR): string {
|
||||
const javaOutput: string[] = [];
|
||||
|
||||
// Generate Java file header
|
||||
javaOutput.push('package com.esotericsoftware.spine.utils;');
|
||||
javaOutput.push('');
|
||||
javaOutput.push('import com.esotericsoftware.spine.*;');
|
||||
javaOutput.push('import com.esotericsoftware.spine.Animation.*;');
|
||||
javaOutput.push('import com.esotericsoftware.spine.AnimationState.*;');
|
||||
javaOutput.push('import com.esotericsoftware.spine.BoneData.Inherit;');
|
||||
javaOutput.push('import com.esotericsoftware.spine.Skin.SkinEntry;');
|
||||
javaOutput.push('import com.esotericsoftware.spine.PathConstraintData.*;');
|
||||
javaOutput.push('import com.esotericsoftware.spine.TransformConstraintData.*;');
|
||||
javaOutput.push('import com.esotericsoftware.spine.attachments.*;');
|
||||
javaOutput.push('import com.badlogic.gdx.graphics.Color;');
|
||||
javaOutput.push('import com.badlogic.gdx.graphics.g2d.TextureRegion;');
|
||||
javaOutput.push('import com.badlogic.gdx.utils.Array;');
|
||||
javaOutput.push('import com.badlogic.gdx.utils.IntArray;');
|
||||
javaOutput.push('import com.badlogic.gdx.utils.FloatArray;');
|
||||
javaOutput.push('');
|
||||
javaOutput.push('import java.util.Locale;');
|
||||
javaOutput.push('import java.util.Set;');
|
||||
javaOutput.push('import java.util.HashSet;');
|
||||
javaOutput.push('');
|
||||
javaOutput.push('public class SkeletonSerializer {');
|
||||
javaOutput.push(' private final Set<Object> visitedObjects = new HashSet<>();');
|
||||
javaOutput.push(' private JsonWriter json;');
|
||||
javaOutput.push('');
|
||||
// Generate Java file header
|
||||
javaOutput.push('package com.esotericsoftware.spine.utils;');
|
||||
javaOutput.push('');
|
||||
javaOutput.push('import com.esotericsoftware.spine.*;');
|
||||
javaOutput.push('import com.esotericsoftware.spine.Animation.*;');
|
||||
javaOutput.push('import com.esotericsoftware.spine.AnimationState.*;');
|
||||
javaOutput.push('import com.esotericsoftware.spine.BoneData.Inherit;');
|
||||
javaOutput.push('import com.esotericsoftware.spine.Skin.SkinEntry;');
|
||||
javaOutput.push('import com.esotericsoftware.spine.PathConstraintData.*;');
|
||||
javaOutput.push('import com.esotericsoftware.spine.TransformConstraintData.*;');
|
||||
javaOutput.push('import com.esotericsoftware.spine.attachments.*;');
|
||||
javaOutput.push('import com.badlogic.gdx.graphics.Color;');
|
||||
javaOutput.push('import com.badlogic.gdx.graphics.g2d.TextureRegion;');
|
||||
javaOutput.push('import com.badlogic.gdx.utils.Array;');
|
||||
javaOutput.push('import com.badlogic.gdx.utils.IntArray;');
|
||||
javaOutput.push('import com.badlogic.gdx.utils.FloatArray;');
|
||||
javaOutput.push('');
|
||||
javaOutput.push('import java.util.Locale;');
|
||||
javaOutput.push('import java.util.Set;');
|
||||
javaOutput.push('import java.util.HashSet;');
|
||||
javaOutput.push('');
|
||||
javaOutput.push('public class SkeletonSerializer {');
|
||||
javaOutput.push(' private final Set<Object> visitedObjects = new HashSet<>();');
|
||||
javaOutput.push(' private JsonWriter json;');
|
||||
javaOutput.push('');
|
||||
|
||||
// Generate public methods
|
||||
for (const method of ir.publicMethods) {
|
||||
javaOutput.push(` public String ${method.name}(${method.paramType} ${method.paramName}) {`);
|
||||
javaOutput.push(' visitedObjects.clear();');
|
||||
javaOutput.push(' json = new JsonWriter();');
|
||||
javaOutput.push(` ${method.writeMethodCall}(${method.paramName});`);
|
||||
javaOutput.push(' json.close();');
|
||||
javaOutput.push(' return json.getString();');
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push('');
|
||||
}
|
||||
// Generate public methods
|
||||
for (const method of ir.publicMethods) {
|
||||
javaOutput.push(` public String ${method.name}(${method.paramType} ${method.paramName}) {`);
|
||||
javaOutput.push(' visitedObjects.clear();');
|
||||
javaOutput.push(' json = new JsonWriter();');
|
||||
javaOutput.push(` ${method.writeMethodCall}(${method.paramName});`);
|
||||
javaOutput.push(' json.close();');
|
||||
javaOutput.push(' return json.getString();');
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push('');
|
||||
}
|
||||
|
||||
// Generate write methods
|
||||
for (const method of ir.writeMethods) {
|
||||
const shortName = method.paramType.split('.').pop()!;
|
||||
const className = method.paramType.includes('.') ? method.paramType : shortName;
|
||||
// Generate write methods
|
||||
for (const method of ir.writeMethods) {
|
||||
const shortName = method.paramType.split('.').pop()!;
|
||||
const className = method.paramType.includes('.') ? method.paramType : shortName;
|
||||
|
||||
javaOutput.push(` private void ${method.name}(${className} obj) {`);
|
||||
javaOutput.push(` private void ${method.name}(${className} obj) {`);
|
||||
|
||||
if (method.isAbstractType) {
|
||||
// Handle abstract types with instanceof chain
|
||||
if (method.subtypeChecks && method.subtypeChecks.length > 0) {
|
||||
let first = true;
|
||||
for (const subtype of method.subtypeChecks) {
|
||||
const subtypeShortName = subtype.typeName.split('.').pop()!;
|
||||
const subtypeClassName = subtype.typeName.includes('.') ? subtype.typeName : subtypeShortName;
|
||||
if (method.isAbstractType) {
|
||||
// Handle abstract types with instanceof chain
|
||||
if (method.subtypeChecks && method.subtypeChecks.length > 0) {
|
||||
let first = true;
|
||||
for (const subtype of method.subtypeChecks) {
|
||||
const subtypeShortName = subtype.typeName.split('.').pop()!;
|
||||
const subtypeClassName = subtype.typeName.includes('.') ? subtype.typeName : subtypeShortName;
|
||||
|
||||
if (first) {
|
||||
javaOutput.push(` if (obj instanceof ${subtypeClassName}) {`);
|
||||
first = false;
|
||||
} else {
|
||||
javaOutput.push(` } else if (obj instanceof ${subtypeClassName}) {`);
|
||||
}
|
||||
javaOutput.push(` ${subtype.writeMethodCall}((${subtypeClassName}) obj);`);
|
||||
}
|
||||
javaOutput.push(' } else {');
|
||||
javaOutput.push(` throw new RuntimeException("Unknown ${shortName} type: " + obj.getClass().getName());`);
|
||||
javaOutput.push(' }');
|
||||
} else {
|
||||
javaOutput.push(' json.writeNull(); // No concrete implementations after filtering exclusions');
|
||||
}
|
||||
} else {
|
||||
// Handle concrete types
|
||||
// Add cycle detection
|
||||
javaOutput.push(' if (visitedObjects.contains(obj)) {');
|
||||
javaOutput.push(' json.writeValue("<circular>");');
|
||||
javaOutput.push(' return;');
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push(' visitedObjects.add(obj);');
|
||||
javaOutput.push('');
|
||||
if (first) {
|
||||
javaOutput.push(` if (obj instanceof ${subtypeClassName}) {`);
|
||||
first = false;
|
||||
} else {
|
||||
javaOutput.push(` } else if (obj instanceof ${subtypeClassName}) {`);
|
||||
}
|
||||
javaOutput.push(` ${subtype.writeMethodCall}((${subtypeClassName}) obj);`);
|
||||
}
|
||||
javaOutput.push(' } else {');
|
||||
javaOutput.push(` throw new RuntimeException("Unknown ${shortName} type: " + obj.getClass().getName());`);
|
||||
javaOutput.push(' }');
|
||||
} else {
|
||||
javaOutput.push(' json.writeNull(); // No concrete implementations after filtering exclusions');
|
||||
}
|
||||
} else {
|
||||
// Handle concrete types
|
||||
// Add cycle detection
|
||||
javaOutput.push(' if (visitedObjects.contains(obj)) {');
|
||||
javaOutput.push(' json.writeValue("<circular>");');
|
||||
javaOutput.push(' return;');
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push(' visitedObjects.add(obj);');
|
||||
javaOutput.push('');
|
||||
|
||||
javaOutput.push(' json.writeObjectStart();');
|
||||
javaOutput.push(' json.writeObjectStart();');
|
||||
|
||||
// Write type field
|
||||
javaOutput.push(' json.writeName("type");');
|
||||
javaOutput.push(` json.writeValue("${shortName}");`);
|
||||
// Write type field
|
||||
javaOutput.push(' json.writeName("type");');
|
||||
javaOutput.push(` json.writeValue("${shortName}");`);
|
||||
|
||||
// Write properties
|
||||
for (const property of method.properties) {
|
||||
javaOutput.push('');
|
||||
javaOutput.push(` json.writeName("${property.name}");`);
|
||||
const propertyLines = generatePropertyCode(property, ' ', method);
|
||||
javaOutput.push(...propertyLines);
|
||||
}
|
||||
// Write properties
|
||||
for (const property of method.properties) {
|
||||
javaOutput.push('');
|
||||
javaOutput.push(` json.writeName("${property.name}");`);
|
||||
const propertyLines = generatePropertyCode(property, ' ', method);
|
||||
javaOutput.push(...propertyLines);
|
||||
}
|
||||
|
||||
javaOutput.push('');
|
||||
javaOutput.push(' json.writeObjectEnd();');
|
||||
}
|
||||
javaOutput.push('');
|
||||
javaOutput.push(' json.writeObjectEnd();');
|
||||
}
|
||||
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push('');
|
||||
}
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push('');
|
||||
}
|
||||
|
||||
// Add helper methods for special types
|
||||
javaOutput.push(' private void writeColor(Color obj) {');
|
||||
javaOutput.push(' if (obj == null) {');
|
||||
javaOutput.push(' json.writeNull();');
|
||||
javaOutput.push(' } else {');
|
||||
javaOutput.push(' json.writeObjectStart();');
|
||||
javaOutput.push(' json.writeName("r");');
|
||||
javaOutput.push(' json.writeValue(obj.r);');
|
||||
javaOutput.push(' json.writeName("g");');
|
||||
javaOutput.push(' json.writeValue(obj.g);');
|
||||
javaOutput.push(' json.writeName("b");');
|
||||
javaOutput.push(' json.writeValue(obj.b);');
|
||||
javaOutput.push(' json.writeName("a");');
|
||||
javaOutput.push(' json.writeValue(obj.a);');
|
||||
javaOutput.push(' json.writeObjectEnd();');
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push('');
|
||||
// Add helper methods for special types
|
||||
javaOutput.push(' private void writeColor(Color obj) {');
|
||||
javaOutput.push(' if (obj == null) {');
|
||||
javaOutput.push(' json.writeNull();');
|
||||
javaOutput.push(' } else {');
|
||||
javaOutput.push(' json.writeObjectStart();');
|
||||
javaOutput.push(' json.writeName("r");');
|
||||
javaOutput.push(' json.writeValue(obj.r);');
|
||||
javaOutput.push(' json.writeName("g");');
|
||||
javaOutput.push(' json.writeValue(obj.g);');
|
||||
javaOutput.push(' json.writeName("b");');
|
||||
javaOutput.push(' json.writeValue(obj.b);');
|
||||
javaOutput.push(' json.writeName("a");');
|
||||
javaOutput.push(' json.writeValue(obj.a);');
|
||||
javaOutput.push(' json.writeObjectEnd();');
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push('');
|
||||
|
||||
javaOutput.push(' private void writeTextureRegion(TextureRegion obj) {');
|
||||
javaOutput.push(' if (obj == null) {');
|
||||
javaOutput.push(' json.writeNull();');
|
||||
javaOutput.push(' } else {');
|
||||
javaOutput.push(' json.writeObjectStart();');
|
||||
javaOutput.push(' json.writeName("u");');
|
||||
javaOutput.push(' json.writeValue(obj.getU());');
|
||||
javaOutput.push(' json.writeName("v");');
|
||||
javaOutput.push(' json.writeValue(obj.getV());');
|
||||
javaOutput.push(' json.writeName("u2");');
|
||||
javaOutput.push(' json.writeValue(obj.getU2());');
|
||||
javaOutput.push(' json.writeName("v2");');
|
||||
javaOutput.push(' json.writeValue(obj.getV2());');
|
||||
javaOutput.push(' json.writeName("width");');
|
||||
javaOutput.push(' json.writeValue(obj.getRegionWidth());');
|
||||
javaOutput.push(' json.writeName("height");');
|
||||
javaOutput.push(' json.writeValue(obj.getRegionHeight());');
|
||||
javaOutput.push(' json.writeObjectEnd();');
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push(' private void writeTextureRegion(TextureRegion obj) {');
|
||||
javaOutput.push(' if (obj == null) {');
|
||||
javaOutput.push(' json.writeNull();');
|
||||
javaOutput.push(' } else {');
|
||||
javaOutput.push(' json.writeObjectStart();');
|
||||
javaOutput.push(' json.writeName("u");');
|
||||
javaOutput.push(' json.writeValue(obj.getU());');
|
||||
javaOutput.push(' json.writeName("v");');
|
||||
javaOutput.push(' json.writeValue(obj.getV());');
|
||||
javaOutput.push(' json.writeName("u2");');
|
||||
javaOutput.push(' json.writeValue(obj.getU2());');
|
||||
javaOutput.push(' json.writeName("v2");');
|
||||
javaOutput.push(' json.writeValue(obj.getV2());');
|
||||
javaOutput.push(' json.writeName("width");');
|
||||
javaOutput.push(' json.writeValue(obj.getRegionWidth());');
|
||||
javaOutput.push(' json.writeName("height");');
|
||||
javaOutput.push(' json.writeValue(obj.getRegionHeight());');
|
||||
javaOutput.push(' json.writeObjectEnd();');
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push(' }');
|
||||
|
||||
// Add IntArray and FloatArray helper methods
|
||||
javaOutput.push('');
|
||||
javaOutput.push(' private void writeIntArray(IntArray obj) {');
|
||||
javaOutput.push(' if (obj == null) {');
|
||||
javaOutput.push(' json.writeNull();');
|
||||
javaOutput.push(' } else {');
|
||||
javaOutput.push(' json.writeArrayStart();');
|
||||
javaOutput.push(' for (int i = 0; i < obj.size; i++) {');
|
||||
javaOutput.push(' json.writeValue(obj.get(i));');
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push(' json.writeArrayEnd();');
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push('');
|
||||
// Add IntArray and FloatArray helper methods
|
||||
javaOutput.push('');
|
||||
javaOutput.push(' private void writeIntArray(IntArray obj) {');
|
||||
javaOutput.push(' if (obj == null) {');
|
||||
javaOutput.push(' json.writeNull();');
|
||||
javaOutput.push(' } else {');
|
||||
javaOutput.push(' json.writeArrayStart();');
|
||||
javaOutput.push(' for (int i = 0; i < obj.size; i++) {');
|
||||
javaOutput.push(' json.writeValue(obj.get(i));');
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push(' json.writeArrayEnd();');
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push('');
|
||||
|
||||
javaOutput.push(' private void writeFloatArray(FloatArray obj) {');
|
||||
javaOutput.push(' if (obj == null) {');
|
||||
javaOutput.push(' json.writeNull();');
|
||||
javaOutput.push(' } else {');
|
||||
javaOutput.push(' json.writeArrayStart();');
|
||||
javaOutput.push(' for (int i = 0; i < obj.size; i++) {');
|
||||
javaOutput.push(' json.writeValue(obj.get(i));');
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push(' json.writeArrayEnd();');
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push(' private void writeFloatArray(FloatArray obj) {');
|
||||
javaOutput.push(' if (obj == null) {');
|
||||
javaOutput.push(' json.writeNull();');
|
||||
javaOutput.push(' } else {');
|
||||
javaOutput.push(' json.writeArrayStart();');
|
||||
javaOutput.push(' for (int i = 0; i < obj.size; i++) {');
|
||||
javaOutput.push(' json.writeValue(obj.get(i));');
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push(' json.writeArrayEnd();');
|
||||
javaOutput.push(' }');
|
||||
javaOutput.push(' }');
|
||||
|
||||
javaOutput.push('}');
|
||||
javaOutput.push('}');
|
||||
|
||||
return javaOutput.join('\n');
|
||||
return javaOutput.join('\n');
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
// Read the IR file
|
||||
const irFile = path.resolve(__dirname, '../output/serializer-ir.json');
|
||||
if (!fs.existsSync(irFile)) {
|
||||
console.error('Serializer IR not found. Run generate-serializer-ir.ts first.');
|
||||
process.exit(1);
|
||||
}
|
||||
async function main () {
|
||||
try {
|
||||
// Read the IR file
|
||||
const irFile = path.resolve(__dirname, '../output/serializer-ir.json');
|
||||
if (!fs.existsSync(irFile)) {
|
||||
console.error('Serializer IR not found. Run generate-serializer-ir.ts first.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const ir: SerializerIR = JSON.parse(fs.readFileSync(irFile, 'utf8'));
|
||||
const ir: SerializerIR = JSON.parse(fs.readFileSync(irFile, 'utf8'));
|
||||
|
||||
// Generate Java serializer from IR
|
||||
const javaCode = generateJavaFromIR(ir);
|
||||
// Generate Java serializer from IR
|
||||
const javaCode = generateJavaFromIR(ir);
|
||||
|
||||
// Write the Java file
|
||||
const javaFile = path.resolve(
|
||||
__dirname,
|
||||
'../../spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/utils/SkeletonSerializer.java'
|
||||
);
|
||||
// Write the Java file
|
||||
const javaFile = path.resolve(
|
||||
__dirname,
|
||||
'../../spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/utils/SkeletonSerializer.java'
|
||||
);
|
||||
|
||||
fs.mkdirSync(path.dirname(javaFile), { recursive: true });
|
||||
fs.writeFileSync(javaFile, javaCode);
|
||||
fs.mkdirSync(path.dirname(javaFile), { recursive: true });
|
||||
fs.writeFileSync(javaFile, javaCode);
|
||||
|
||||
console.log(`Generated Java serializer from IR: ${javaFile}`);
|
||||
console.log(`- ${ir.publicMethods.length} public methods`);
|
||||
console.log(`- ${ir.writeMethods.length} write methods`);
|
||||
console.log(`Generated Java serializer from IR: ${javaFile}`);
|
||||
console.log(`- ${ir.publicMethods.length} public methods`);
|
||||
console.log(`- ${ir.writeMethods.length} write methods`);
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('Error:', error.message);
|
||||
console.error('Stack:', error.stack);
|
||||
process.exit(1);
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('Error:', error.message);
|
||||
console.error('Stack:', error.stack);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Allow running as a script or importing the function
|
||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
main();
|
||||
main();
|
||||
}
|
||||
|
||||
export { generateJavaFromIR };
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -2,44 +2,44 @@ import { Supertype } from '@mariozechner/lsp-cli';
|
||||
|
||||
// Shared types for the Spine serializer generator
|
||||
export interface ClassInfo {
|
||||
className: string;
|
||||
superTypes: string[]; // Just the names for backward compatibility
|
||||
superTypeDetails?: Supertype[]; // Full details with type arguments
|
||||
getters: GetterInfo[];
|
||||
fields: FieldInfo[];
|
||||
file: string;
|
||||
isAbstract: boolean;
|
||||
isInterface: boolean;
|
||||
isEnum: boolean;
|
||||
typeParameters?: string[]; // The class's own type parameters
|
||||
enumValues?: string[]; // For enums
|
||||
concreteImplementations?: string[]; // For abstract classes/interfaces - only leaf concrete types
|
||||
allImplementations?: string[]; // For abstract classes/interfaces - includes intermediate abstract types
|
||||
className: string;
|
||||
superTypes: string[]; // Just the names for backward compatibility
|
||||
superTypeDetails?: Supertype[]; // Full details with type arguments
|
||||
getters: GetterInfo[];
|
||||
fields: FieldInfo[];
|
||||
file: string;
|
||||
isAbstract: boolean;
|
||||
isInterface: boolean;
|
||||
isEnum: boolean;
|
||||
typeParameters?: string[]; // The class's own type parameters
|
||||
enumValues?: string[]; // For enums
|
||||
concreteImplementations?: string[]; // For abstract classes/interfaces - only leaf concrete types
|
||||
allImplementations?: string[]; // For abstract classes/interfaces - includes intermediate abstract types
|
||||
}
|
||||
|
||||
export interface GetterInfo {
|
||||
methodName: string;
|
||||
returnType: string;
|
||||
methodName: string;
|
||||
returnType: string;
|
||||
}
|
||||
|
||||
export interface FieldInfo {
|
||||
fieldName: string;
|
||||
fieldType: string;
|
||||
isFinal: boolean;
|
||||
fieldName: string;
|
||||
fieldType: string;
|
||||
isFinal: boolean;
|
||||
}
|
||||
|
||||
export interface PropertyInfo {
|
||||
name: string;
|
||||
type: string;
|
||||
isGetter: boolean;
|
||||
inheritedFrom?: string; // Which class this property was inherited from
|
||||
excluded: boolean; // Whether this property should be excluded from serialization
|
||||
name: string;
|
||||
type: string;
|
||||
isGetter: boolean;
|
||||
inheritedFrom?: string; // Which class this property was inherited from
|
||||
excluded: boolean; // Whether this property should be excluded from serialization
|
||||
}
|
||||
|
||||
export interface AnalysisResult {
|
||||
classMap: Map<string, ClassInfo>;
|
||||
accessibleTypes: Set<string>;
|
||||
abstractTypes: Map<string, string[]>; // abstract type -> concrete implementations
|
||||
allTypesToGenerate: Set<string>; // all types that need write methods
|
||||
typeProperties: Map<string, PropertyInfo[]>; // type -> all properties (including inherited)
|
||||
classMap: Map<string, ClassInfo>;
|
||||
accessibleTypes: Set<string>;
|
||||
abstractTypes: Map<string, string[]>; // abstract type -> concrete implementations
|
||||
allTypesToGenerate: Set<string>; // all types that need write methods
|
||||
typeProperties: Map<string, PropertyInfo[]>; // type -> all properties (including inherited)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user