Fix storage root fallback for references
This commit is contained in:
@@ -8,9 +8,9 @@
|
|||||||
},
|
},
|
||||||
"Hero": {
|
"Hero": {
|
||||||
"Title": "Kosmos Storage Audit",
|
"Title": "Kosmos Storage Audit",
|
||||||
"Intro1": "Prüft Medienreferenzen und markiert primär benutzerrelevante Risiken in den Foundry-Roots {dataRoot} und {publicRoot}.",
|
"Intro1": "Prüft lokale Medienpfade aus Weltdokumenten, Paket-Packs und Manifesten gegen {dataRoot} und {publicRoot} und meldet nur broken-reference, non-package-to-package-reference und orphan-file.",
|
||||||
"Intro2": "Orphans werden bewusst nicht global für den gesamten {dataRoot}-Root behauptet, sondern nur in klar weltlokalen oder explizit riskanten Bereichen.",
|
"Intro2": "Nicht gemeldet werden reguläre Weltverweise auf Modul- oder Systemassets, wenn das Ziel im Owner-Paket selbst sichtbar referenziert ist; Wildcards gelten als gültig, sobald mindestens eine Datei passt.",
|
||||||
"Intro3": "Weltverweise auf Modul- oder Systemassets gelten nicht pauschal als Problem. Relevant sind vor allem Ziele, die im Owner-Paket selbst nicht sichtbar referenziert werden."
|
"Intro3": "orphan-file wird nur in weltlokalen oder explizit riskanten Bereichen gebildet, nie global für den gesamten {dataRoot}-Root; ChatMessages und andere flüchtige Quellen werden nicht geprüft."
|
||||||
},
|
},
|
||||||
"Action": {
|
"Action": {
|
||||||
"Run": "Analyse starten",
|
"Run": "Analyse starten",
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
},
|
},
|
||||||
"Hero": {
|
"Hero": {
|
||||||
"Title": "Kosmos Storage Audit",
|
"Title": "Kosmos Storage Audit",
|
||||||
"Intro1": "Audits media references and highlights primarily user-relevant risks in the Foundry roots {dataRoot} and {publicRoot}.",
|
"Intro1": "Checks local media paths from world documents, package packs, and manifests against {dataRoot} and {publicRoot}, and only reports broken-reference, non-package-to-package-reference, and orphan-file.",
|
||||||
"Intro2": "Orphans are intentionally not claimed globally for the entire {dataRoot} root, but only in clearly world-local or explicitly risky areas.",
|
"Intro2": "Regular world references to module or system assets are not reported if the target is visibly referenced by its owning package; wildcards are treated as valid as soon as at least one file matches.",
|
||||||
"Intro3": "World references to module or system assets are not treated as a problem by default. The main focus is on targets that are not visibly referenced by their owning package."
|
"Intro3": "orphan-file is only produced for world-local or explicitly risky areas, never globally for the entire {dataRoot} root; ChatMessages and other transient sources are excluded."
|
||||||
},
|
},
|
||||||
"Action": {
|
"Action": {
|
||||||
"Run": "Start Analysis",
|
"Run": "Start Analysis",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"id": "kosmos-storage-audit",
|
"id": "kosmos-storage-audit",
|
||||||
"title": "Kosmos Storage Audit",
|
"title": "Kosmos Storage Audit",
|
||||||
"description": "Analyzes media references and risky storage locations across Foundry data and public roots.",
|
"description": "Analyzes media references and risky storage locations across Foundry data and public roots.",
|
||||||
"version": "0.0.18",
|
"version": "0.0.19",
|
||||||
"compatibility": {
|
"compatibility": {
|
||||||
"minimum": "13",
|
"minimum": "13",
|
||||||
"verified": "13"
|
"verified": "13"
|
||||||
|
|||||||
@@ -39,11 +39,12 @@ export function buildFindings({ files, references, i18n }={}) {
|
|||||||
path: file.path,
|
path: file.path,
|
||||||
locator: createCanonicalLocator(file.storage, file.path)
|
locator: createCanonicalLocator(file.storage, file.path)
|
||||||
}));
|
}));
|
||||||
|
const resolvedReferences = references.map(reference => resolveReferenceTarget(reference, fileByLocator, fileLocators));
|
||||||
const refsByLocator = new Map();
|
const refsByLocator = new Map();
|
||||||
const wildcardReferences = [];
|
const wildcardReferences = [];
|
||||||
const findings = [];
|
const findings = [];
|
||||||
|
|
||||||
for (const reference of references) {
|
for (const reference of resolvedReferences) {
|
||||||
const normalized = reference.normalized;
|
const normalized = reference.normalized;
|
||||||
if (!normalized) continue;
|
if (!normalized) continue;
|
||||||
if (normalized.targetKind === "wildcard") {
|
if (normalized.targetKind === "wildcard") {
|
||||||
@@ -56,7 +57,7 @@ export function buildFindings({ files, references, i18n }={}) {
|
|||||||
refsByLocator.set(normalizedLocator, bucket);
|
refsByLocator.set(normalizedLocator, bucket);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const reference of references) {
|
for (const reference of resolvedReferences) {
|
||||||
const normalized = reference.normalized;
|
const normalized = reference.normalized;
|
||||||
if (!normalized) continue;
|
if (!normalized) continue;
|
||||||
const normalizedLocator = createCanonicalLocator(normalized.storage, normalized.path);
|
const normalizedLocator = createCanonicalLocator(normalized.storage, normalized.path);
|
||||||
@@ -117,7 +118,7 @@ export function buildFindings({ files, references, i18n }={}) {
|
|||||||
if (detectMediaKind(file.path) === "other") continue;
|
if (detectMediaKind(file.path) === "other") continue;
|
||||||
const refs = matchingReferencesForFile(file, refsByLocator, wildcardReferences);
|
const refs = matchingReferencesForFile(file, refsByLocator, wildcardReferences);
|
||||||
if (refs.length) continue;
|
if (refs.length) continue;
|
||||||
if (!shouldReportOrphan(file, references)) continue;
|
if (!shouldReportOrphan(file, resolvedReferences)) continue;
|
||||||
|
|
||||||
const severity = (file.riskClass === "package-module") || (file.riskClass === "package-system") || (file.riskClass === "release-public")
|
const severity = (file.riskClass === "package-module") || (file.riskClass === "package-system") || (file.riskClass === "release-public")
|
||||||
? "warning"
|
? "warning"
|
||||||
@@ -139,6 +140,41 @@ export function buildFindings({ files, references, i18n }={}) {
|
|||||||
return findings;
|
return findings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveReferenceTarget(reference, fileByLocator, fileLocators) {
|
||||||
|
const normalized = reference.normalized;
|
||||||
|
if (!normalized) return reference;
|
||||||
|
|
||||||
|
const currentLocator = createCanonicalLocator(normalized.storage, normalized.path);
|
||||||
|
if (fileByLocator.has(currentLocator)) return reference;
|
||||||
|
|
||||||
|
const alternateStorage = normalized.storage === "data"
|
||||||
|
? "public"
|
||||||
|
: normalized.storage === "public"
|
||||||
|
? "data"
|
||||||
|
: null;
|
||||||
|
if (!alternateStorage) return reference;
|
||||||
|
|
||||||
|
const alternateLocator = createCanonicalLocator(alternateStorage, normalized.path);
|
||||||
|
if (normalized.targetKind === "wildcard") {
|
||||||
|
const alternateTarget = { ...normalized, storage: alternateStorage, locator: alternateLocator };
|
||||||
|
if (!wildcardMatchesAny(alternateTarget, fileLocators)) return reference;
|
||||||
|
return {
|
||||||
|
...reference,
|
||||||
|
normalized: alternateTarget
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fileByLocator.has(alternateLocator)) return reference;
|
||||||
|
return {
|
||||||
|
...reference,
|
||||||
|
normalized: {
|
||||||
|
...normalized,
|
||||||
|
storage: alternateStorage,
|
||||||
|
locator: alternateLocator
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function isAnchoredInOwningPackage(file, references) {
|
function isAnchoredInOwningPackage(file, references) {
|
||||||
const ownerType = file.ownerHint.ownerType;
|
const ownerType = file.ownerHint.ownerType;
|
||||||
const ownerId = file.ownerHint.ownerId;
|
const ownerId = file.ownerHint.ownerId;
|
||||||
|
|||||||
30
tests/storage-root-resolution-test.mjs
Normal file
30
tests/storage-root-resolution-test.mjs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import assert from "node:assert/strict";
|
||||||
|
import { buildFindings, createFileRecord } from "../scripts/core/finding-engine.js";
|
||||||
|
import { createFileLocator } from "../scripts/core/path-utils.js";
|
||||||
|
|
||||||
|
const files = [
|
||||||
|
createFileRecord(createFileLocator("data", "canvas/background_paper_16x9_4k.webp"), 1234)
|
||||||
|
];
|
||||||
|
|
||||||
|
const references = [
|
||||||
|
{
|
||||||
|
sourceType: "world-document",
|
||||||
|
sourceScope: { ownerType: "world", ownerId: "demo-world", systemId: "demo-system", subtype: "scenes" },
|
||||||
|
sourceLabel: "Scene demo",
|
||||||
|
rawValue: "canvas/background_paper_16x9_4k.webp",
|
||||||
|
normalized: {
|
||||||
|
...createFileLocator("public", "canvas/background_paper_16x9_4k.webp"),
|
||||||
|
targetKind: "local-file"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const findings = buildFindings({ files, references });
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
findings.some(finding => finding.kind === "broken-reference" && finding.target.locator === "public:canvas/background_paper_16x9_4k.webp"),
|
||||||
|
false,
|
||||||
|
"references should be remapped to the existing storage root before reporting a broken target"
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log("storage-root-resolution-test: ok");
|
||||||
Reference in New Issue
Block a user