mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
158 lines
5.6 KiB
TypeScript
158 lines
5.6 KiB
TypeScript
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import { Type, toSnakeCase } from './types';
|
|
|
|
const LICENSE_HEADER = `/******************************************************************************
|
|
* Spine Runtimes License Agreement
|
|
* Last updated April 5, 2025. Replaces all prior versions.
|
|
*
|
|
* Copyright (c) 2013-2025, Esoteric Software LLC
|
|
*
|
|
* Integration of the Spine Runtimes into software or otherwise creating
|
|
* derivative works of the Spine Runtimes is permitted under the terms and
|
|
* conditions of Section 2 of the Spine Editor License Agreement:
|
|
* http://esotericsoftware.com/spine-editor-license
|
|
*
|
|
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
|
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
|
* "Products"), provided that each user of the Products must obtain their own
|
|
* Spine Editor license and redistribution of the Products in any form must
|
|
* include this license and copyright notice.
|
|
*
|
|
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
|
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*****************************************************************************/`;
|
|
|
|
export class FileWriter {
|
|
constructor(private outputDir: string) {
|
|
// Clean and recreate output directory
|
|
this.cleanOutputDirectory();
|
|
}
|
|
|
|
private cleanOutputDirectory(): void {
|
|
// Remove existing generated directory if it exists
|
|
if (fs.existsSync(this.outputDir)) {
|
|
console.log(`Cleaning ${this.outputDir}...`);
|
|
fs.rmSync(this.outputDir, { recursive: true, force: true });
|
|
}
|
|
|
|
// Recreate the directory
|
|
fs.mkdirSync(this.outputDir, { recursive: true });
|
|
}
|
|
|
|
async writeType(typeName: string, headerContent: string[], sourceContent: string[]): Promise<void> {
|
|
const fileName = toSnakeCase(typeName);
|
|
|
|
// Write header file
|
|
const headerPath = path.join(this.outputDir, `${fileName}.h`);
|
|
const headerGuard = `SPINE_C_${typeName.toUpperCase()}_H`;
|
|
|
|
const headerLines = [
|
|
LICENSE_HEADER,
|
|
'',
|
|
`#ifndef ${headerGuard}`,
|
|
`#define ${headerGuard}`,
|
|
'',
|
|
'#ifdef __cplusplus',
|
|
'extern "C" {',
|
|
'#endif',
|
|
'',
|
|
...headerContent,
|
|
'',
|
|
'#ifdef __cplusplus',
|
|
'}',
|
|
'#endif',
|
|
'',
|
|
`#endif // ${headerGuard}`
|
|
];
|
|
|
|
fs.writeFileSync(headerPath, headerLines.join('\n'));
|
|
|
|
// Write source file (as .cpp since it contains C++ code)
|
|
const sourcePath = path.join(this.outputDir, `${fileName}.cpp`);
|
|
const sourceLines = [
|
|
LICENSE_HEADER,
|
|
'',
|
|
...sourceContent
|
|
];
|
|
|
|
fs.writeFileSync(sourcePath, sourceLines.join('\n'));
|
|
}
|
|
|
|
async writeEnum(enumName: string, content: string[]): Promise<void> {
|
|
const fileName = toSnakeCase(enumName);
|
|
const headerPath = path.join(this.outputDir, `${fileName}.h`);
|
|
const headerGuard = `SPINE_C_${enumName.toUpperCase()}_H`;
|
|
|
|
const headerLines = [
|
|
LICENSE_HEADER,
|
|
'',
|
|
`#ifndef ${headerGuard}`,
|
|
`#define ${headerGuard}`,
|
|
'',
|
|
'#include "../../custom.h"',
|
|
'',
|
|
'#ifdef __cplusplus',
|
|
'extern "C" {',
|
|
'#endif',
|
|
'',
|
|
...content,
|
|
'',
|
|
'#ifdef __cplusplus',
|
|
'}',
|
|
'#endif',
|
|
'',
|
|
`#endif // ${headerGuard}`
|
|
];
|
|
|
|
fs.writeFileSync(headerPath, headerLines.join('\n'));
|
|
}
|
|
|
|
async writeMainHeader(classes: Type[], enums: Type[]): Promise<void> {
|
|
const mainHeaderPath = path.join(this.outputDir, '..', '..', 'include', 'spine-c.h');
|
|
|
|
// Ensure include directory exists
|
|
const includeDir = path.dirname(mainHeaderPath);
|
|
if (!fs.existsSync(includeDir)) {
|
|
fs.mkdirSync(includeDir, { recursive: true });
|
|
}
|
|
|
|
const lines = [
|
|
LICENSE_HEADER,
|
|
'',
|
|
'#ifndef SPINE_C_H',
|
|
'#define SPINE_C_H',
|
|
'',
|
|
'// Custom types and functions',
|
|
'#include "../src/custom.h"',
|
|
'',
|
|
'// Generated enum types'
|
|
];
|
|
|
|
// Add enum includes
|
|
for (const enumType of enums) {
|
|
lines.push(`#include "../src/generated/${toSnakeCase(enumType.name)}.h"`);
|
|
}
|
|
|
|
lines.push('');
|
|
lines.push('// Generated class types');
|
|
|
|
// Add class includes
|
|
for (const classType of classes) {
|
|
lines.push(`#include "../src/generated/${toSnakeCase(classType.name)}.h"`);
|
|
}
|
|
|
|
lines.push('');
|
|
lines.push('#endif // SPINE_C_H');
|
|
|
|
fs.writeFileSync(mainHeaderPath, lines.join('\n'));
|
|
}
|
|
} |