Initial commit: funplay cocos mcp
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { execFile } = require('child_process');
|
||||
|
||||
function exists(filePath) {
|
||||
try {
|
||||
return fs.existsSync(filePath);
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function findTypescriptBinary(projectPath) {
|
||||
const tscName = process.platform === 'win32' ? 'tsc.cmd' : 'tsc';
|
||||
const possibleRoots = [
|
||||
global.Editor && Editor.App && Editor.App.path,
|
||||
process.resourcesPath,
|
||||
global.Editor && Editor.App && Editor.App.path ? path.dirname(Editor.App.path) : '',
|
||||
global.Editor && Editor.App && Editor.App.path ? path.resolve(Editor.App.path, '..') : '',
|
||||
].filter(Boolean);
|
||||
|
||||
const editorBundledCandidates = [];
|
||||
for (const root of possibleRoots) {
|
||||
editorBundledCandidates.push(
|
||||
path.join(root, 'resources', '3d', 'engine', 'node_modules', '.bin', tscName),
|
||||
path.join(root, 'resources', '3d', 'engine', 'node_modules', 'typescript', 'bin', 'tsc'),
|
||||
path.join(root, 'resources', '3d', 'engine', 'node_modules', '@cocos', 'typescript', 'bin', 'tsc'),
|
||||
path.join(root, 'app.asar.unpacked', 'node_modules', 'typescript', 'bin', 'tsc'),
|
||||
path.join(root, 'Contents', 'Resources', 'resources', '3d', 'engine', 'node_modules', '.bin', tscName),
|
||||
path.join(root, 'Contents', 'Resources', 'resources', '3d', 'engine', 'node_modules', 'typescript', 'bin', 'tsc'),
|
||||
path.join(root, 'Contents', 'Resources', 'resources', '3d', 'engine', 'node_modules', '@cocos', 'typescript', 'bin', 'tsc')
|
||||
);
|
||||
}
|
||||
|
||||
const candidates = [
|
||||
path.join(projectPath, 'node_modules', '.bin', tscName),
|
||||
path.join(projectPath, 'node_modules', 'typescript', 'bin', 'tsc'),
|
||||
...editorBundledCandidates,
|
||||
process.platform === 'win32' ? 'npx.cmd' : 'npx',
|
||||
];
|
||||
|
||||
for (const candidate of candidates) {
|
||||
if (candidate.includes(path.sep) && exists(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
if (!candidate.includes(path.sep)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
||||
}
|
||||
|
||||
function findTsConfig(projectPath, explicitPath) {
|
||||
if (explicitPath) {
|
||||
return path.isAbsolute(explicitPath) ? explicitPath : path.join(projectPath, explicitPath);
|
||||
}
|
||||
|
||||
const candidates = [
|
||||
path.join(projectPath, 'tsconfig.json'),
|
||||
path.join(projectPath, 'temp', 'tsconfig.cocos.json'),
|
||||
];
|
||||
|
||||
return candidates.find((candidate) => exists(candidate)) || '';
|
||||
}
|
||||
|
||||
function runExec(file, args, cwd) {
|
||||
return new Promise((resolve) => {
|
||||
execFile(file, args, { cwd, maxBuffer: 8 * 1024 * 1024 }, (error, stdout, stderr) => {
|
||||
resolve({
|
||||
code: error && typeof error.code === 'number' ? error.code : 0,
|
||||
stdout: stdout || '',
|
||||
stderr: stderr || '',
|
||||
error: error ? error.message : '',
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function parseTscOutput(output) {
|
||||
const lines = String(output || '')
|
||||
.split(/\r?\n/)
|
||||
.map((line) => line.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
const diagnostics = [];
|
||||
const regex = /^(.*)\((\d+),(\d+)\):\s+error\s+(TS\d+):\s+(.*)$/i;
|
||||
for (const line of lines) {
|
||||
const match = regex.exec(line);
|
||||
if (!match) {
|
||||
continue;
|
||||
}
|
||||
|
||||
diagnostics.push({
|
||||
file: match[1],
|
||||
line: Number(match[2]),
|
||||
column: Number(match[3]),
|
||||
code: match[4],
|
||||
message: match[5],
|
||||
});
|
||||
}
|
||||
|
||||
return diagnostics;
|
||||
}
|
||||
|
||||
async function runScriptDiagnostics(projectPath, options = {}) {
|
||||
const tsconfigPath = findTsConfig(projectPath, options.tsconfigPath);
|
||||
if (!tsconfigPath || !exists(tsconfigPath)) {
|
||||
return {
|
||||
ok: false,
|
||||
tool: 'typescript',
|
||||
summary: 'No tsconfig.json was found in the Cocos project.',
|
||||
diagnostics: [],
|
||||
stdout: '',
|
||||
stderr: '',
|
||||
};
|
||||
}
|
||||
|
||||
const binary = findTypescriptBinary(projectPath);
|
||||
const args = binary.endsWith('npx') || binary.endsWith('npx.cmd')
|
||||
? ['tsc', '--noEmit', '-p', tsconfigPath, '--pretty', 'false']
|
||||
: ['--noEmit', '-p', tsconfigPath, '--pretty', 'false'];
|
||||
|
||||
const result = await runExec(binary, args, projectPath);
|
||||
const mergedOutput = [result.stdout, result.stderr, result.error].filter(Boolean).join('\n').trim();
|
||||
const diagnostics = parseTscOutput(mergedOutput);
|
||||
const ok = result.code === 0 && diagnostics.length === 0;
|
||||
|
||||
return {
|
||||
ok,
|
||||
tool: 'typescript',
|
||||
binary,
|
||||
tsconfigPath,
|
||||
exitCode: result.code,
|
||||
summary: ok
|
||||
? 'TypeScript diagnostics completed successfully with no errors.'
|
||||
: diagnostics.length
|
||||
? `Found ${diagnostics.length} TypeScript error(s).`
|
||||
: mergedOutput || 'TypeScript diagnostics reported a non-zero exit code.',
|
||||
diagnostics,
|
||||
stdout: result.stdout,
|
||||
stderr: result.stderr,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
runScriptDiagnostics,
|
||||
};
|
||||
Reference in New Issue
Block a user