feat: implement JSON/Function file checking using SpyglassMC

This commit is contained in:
2025-09-11 14:48:14 +02:00
parent 48515b0fc0
commit 14f7b74d0f
4 changed files with 554 additions and 7 deletions

View File

@@ -1,3 +1,117 @@
export async function checkDatapack(rootDir: String, version: String): Promise<void> {
import * as core from '@spyglassmc/core'
import * as je from '@spyglassmc/java-edition'
import * as mcdoc from '@spyglassmc/mcdoc'
import { NodeJsExternals } from '@spyglassmc/core/lib/nodejs.js'
import path from "path"
import { glob } from "glob"
import fs from "fs"
export class CustomService extends core.Service {
rootDir: string
constructor(rootDir: string, version: string) {
rootDir = path.resolve(rootDir)
const fullRootDir = core.fileUtil.ensureEndingSlash("file://" + rootDir)
const config = {
env: {
gameVersion: version,
feature: {
codeActions: false,
colors: false,
completions: false,
documentHighlighting: false,
documentLinks: false,
foldingRanges: false,
formatting: false,
hover: false,
inlayHint: {
enabledNodes: []
},
semanticColoring: false,
selectionRanges: false,
signatures: false
}
}
}
super({
logger: console,
profilers: new core.ProfilerFactory(console, [
'cache#load',
'cache#save',
'project#init',
'project#ready',
]),
project: {
cacheRoot: 'file:///tmp/.cache/',
defaultConfig: core.ConfigService.merge(
core.VanillaConfig,
config
),
externals: NodeJsExternals,
initializers: [mcdoc.initialize, je.initialize],
projectRoots: [fullRootDir],
},
})
this.rootDir = rootDir
}
async shutdown() {
console.log("Shutting down")
await this.project.close()
}
private listFilesByExtension(extension: string) {
return glob(path.join(this.rootDir, `**/*.${extension}`))
}
private makeFileUrl(path: string) {
return "file://" + path
}
private getFileContent(path: string) {
return fs.readFileSync(path, {
encoding: "utf-8"
})
}
async checkFile(path: string, lang: string) {
const url = this.makeFileUrl(path)
this.project.onDidOpen(url, lang, 0, this.getFileContent(path))
const docAndNode = this.project.getClientManaged(url)
if (!docAndNode) {
console.error(`File ${path} is not loaded`)
return
}
const { node } = docAndNode
const errors = core.FileNode.getErrors(node)
if (errors.length !== 0) {
console.error(`${errors.length} error${errors.length > 1 ? "s" : ""} in ${path}`)
}
}
async checkAllFiles() {
console.log("Checking all files")
const jsonFiles = await this.listFilesByExtension("json")
const funcFiles = await this.listFilesByExtension("mcfunction")
console.log("Files to check")
console.log(`- JSON: ${jsonFiles.length}`)
console.log(`- Function: ${funcFiles.length}`)
for (const jsonFile of jsonFiles) {
this.checkFile(jsonFile, "json")
}
for (const funcFile of funcFiles) {
this.checkFile(funcFile, "mcfunction")
}
}
}
export async function checkDatapack(rootDir: string, version: string): Promise<void> {
console.log(`Checking datapack in directory ${rootDir} for Minecraft version ${version}`)
const service = new CustomService(rootDir, version)
await service.project.ready()
await service.checkAllFiles()
await service.shutdown()
}

View File

@@ -3,11 +3,8 @@ import { checkDatapack } from "./check_datapack.js"
async function run(): Promise<void> {
try {
const rootDir = core.getInput("dir")
const rootDir = core.getInput("rootDir")
let version = core.getInput("version")
if (version === "") {
version = "auto"
}
await checkDatapack(rootDir, version)
} catch (error) {