fix: validate texture asset names server-side

This commit is contained in:
Tom Boullay
2026-04-28 00:17:28 +02:00
parent 2679d29ab4
commit 9dc0232e4a
5 changed files with 72 additions and 48 deletions
+2 -40
View File
@@ -1,5 +1,5 @@
import { ASSET_EXTENSIONS, TEXTURE_EXTENSIONS } from '@/lib/constants'
import { formatAssetFamilies, getAssetFamily, getForbiddenAssetFamilyAlias } from '@/lib/asset-naming'
import { getTextureNamingError } from '@/lib/asset-naming'
import { getErrorMessage, isRecord } from '@/lib/guards'
import type { TextureFile } from '@/lib/client-types'
@@ -37,44 +37,6 @@ function getFileExtension(filename: string) {
return filename.slice(filename.lastIndexOf('.')).toLowerCase()
}
function getFileStem(filename: string) {
return filename.replace(/\.[^.]+$/, '')
}
function getTextureNamingError(file: File) {
const stem = getFileStem(file.name)
const [prefix, ...targetParts] = stem.split('_')
const family = getAssetFamily(prefix)
const extension = file.name.split('.').pop()
if (family && targetParts.every(Boolean)) return null
const aliasSuggestion = getForbiddenAssetFamilyAlias(prefix)
if (aliasSuggestion && targetParts.every(Boolean)) {
const target = targetParts.join('_')
return `Convention invalide : ${file.name}. Utilisez ${aliasSuggestion}_${target}.${extension} pour cibler "${target}", ou ${aliasSuggestion}.${extension} pour tout le modele.`
}
const reversedParts = stem.split('_')
const reversedFamily = reversedParts.length > 1 ? getAssetFamily(reversedParts[reversedParts.length - 1]) : undefined
const reversedAliasSuggestion = reversedParts.length > 1
? getForbiddenAssetFamilyAlias(reversedParts[reversedParts.length - 1])
: undefined
if (reversedFamily) {
const target = reversedParts.slice(0, -1).join('_')
return `Convention invalide : ${file.name}. Utilisez ${reversedFamily}_${target}.${extension} pour cibler "${target}", ou ${reversedFamily}.${extension} pour tout le modele.`
}
if (reversedAliasSuggestion) {
const target = reversedParts.slice(0, -1).join('_')
return `Convention invalide : ${file.name}. Utilisez ${reversedAliasSuggestion}_${target}.${extension} pour cibler "${target}", ou ${reversedAliasSuggestion}.${extension} pour tout le modele.`
}
return `Asset inconnu : ${file.name}. Familles autorisees : ${formatAssetFamilies()}. Utilisez asset.png pour tout le modele ou asset_objet.png pour cibler un objet.`
}
async function getGltfWarnings(model: File, supportFiles: File[]) {
const warnings: string[] = []
let parsed: unknown
@@ -132,7 +94,7 @@ export async function validateFolder(files: File[]): Promise<ValidationResult> {
const textureNamingErrors = supportFiles
.filter((file) => TEXTURE_EXTENSIONS.has(getFileExtension(file.name)))
.map(getTextureNamingError)
.map((file) => getTextureNamingError(file.name))
.filter((error): error is string => Boolean(error))
errors.push(...textureNamingErrors)