checkMapping takes kind absent, hybrid or draft. A draft has a name and one or more prefixes and no books, and comes back with books []. A prefix inside or holding another entry's book refuses library-playground-other-universe, which replaces library-playground-outside-book. A prefix equal to a book or holding its own refuses library-mapping-invalid, as does a draft source. classify returns a playground file's entry and the book holding its prefix, or null at universe level and in a draft.
33 lines
1.9 KiB
JavaScript
33 lines
1.9 KiB
JavaScript
// The scope rule of design 1.2. Scope comes from the path alone (D2): no file content can change it.
|
|
// Paths are repo-relative and compared exactly, case included (R7 handles case-only twins).
|
|
const inside = (folder, path) => path.startsWith(folder.endsWith('/') ? folder : `${folder}/`);
|
|
|
|
// { scope: 'playground' | 'canon', universe, book, type, folder } or { scope: 'unmapped' }.
|
|
// Prefixes come first (ruling after r11, C2-01c): a `.md` file under any entry's playground prefix is
|
|
// playground, with that entry as `universe` and the book folder that holds the prefix as `book`, or
|
|
// null at universe level and in a draft. Otherwise a `.md` file in a book folder is canon. `type` is
|
|
// the mapped type of the first folder under the prefix (playground) or under the book (canon),
|
|
// 'manuscript' for a manuscript folder, else null. `folder` is that folder name. checkMapping keeps
|
|
// prefixes from overlapping, so at most one matches.
|
|
export function classify(mapping, path) {
|
|
if (typeof path !== 'string' || !path.endsWith('.md')) return { scope: 'unmapped' };
|
|
const entries = Object.entries(mapping.universes);
|
|
for (const [universe, entry] of entries) {
|
|
const prefix = entry.playground.find(p => inside(p, path));
|
|
if (prefix) return place(mapping, path, prefix, { scope: 'playground', universe, book: entry.books.find(b => inside(b, prefix)) ?? null });
|
|
}
|
|
for (const [universe, entry] of entries) {
|
|
const book = entry.books.find(b => inside(b, path));
|
|
if (book) return place(mapping, path, `${book}/`, { scope: 'canon', universe, book });
|
|
}
|
|
return { scope: 'unmapped' };
|
|
}
|
|
|
|
function place(mapping, path, under, where) {
|
|
const rest = path.slice(under.length).split('/');
|
|
const folder = rest.length > 1 ? rest[0] : null;
|
|
const type = folder === null ? null : Object.hasOwn(mapping.types, folder) ? mapping.types[folder]
|
|
: mapping.manuscript.includes(folder) ? 'manuscript' : null;
|
|
return { ...where, type, folder };
|
|
}
|