[tests] Fix up output paths, lsp-cli invocation

This commit is contained in:
Mario Zechner 2025-07-15 16:22:45 +02:00
parent 0c74907da2
commit 4d45abbcf3
9 changed files with 48 additions and 45 deletions

View File

@ -1,21 +1,22 @@
#!/bin/bash #!/bin/bash
set -e set -e
set -o pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
pushd "$SCRIPT_DIR" > /dev/null pushd "$SCRIPT_DIR" > /dev/null
echo "Analyzing Java API..." 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..." 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..." 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..." 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." echo "Done."
popd > /dev/null popd > /dev/null

View File

@ -6,7 +6,7 @@
"": { "": {
"name": "spine-tests", "name": "spine-tests",
"dependencies": { "dependencies": {
"@mariozechner/lsp-cli": "^0.1.1" "@mariozechner/lsp-cli": "^0.1.3"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20.0.0", "@types/node": "^20.0.0",
@ -456,9 +456,9 @@
} }
}, },
"node_modules/@mariozechner/lsp-cli": { "node_modules/@mariozechner/lsp-cli": {
"version": "0.1.1", "version": "0.1.3",
"resolved": "https://registry.npmjs.org/@mariozechner/lsp-cli/-/lsp-cli-0.1.1.tgz", "resolved": "https://registry.npmjs.org/@mariozechner/lsp-cli/-/lsp-cli-0.1.3.tgz",
"integrity": "sha512-/5HF/PoYhQKFMhXLQiH1ZHTBJfs7rB8xcXa4YXSq6aTR5G6tWOrE6fwFbK7pwtkry6ZFeCTE2HI4BRWv5La9Qg==", "integrity": "sha512-5kyYiI4k7bf48ineGLdHluHx9ZjYLIEknsgi3vpxBjUCf6y6pDmXsqDezlvZsWkittz9PMUJzCJD9cze6/d/Ug==",
"dependencies": { "dependencies": {
"chalk": "^5.4.1", "chalk": "^5.4.1",
"commander": "^11.0.0", "commander": "^11.0.0",
@ -468,7 +468,7 @@
"vscode-languageserver-protocol": "^3.17.0" "vscode-languageserver-protocol": "^3.17.0"
}, },
"bin": { "bin": {
"lsp-cli": "dist/index.js" "lsp-cli": "dist/cli.js"
} }
}, },
"node_modules/@types/node": { "node_modules/@types/node": {

View File

@ -10,6 +10,6 @@
"tsx": "^4.0.0" "tsx": "^4.0.0"
}, },
"dependencies": { "dependencies": {
"@mariozechner/lsp-cli": "^0.1.1" "@mariozechner/lsp-cli": "^0.1.3"
} }
} }

View File

@ -4,12 +4,13 @@ import { execSync } from 'child_process';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import { fileURLToPath } from 'url'; 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)); const __dirname = path.dirname(fileURLToPath(import.meta.url));
function ensureOutputDir(): string { function ensureOutputDir(): string {
const outputDir = path.resolve(__dirname, '../../output'); const outputDir = path.resolve(__dirname, '../output');
if (!fs.existsSync(outputDir)) { if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true }); fs.mkdirSync(outputDir, { recursive: true });
} }
@ -18,7 +19,7 @@ function ensureOutputDir(): string {
function generateLspData(outputDir: string): string { function generateLspData(outputDir: string): string {
const outputFile = path.join(outputDir, 'spine-libgdx-symbols.json'); 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'); const srcDir = path.join(projectDir, 'spine-libgdx/src');
// Check if we need to regenerate // Check if we need to regenerate
@ -42,9 +43,8 @@ function generateLspData(outputDir: string): string {
if (needsRegeneration) { if (needsRegeneration) {
console.error('Generating LSP data for spine-libgdx...'); console.error('Generating LSP data for spine-libgdx...');
try { try {
execSync(`npx lsp-cli "${projectDir}" java "${outputFile}"`, { execSync(`node ${path.join(__dirname, '../node_modules/@mariozechner/lsp-cli/dist/index.js')} "${projectDir}" java "${outputFile}"`, {
encoding: 'utf8', stdio: 'inherit' // Show all output
stdio: ['ignore', 'ignore', 'pipe'] // Hide stdout but show stderr
}); });
console.error('LSP data generated successfully'); console.error('LSP data generated successfully');
} catch (error: any) { } catch (error: any) {
@ -58,11 +58,11 @@ function generateLspData(outputDir: string): string {
return outputFile; return outputFile;
} }
function analyzeClasses(symbols: Symbol[]): Map<string, ClassInfo> { function analyzeClasses(symbols: SymbolInfo[]): Map<string, ClassInfo> {
const classMap = new 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; if (symbol.kind !== 'class' && symbol.kind !== 'enum' && symbol.kind !== 'interface') return;
// Filter: only process symbols in spine-libgdx/src, excluding SkeletonSerializer // 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); const typeMatches = returnType.match(/\b([A-Z]\w+(?:\.[A-Z]\w+)*)\b/g);
if (typeMatches) { if (typeMatches) {
for (const match of 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 // For non-qualified names, also try as inner class
if (!match.includes('.')) { if (!match.includes('.')) {
// Try as inner class of current type and its parents // 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>> } { 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 types = new Set<string>();
const methods = new Map<string, Set<string>>(); const methods = new Map<string, Set<string>>();
const fields = new Map<string, Set<string>>(); const fields = new Map<string, Set<string>>();
@ -688,7 +691,7 @@ async function main() {
// Read and parse the JSON // Read and parse the JSON
const jsonContent = fs.readFileSync(jsonFile, 'utf8'); 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...`); console.error(`Analyzing ${lspData.symbols.length} symbols...`);

View File

@ -420,7 +420,7 @@ function generateCppFromIR(ir: SerializerIR): string {
async function main() { async function main() {
try { try {
// Read the IR file // 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)) { if (!fs.existsSync(irFile)) {
console.error('Serializer IR not found. Run generate-serializer-ir.ts first.'); console.error('Serializer IR not found. Run generate-serializer-ir.ts first.');
process.exit(1); process.exit(1);
@ -434,7 +434,7 @@ async function main() {
// Write the C++ file // Write the C++ file
const cppFile = path.resolve( const cppFile = path.resolve(
__dirname, __dirname,
'../../../spine-cpp/tests/SkeletonSerializer.h' '../../spine-cpp/tests/SkeletonSerializer.h'
); );
fs.mkdirSync(path.dirname(cppFile), { recursive: true }); fs.mkdirSync(path.dirname(cppFile), { recursive: true });

View File

@ -290,7 +290,7 @@ function generateJavaFromIR(ir: SerializerIR): string {
async function main() { async function main() {
try { try {
// Read the IR file // 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)) { if (!fs.existsSync(irFile)) {
console.error('Serializer IR not found. Run generate-serializer-ir.ts first.'); console.error('Serializer IR not found. Run generate-serializer-ir.ts first.');
process.exit(1); process.exit(1);
@ -304,7 +304,7 @@ async function main() {
// Write the Java file // Write the Java file
const javaFile = path.resolve( const javaFile = path.resolve(
__dirname, __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 }); fs.mkdirSync(path.dirname(javaFile), { recursive: true });

View File

@ -88,7 +88,7 @@ interface SerializedAnalysisResult {
} }
function loadExclusions(): { types: Set<string>, methods: Map<string, Set<string>>, fields: Map<string, Set<string>> } { 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 types = new Set<string>();
const methods = new Map<string, Set<string>>(); const methods = new Map<string, Set<string>>();
const fields = new Map<string, Set<string>>(); const fields = new Map<string, Set<string>>();
@ -539,7 +539,7 @@ function analyzePropertyWithDetails(prop: PropertyInfo, propName: string, getter
async function main() { async function main() {
try { try {
// Read analysis result // 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)) { if (!fs.existsSync(analysisFile)) {
console.error('Analysis result not found. Run analyze-java-api.ts first.'); console.error('Analysis result not found. Run analyze-java-api.ts first.');
process.exit(1); process.exit(1);
@ -551,7 +551,7 @@ async function main() {
const ir = generateSerializerIR(analysisData); const ir = generateSerializerIR(analysisData);
// Write the IR file // 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.mkdirSync(path.dirname(irFile), { recursive: true });
fs.writeFileSync(irFile, JSON.stringify(ir, null, 2)); fs.writeFileSync(irFile, JSON.stringify(ir, null, 2));

View File

@ -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 // Shared types for the Spine serializer generator
export interface ClassInfo { export interface ClassInfo {

View File

@ -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) - 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 - 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 - Generate language bindings in spine-c/codegen