Mark references into missing module folders
This commit is contained in:
@@ -42,7 +42,8 @@
|
|||||||
},
|
},
|
||||||
"Notice": {
|
"Notice": {
|
||||||
"Title": "Hinweise",
|
"Title": "Hinweise",
|
||||||
"InactiveModuleReferences": "Die aktive Welt referenziert Dateien aus inaktiven Modulen. Diese Modulziele wurden nicht als unverankert gewertet: {modules}"
|
"InactiveModuleReferences": "Die aktive Welt referenziert Dateien aus inaktiven Modulen: {modules}",
|
||||||
|
"MissingModuleReferences": "Die aktive Welt referenziert Dateien aus Modulordnern, die von Foundry derzeit nicht als Module erkannt werden: {modules}"
|
||||||
},
|
},
|
||||||
"Summary": {
|
"Summary": {
|
||||||
"NoAnalysis": "Noch keine Analyse ausgeführt.",
|
"NoAnalysis": "Noch keine Analyse ausgeführt.",
|
||||||
|
|||||||
@@ -42,7 +42,8 @@
|
|||||||
},
|
},
|
||||||
"Notice": {
|
"Notice": {
|
||||||
"Title": "Notes",
|
"Title": "Notes",
|
||||||
"InactiveModuleReferences": "The active world references files from inactive modules. These module targets were not treated as unanchored: {modules}"
|
"InactiveModuleReferences": "The active world references files from inactive modules: {modules}",
|
||||||
|
"MissingModuleReferences": "The active world references files from module folders that Foundry does not currently recognize as installed modules: {modules}"
|
||||||
},
|
},
|
||||||
"Summary": {
|
"Summary": {
|
||||||
"NoAnalysis": "No analysis has been run yet.",
|
"NoAnalysis": "No analysis has been run yet.",
|
||||||
|
|||||||
@@ -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.24",
|
"version": "0.0.25",
|
||||||
"compatibility": {
|
"compatibility": {
|
||||||
"minimum": "13",
|
"minimum": "13",
|
||||||
"verified": "13"
|
"verified": "13"
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ export function buildFindings({ files, references, i18n, packageActivity }={}) {
|
|||||||
const wildcardReferences = [];
|
const wildcardReferences = [];
|
||||||
const findings = [];
|
const findings = [];
|
||||||
const inactiveModuleReferenceIds = new Set();
|
const inactiveModuleReferenceIds = new Set();
|
||||||
|
const missingModuleReferenceIds = new Set();
|
||||||
|
|
||||||
for (const reference of resolvedReferences) {
|
for (const reference of resolvedReferences) {
|
||||||
const normalized = reference.normalized;
|
const normalized = reference.normalized;
|
||||||
@@ -85,6 +86,10 @@ export function buildFindings({ files, references, i18n, packageActivity }={}) {
|
|||||||
|
|
||||||
const ownerRelation = compareOwner(reference.sourceScope, file.ownerHint);
|
const ownerRelation = compareOwner(reference.sourceScope, file.ownerHint);
|
||||||
if (ownerRelation === "non-package-to-package") {
|
if (ownerRelation === "non-package-to-package") {
|
||||||
|
if (isMissingModuleTarget(file, packageActivity)) {
|
||||||
|
missingModuleReferenceIds.add(file.ownerHint.ownerId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (isInactiveModuleTarget(file, packageActivity)) {
|
if (isInactiveModuleTarget(file, packageActivity)) {
|
||||||
inactiveModuleReferenceIds.add(file.ownerHint.ownerId);
|
inactiveModuleReferenceIds.add(file.ownerHint.ownerId);
|
||||||
continue;
|
continue;
|
||||||
@@ -144,7 +149,7 @@ export function buildFindings({ files, references, i18n, packageActivity }={}) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
findings,
|
findings,
|
||||||
notices: createNotices({ inactiveModuleReferenceIds, packageActivity, i18n })
|
notices: createNotices({ inactiveModuleReferenceIds, missingModuleReferenceIds, packageActivity, i18n })
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,19 +244,42 @@ function isInactiveModuleTarget(file, packageActivity) {
|
|||||||
return active === false;
|
return active === false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createNotices({ inactiveModuleReferenceIds, packageActivity, i18n }) {
|
function isMissingModuleTarget(file, packageActivity) {
|
||||||
const moduleIds = [...inactiveModuleReferenceIds].sort((a, b) => a.localeCompare(b));
|
if (file.ownerHint?.ownerType !== "module") return false;
|
||||||
if (!moduleIds.length) return [];
|
return packageActivity?.modules?.has?.(file.ownerHint.ownerId) === false;
|
||||||
const moduleLabels = moduleIds.map(id => packageActivity?.moduleLabels?.get?.(id) ?? id);
|
}
|
||||||
return [{
|
|
||||||
kind: "inactive-module-references",
|
function createNotices({ inactiveModuleReferenceIds, missingModuleReferenceIds, packageActivity, i18n }) {
|
||||||
severity: "info",
|
const notices = [];
|
||||||
moduleIds,
|
|
||||||
moduleLabels,
|
const inactiveModuleIds = [...inactiveModuleReferenceIds].sort((a, b) => a.localeCompare(b));
|
||||||
message: format(i18n, "KSA.Notice.InactiveModuleReferences", {
|
if (inactiveModuleIds.length) {
|
||||||
modules: moduleLabels.join(", ")
|
const moduleLabels = inactiveModuleIds.map(id => packageActivity?.moduleLabels?.get?.(id) ?? id);
|
||||||
})
|
notices.push({
|
||||||
}];
|
kind: "inactive-module-references",
|
||||||
|
severity: "info",
|
||||||
|
moduleIds: inactiveModuleIds,
|
||||||
|
moduleLabels,
|
||||||
|
message: format(i18n, "KSA.Notice.InactiveModuleReferences", {
|
||||||
|
modules: moduleLabels.join(", ")
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const missingModuleIds = [...missingModuleReferenceIds].sort((a, b) => a.localeCompare(b));
|
||||||
|
if (missingModuleIds.length) {
|
||||||
|
notices.push({
|
||||||
|
kind: "missing-module-references",
|
||||||
|
severity: "info",
|
||||||
|
moduleIds: missingModuleIds,
|
||||||
|
moduleLabels: missingModuleIds,
|
||||||
|
message: format(i18n, "KSA.Notice.MissingModuleReferences", {
|
||||||
|
modules: missingModuleIds.join(", ")
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return notices;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isDerivedSceneThumbnail(file) {
|
function isDerivedSceneThumbnail(file) {
|
||||||
|
|||||||
40
tests/missing-module-reference-test.mjs
Normal file
40
tests/missing-module-reference-test.mjs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
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", "modules/legacy-module/icons/token.webp"), 1234)
|
||||||
|
];
|
||||||
|
|
||||||
|
const references = [
|
||||||
|
{
|
||||||
|
sourceType: "world-document",
|
||||||
|
sourceScope: { ownerType: "world", ownerId: "demo-world", systemId: "demo-system", subtype: "actors" },
|
||||||
|
sourceLabel: "Actor demo",
|
||||||
|
normalized: {
|
||||||
|
...createFileLocator("data", "modules/legacy-module/icons/token.webp"),
|
||||||
|
targetKind: "local-file"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const packageActivity = {
|
||||||
|
modules: new Map(),
|
||||||
|
moduleLabels: new Map()
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = buildFindings({ files, references, packageActivity, i18n: { format: (key, data={}) => `${key}:${data.modules ?? ""}` } });
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
result.findings.some(finding => finding.kind === "non-package-to-package-reference"),
|
||||||
|
false,
|
||||||
|
"world references into module folders that Foundry does not recognize should not be reported as unanchored package targets"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
result.notices.some(notice => notice.kind === "missing-module-references" && notice.moduleIds.includes("legacy-module")),
|
||||||
|
true,
|
||||||
|
"missing module references should create a dedicated report notice"
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log("missing-module-reference-test: ok");
|
||||||
Reference in New Issue
Block a user