mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-05 23:05:01 +08:00
[tests] Fix up output paths, lsp-cli invocation
This commit is contained in:
parent
0c74907da2
commit
4d45abbcf3
@ -1,21 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
pushd "$SCRIPT_DIR" > /dev/null
|
||||
|
||||
echo "Analyzing Java API..."
|
||||
npx tsx src/analyze-java-api.ts
|
||||
npx tsx src/analyze-java-api.ts || { echo "Failed to analyze Java API"; exit 1; }
|
||||
|
||||
echo "Generating serializer IR..."
|
||||
npx tsx src/generate-serializer-ir.ts
|
||||
npx tsx src/generate-serializer-ir.ts || { echo "Failed to generate IR"; exit 1; }
|
||||
|
||||
echo "Generating Java SkeletonSerializer..."
|
||||
npx tsx src/generate-java-serializer.ts
|
||||
npx tsx src/generate-java-serializer.ts || { echo "Failed to generate Java serializer"; exit 1; }
|
||||
|
||||
echo "Generating C++ SkeletonSerializer..."
|
||||
npx tsx src/generate-cpp-serializer.ts
|
||||
npx tsx src/generate-cpp-serializer.ts || { echo "Failed to generate C++ serializer"; exit 1; }
|
||||
|
||||
echo "Done."
|
||||
popd > /dev/null
|
||||
10
tests/package-lock.json
generated
10
tests/package-lock.json
generated
@ -6,7 +6,7 @@
|
||||
"": {
|
||||
"name": "spine-tests",
|
||||
"dependencies": {
|
||||
"@mariozechner/lsp-cli": "^0.1.1"
|
||||
"@mariozechner/lsp-cli": "^0.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.0.0",
|
||||
@ -456,9 +456,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mariozechner/lsp-cli": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@mariozechner/lsp-cli/-/lsp-cli-0.1.1.tgz",
|
||||
"integrity": "sha512-/5HF/PoYhQKFMhXLQiH1ZHTBJfs7rB8xcXa4YXSq6aTR5G6tWOrE6fwFbK7pwtkry6ZFeCTE2HI4BRWv5La9Qg==",
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@mariozechner/lsp-cli/-/lsp-cli-0.1.3.tgz",
|
||||
"integrity": "sha512-5kyYiI4k7bf48ineGLdHluHx9ZjYLIEknsgi3vpxBjUCf6y6pDmXsqDezlvZsWkittz9PMUJzCJD9cze6/d/Ug==",
|
||||
"dependencies": {
|
||||
"chalk": "^5.4.1",
|
||||
"commander": "^11.0.0",
|
||||
@ -468,7 +468,7 @@
|
||||
"vscode-languageserver-protocol": "^3.17.0"
|
||||
},
|
||||
"bin": {
|
||||
"lsp-cli": "dist/index.js"
|
||||
"lsp-cli": "dist/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
|
||||
@ -10,6 +10,6 @@
|
||||
"tsx": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mariozechner/lsp-cli": "^0.1.1"
|
||||
"@mariozechner/lsp-cli": "^0.1.3"
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,12 +4,13 @@ import { execSync } from 'child_process';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import type { Symbol, LspOutput, ClassInfo, PropertyInfo, AnalysisResult } from './types';
|
||||
import type { ClassInfo, PropertyInfo, AnalysisResult } from './types';
|
||||
import type { LspCliResult, SymbolInfo } from '@mariozechner/lsp-cli';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
function ensureOutputDir(): string {
|
||||
const outputDir = path.resolve(__dirname, '../../output');
|
||||
const outputDir = path.resolve(__dirname, '../output');
|
||||
if (!fs.existsSync(outputDir)) {
|
||||
fs.mkdirSync(outputDir, { recursive: true });
|
||||
}
|
||||
@ -18,7 +19,7 @@ function ensureOutputDir(): string {
|
||||
|
||||
function generateLspData(outputDir: string): string {
|
||||
const outputFile = path.join(outputDir, 'spine-libgdx-symbols.json');
|
||||
const projectDir = '/Users/badlogic/workspaces/spine-runtimes/spine-libgdx';
|
||||
const projectDir = path.resolve(__dirname, '../../spine-libgdx');
|
||||
const srcDir = path.join(projectDir, 'spine-libgdx/src');
|
||||
|
||||
// Check if we need to regenerate
|
||||
@ -42,9 +43,8 @@ function generateLspData(outputDir: string): string {
|
||||
if (needsRegeneration) {
|
||||
console.error('Generating LSP data for spine-libgdx...');
|
||||
try {
|
||||
execSync(`npx lsp-cli "${projectDir}" java "${outputFile}"`, {
|
||||
encoding: 'utf8',
|
||||
stdio: ['ignore', 'ignore', 'pipe'] // Hide stdout but show stderr
|
||||
execSync(`node ${path.join(__dirname, '../node_modules/@mariozechner/lsp-cli/dist/index.js')} "${projectDir}" java "${outputFile}"`, {
|
||||
stdio: 'inherit' // Show all output
|
||||
});
|
||||
console.error('LSP data generated successfully');
|
||||
} catch (error: any) {
|
||||
@ -58,11 +58,11 @@ function generateLspData(outputDir: string): string {
|
||||
return outputFile;
|
||||
}
|
||||
|
||||
function analyzeClasses(symbols: Symbol[]): Map<string, ClassInfo> {
|
||||
function analyzeClasses(symbols: SymbolInfo[]): Map<string, ClassInfo> {
|
||||
const classMap = new Map<string, ClassInfo>();
|
||||
const srcPath = '/Users/badlogic/workspaces/spine-runtimes/spine-libgdx/spine-libgdx/src/';
|
||||
const srcPath = path.resolve(__dirname, '../../spine-libgdx/spine-libgdx/src/');
|
||||
|
||||
function processSymbol(symbol: Symbol, parentName?: string) {
|
||||
function processSymbol(symbol: SymbolInfo, parentName?: string) {
|
||||
if (symbol.kind !== 'class' && symbol.kind !== 'enum' && symbol.kind !== 'interface') return;
|
||||
|
||||
// Filter: only process symbols in spine-libgdx/src, excluding SkeletonSerializer
|
||||
@ -256,6 +256,9 @@ function findAccessibleTypes(
|
||||
const typeMatches = returnType.match(/\b([A-Z]\w+(?:\.[A-Z]\w+)*)\b/g);
|
||||
if (typeMatches) {
|
||||
for (const match of typeMatches) {
|
||||
if (classMap.has(match) && !visited.has(match)) {
|
||||
toVisit.push(match);
|
||||
}
|
||||
// For non-qualified names, also try as inner class
|
||||
if (!match.includes('.')) {
|
||||
// Try as inner class of current type and its parents
|
||||
@ -279,7 +282,7 @@ function findAccessibleTypes(
|
||||
}
|
||||
|
||||
function loadExclusions(): { types: Set<string>, methods: Map<string, Set<string>>, fields: Map<string, Set<string>> } {
|
||||
const exclusionsPath = path.resolve(__dirname, 'java-exclusions.txt');
|
||||
const exclusionsPath = path.resolve(__dirname, '../java-exclusions.txt');
|
||||
const types = new Set<string>();
|
||||
const methods = new Map<string, Set<string>>();
|
||||
const fields = new Map<string, Set<string>>();
|
||||
@ -688,7 +691,7 @@ async function main() {
|
||||
|
||||
// Read and parse the JSON
|
||||
const jsonContent = fs.readFileSync(jsonFile, 'utf8');
|
||||
const lspData: LspOutput = JSON.parse(jsonContent);
|
||||
const lspData: LspCliResult = JSON.parse(jsonContent);
|
||||
|
||||
console.error(`Analyzing ${lspData.symbols.length} symbols...`);
|
||||
|
||||
|
||||
@ -420,7 +420,7 @@ function generateCppFromIR(ir: SerializerIR): string {
|
||||
async function main() {
|
||||
try {
|
||||
// Read the IR file
|
||||
const irFile = path.resolve(__dirname, '../../output/serializer-ir.json');
|
||||
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);
|
||||
@ -434,7 +434,7 @@ async function main() {
|
||||
// Write the C++ file
|
||||
const cppFile = path.resolve(
|
||||
__dirname,
|
||||
'../../../spine-cpp/tests/SkeletonSerializer.h'
|
||||
'../../spine-cpp/tests/SkeletonSerializer.h'
|
||||
);
|
||||
|
||||
fs.mkdirSync(path.dirname(cppFile), { recursive: true });
|
||||
|
||||
@ -290,7 +290,7 @@ function generateJavaFromIR(ir: SerializerIR): string {
|
||||
async function main() {
|
||||
try {
|
||||
// Read the IR file
|
||||
const irFile = path.resolve(__dirname, '../../output/serializer-ir.json');
|
||||
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);
|
||||
@ -304,7 +304,7 @@ async function main() {
|
||||
// Write the Java file
|
||||
const javaFile = path.resolve(
|
||||
__dirname,
|
||||
'../../../spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/utils/SkeletonSerializer.java'
|
||||
'../../spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/utils/SkeletonSerializer.java'
|
||||
);
|
||||
|
||||
fs.mkdirSync(path.dirname(javaFile), { recursive: true });
|
||||
|
||||
@ -88,27 +88,27 @@ interface SerializedAnalysisResult {
|
||||
}
|
||||
|
||||
function loadExclusions(): { types: Set<string>, methods: Map<string, Set<string>>, fields: Map<string, Set<string>> } {
|
||||
const exclusionsPath = path.resolve(__dirname, 'java-exclusions.txt');
|
||||
const exclusionsPath = path.resolve(__dirname, '../java-exclusions.txt');
|
||||
const types = new Set<string>();
|
||||
const methods = new Map<string, Set<string>>();
|
||||
const fields = new Map<string, Set<string>>();
|
||||
|
||||
|
||||
if (!fs.existsSync(exclusionsPath)) {
|
||||
return { types, methods, fields };
|
||||
}
|
||||
|
||||
|
||||
const content = fs.readFileSync(exclusionsPath, 'utf-8');
|
||||
const lines = content.split('\n');
|
||||
|
||||
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed || trimmed.startsWith('#')) continue;
|
||||
|
||||
|
||||
const parts = trimmed.split(/\s+/);
|
||||
if (parts.length < 2) continue;
|
||||
|
||||
|
||||
const [type, className, property] = parts;
|
||||
|
||||
|
||||
switch (type) {
|
||||
case 'type':
|
||||
types.add(className);
|
||||
@ -131,7 +131,7 @@ function loadExclusions(): { types: Set<string>, methods: Map<string, Set<string
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return { types, methods, fields };
|
||||
}
|
||||
|
||||
@ -182,7 +182,7 @@ function analyzePropertyType(propType: string, classMap: Map<string, ClassInfo>)
|
||||
if (propType.startsWith('Array<')) {
|
||||
const innerType = propType.match(/Array<(.+?)>/)![1].trim();
|
||||
const elementKind = ['String', 'int', 'float', 'boolean', 'short', 'byte', 'double', 'long'].includes(innerType) ? "primitive" : "object";
|
||||
|
||||
|
||||
return {
|
||||
kind: "array",
|
||||
name,
|
||||
@ -257,14 +257,14 @@ function generateSerializerIR(analysisData: SerializedAnalysisResult): Serialize
|
||||
if (classInfo.isEnum && classInfo.enumValues) {
|
||||
const shortName = className.split('.').pop()!;
|
||||
const valueMap: { [javaValue: string]: string } = {};
|
||||
|
||||
|
||||
for (const javaValue of classInfo.enumValues) {
|
||||
// Convert Java enum value to C++ enum value
|
||||
// e.g. "setup" -> "MixBlend_Setup", "first" -> "MixBlend_First"
|
||||
const cppValue = `${shortName}_${javaValue.charAt(0).toUpperCase() + javaValue.slice(1)}`;
|
||||
valueMap[javaValue] = cppValue;
|
||||
}
|
||||
|
||||
|
||||
enumMappings[shortName] = valueMap;
|
||||
}
|
||||
}
|
||||
@ -356,7 +356,7 @@ function generateSerializerIR(analysisData: SerializedAnalysisResult): Serialize
|
||||
for (const typeName of Array.from(typesNeedingMethods).sort()) {
|
||||
const classInfo = classMap.get(typeName);
|
||||
if (!classInfo) continue;
|
||||
|
||||
|
||||
// Skip enums - they are handled inline with .name() calls
|
||||
if (classInfo.isEnum) continue;
|
||||
|
||||
@ -376,12 +376,12 @@ function generateSerializerIR(analysisData: SerializedAnalysisResult): Serialize
|
||||
if (classInfo.isAbstract || classInfo.isInterface) {
|
||||
// Handle abstract types with instanceof chain
|
||||
const implementations = classInfo.concreteImplementations || [];
|
||||
|
||||
|
||||
// Filter out excluded types from implementations
|
||||
const filteredImplementations = implementations.filter(impl => {
|
||||
return !exclusions.types.has(impl);
|
||||
});
|
||||
|
||||
|
||||
if (filteredImplementations.length > 0) {
|
||||
writeMethod.subtypeChecks = filteredImplementations.map(impl => {
|
||||
const implShortName = impl.split('.').pop()!;
|
||||
@ -399,7 +399,7 @@ function generateSerializerIR(analysisData: SerializedAnalysisResult): Serialize
|
||||
if (prop.excluded) {
|
||||
continue; // Skip excluded properties
|
||||
}
|
||||
|
||||
|
||||
const propName = prop.isGetter ?
|
||||
prop.name.replace('get', '').replace('()', '').charAt(0).toLowerCase() +
|
||||
prop.name.replace('get', '').replace('()', '').slice(1) :
|
||||
@ -474,7 +474,7 @@ function analyzePropertyWithDetails(prop: PropertyInfo, propName: string, getter
|
||||
if (propType.startsWith('Array<')) {
|
||||
const innerType = propType.match(/Array<(.+?)>/)![1].trim();
|
||||
const elementKind = ['String', 'int', 'float', 'boolean', 'short', 'byte', 'double', 'long'].includes(innerType) ? "primitive" : "object";
|
||||
|
||||
|
||||
return {
|
||||
kind: "array",
|
||||
name: propName,
|
||||
@ -539,7 +539,7 @@ function analyzePropertyWithDetails(prop: PropertyInfo, propName: string, getter
|
||||
async function main() {
|
||||
try {
|
||||
// Read analysis result
|
||||
const analysisFile = path.resolve(__dirname, '../../output/analysis-result.json');
|
||||
const analysisFile = path.resolve(__dirname, '../output/analysis-result.json');
|
||||
if (!fs.existsSync(analysisFile)) {
|
||||
console.error('Analysis result not found. Run analyze-java-api.ts first.');
|
||||
process.exit(1);
|
||||
@ -551,7 +551,7 @@ async function main() {
|
||||
const ir = generateSerializerIR(analysisData);
|
||||
|
||||
// Write the IR file
|
||||
const irFile = path.resolve(__dirname, '../../output/serializer-ir.json');
|
||||
const irFile = path.resolve(__dirname, '../output/serializer-ir.json');
|
||||
fs.mkdirSync(path.dirname(irFile), { recursive: true });
|
||||
fs.writeFileSync(irFile, JSON.stringify(ir, null, 2));
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Symbol, Supertype, LspOutput } from '@mariozechner/lsp-cli';
|
||||
import { Supertype } from '@mariozechner/lsp-cli';
|
||||
|
||||
// Shared types for the Spine serializer generator
|
||||
export interface ClassInfo {
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
- lsp-cli should export its types, so we can pull them in as a dependency instead of redefining them ourselves in types.ts
|
||||
- clean up logging in spine-c/codegen, use chalk to do colored warnings/errors and make logging look very nice and informative (no emojis)
|
||||
- spine-c/codegen type extractor should also report typedefs like typedef long long PropertyId; so primitive type to some name, and we need to handle that in the codegen
|
||||
- Generate language bindings in spine-c/codegen
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user