diff options
author | (quasar) nebula <qznebula@protonmail.com> | 2025-02-22 20:35:10 -0400 |
---|---|---|
committer | (quasar) nebula <qznebula@protonmail.com> | 2025-02-22 21:12:25 -0400 |
commit | 2d836f4c2ab3895d675b5d8a93e36922e38fbf35 (patch) | |
tree | fda5e4badbbe9a4e2f83217f2892a5df8c630fb2 | |
parent | e0bf4a7ae3a6ec2f2278f0a62efac45466397803 (diff) |
data: SortingRule: multiple rules, one file (hopefully)
-rw-r--r-- | src/data/things/sorting-rule.js | 96 | ||||
-rw-r--r-- | src/write/build-modes/sort.js | 19 |
2 files changed, 97 insertions, 18 deletions
diff --git a/src/data/things/sorting-rule.js b/src/data/things/sorting-rule.js index d21781e2..a2937157 100644 --- a/src/data/things/sorting-rule.js +++ b/src/data/things/sorting-rule.js @@ -4,7 +4,7 @@ import {readFile, writeFile} from 'node:fs/promises'; import * as path from 'node:path'; import {input} from '#composite'; -import {compareArrays} from '#sugar'; +import {chunkByProperties, compareArrays, unique} from '#sugar'; import Thing from '#thing'; import {isStringNonEmpty, strictArrayOf} from '#validators'; @@ -60,6 +60,39 @@ export class SortingRule extends Thing { save: (results) => ({sortingRules: results}), }); + + check({wikiData}) { + return this.constructor.check(this, opts); + } + + apply(opts) { + return this.constructor.apply(this, opts); + } + + static check() { + throw new Error(`Not implemented`); + } + + static async apply() { + throw new Error(`Not implemented`); + } + + static async* applyAll() { + throw new Error(`Not implemented`); + } + + static async* go({dataPath, wikiData}) { + const rules = wikiData.sortingRules; + const constructors = unique(rules.map(rule => rule.constructor)); + + for (const constructor of constructors) { + yield* constructor.applyAll( + rules + .filter(rule => rule.active) + .filter(rule => rule.constructor === constructor), + {dataPath, wikiData}); + } + } } export class ThingSortingRule extends SortingRule { @@ -156,11 +189,11 @@ export class DocumentSortingRule extends ThingSortingRule { }, }); - check({wikiData}) { - const oldLayout = getThingLayoutForFilename(this.filename, wikiData); + static check(rule, {wikiData}) { + const oldLayout = getThingLayoutForFilename(rule.filename, wikiData); if (!oldLayout) return; - const newLayout = this.#processLayout(oldLayout); + const newLayout = rule.#processLayout(oldLayout); const oldOrder = flattenThingLayoutToDocumentOrder(oldLayout); const newOrder = flattenThingLayoutToDocumentOrder(newLayout); @@ -168,17 +201,17 @@ export class DocumentSortingRule extends ThingSortingRule { return compareArrays(oldOrder, newOrder); } - async apply({wikiData, dataPath}) { - const oldLayout = getThingLayoutForFilename(this.filename, wikiData); + static async apply(rule, {wikiData, dataPath}) { + const oldLayout = getThingLayoutForFilename(rule.filename, wikiData); if (!oldLayout) return; - const newLayout = this.#processLayout(oldLayout); + const newLayout = rule.#processLayout(oldLayout); const newOrder = flattenThingLayoutToDocumentOrder(newLayout); const realPath = path.join( dataPath, - this.filename.split(path.posix.sep).join(path.sep)); + rule.filename.split(path.posix.sep).join(path.sep)); const oldSourceText = await readFile(realPath, 'utf8'); const newSourceText = reorderDocumentsInYAMLSourceText(oldSourceText, newOrder); @@ -186,6 +219,53 @@ export class DocumentSortingRule extends ThingSortingRule { await writeFile(realPath, newSourceText); } + static async* applyAll(rules, {wikiData, dataPath}) { + rules = + rules + .slice() + .sort((a, b) => a.filename.localeCompare(b.filename)); + + for (const {chunk, filename} of chunkByProperties(rules, ['filename'])) { + const initialLayout = getThingLayoutForFilename(filename, wikiData); + if (!initialLayout) continue; + + let currLayout = initialLayout; + let prevLayout = initialLayout; + let anyChanged = false; + + for (const rule of chunk) { + currLayout = rule.#processLayout(currLayout); + + const prevOrder = flattenThingLayoutToDocumentOrder(prevLayout); + const currOrder = flattenThingLayoutToDocumentOrder(currLayout); + + if (compareArrays(currOrder, prevOrder)) { + yield {rule, changed: false}; + } else { + anyChanged = true; + yield {rule, changed: true}; + } + + prevLayout = currLayout; + } + + if (!anyChanged) continue; + + const newLayout = currLayout; + const newOrder = flattenThingLayoutToDocumentOrder(newLayout); + + const realPath = + path.join( + dataPath, + filename.split(path.posix.sep).join(path.sep)); + + const oldSourceText = await readFile(realPath, 'utf8'); + const newSourceText = reorderDocumentsInYAMLSourceText(oldSourceText, newOrder); + + await writeFile(realPath, newSourceText); + } + } + #processLayout(layout) { const fresh = {...layout}; diff --git a/src/write/build-modes/sort.js b/src/write/build-modes/sort.js index 0b759c45..df531dfa 100644 --- a/src/write/build-modes/sort.js +++ b/src/write/build-modes/sort.js @@ -2,6 +2,7 @@ export const description = `Update data files in-place to satisfy custom sorting import {logInfo} from '#cli'; import {empty} from '#sugar'; +import thingConstructors from '#things'; export const config = { fileSizes: { @@ -39,23 +40,21 @@ export async function go({wikiData, dataPath}) { return true; } + const {SortingRule} = thingConstructors; + let numUpdated = 0; let numActive = 0; - for (const sortingRule of wikiData.sortingRules) { - if (!sortingRule.active) continue; - + for await (const result of SortingRule.go({wikiData, dataPath})) { numActive++; - const niceMessage = `"${sortingRule.message}"`; - - if (sortingRule.check({wikiData})) { - logInfo`Already good: ${niceMessage}`; - } else { - logInfo`Updating to satisfy ${niceMessage}.`; - await sortingRule.apply({wikiData, dataPath}); + const niceMessage = `"${result.rule.message}"`; + if (result.changed) { numUpdated++; + logInfo`Updating to satisfy ${niceMessage}.`; + } else { + logInfo`Already good: ${niceMessage}`; } } |