diff options
author | (quasar) nebula <qznebula@protonmail.com> | 2025-02-22 13:16:05 -0400 |
---|---|---|
committer | (quasar) nebula <qznebula@protonmail.com> | 2025-02-22 13:16:47 -0400 |
commit | d35275e1312cdc889aede73293afd971274384dc (patch) | |
tree | 2981c080b79670f9ff9d314dd3f6a46b34d5872c /src/data/things/sorting-rule.js | |
parent | f21883e743670dc727d3644b920319060ccb5bee (diff) |
data: SortingRule, DocumentSortingRule
Diffstat (limited to 'src/data/things/sorting-rule.js')
-rw-r--r-- | src/data/things/sorting-rule.js | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/src/data/things/sorting-rule.js b/src/data/things/sorting-rule.js new file mode 100644 index 00000000..88f37719 --- /dev/null +++ b/src/data/things/sorting-rule.js @@ -0,0 +1,139 @@ +export const SORTING_RULE_DATA_FILE = 'sorting-rules.yaml'; + +import {input} from '#composite'; +import Thing from '#thing'; +import {isStringNonEmpty, strictArrayOf} from '#validators'; +import {documentModes} from '#yaml'; + +import { + compareCaseLessSensitive, + sortByDate, + sortByDirectory, + sortByName, +} from '#sort'; + +import {flag} from '#composite/wiki-properties'; + +export class SortingRule extends Thing { + static [Thing.friendlyName] = `Sorting Rule`; + + static [Thing.getPropertyDescriptors] = () => ({ + // Update & expose + + active: flag(true), + }); + + static [Thing.yamlDocumentSpec] = { + fields: { + 'Active': {property: 'active'}, + }, + }; + + static [Thing.getYamlLoadingSpec] = ({ + documentModes: {allInOne}, + thingConstructors: {DocumentSortingRule}, + }) => ({ + title: `Process sorting rules file`, + file: SORTING_RULE_DATA_FILE, + + documentMode: allInOne, + documentThing: document => + (document['Sort Documents'] + ? DocumentSortingRule + : null), + + save: (results) => ({sortingRules: results}), + }); +} + +export class DocumentSortingRule extends SortingRule { + static [Thing.getPropertyDescriptors] = () => ({ + // Update & expose + + // TODO: glob :plead: + filename: { + flags: {update: true, expose: true}, + update: { + validate: isStringNonEmpty, + }, + }, + + properties: { + flags: {update: true, expose: true}, + update: { + validate: strictArrayOf(isStringNonEmpty), + }, + }, + }); + + static [Thing.yamlDocumentSpec] = Thing.extendDocumentSpec(SortingRule, { + fields: { + 'Sort Documents': {property: 'filename'}, + 'By Properties': {property: 'properties'}, + }, + }); + + apply(layout) { + const fresh = {...layout}; + + let sortable = null; + switch (fresh.documentMode) { + case documentModes.headerAndEntries: + sortable = fresh.entryThings = + fresh.entryThings.slice(); + break; + + case documentModes.allInOne: + sortable = fresh.things = + fresh.things.slice(); + break; + + default: + throw new Error(`Invalid document type for sorting`); + } + + if (this.properties) { + for (const property of this.properties.slice().reverse()) { + const get = thing => thing[property]; + const lc = property.toLowerCase(); + + if (lc.endsWith('date')) { + sortByDate(sortable, {getDate: get}); + continue; + } + + if (lc.endsWith('directory')) { + sortByDirectory(sortable, {getDirectory: get}); + continue; + } + + if (lc.endsWith('name')) { + sortByName(sortable, {getName: get}); + continue; + } + + const values = sortable.map(get); + + if (values.every(v => typeof v === 'string')) { + sortable.sort((a, b) => + compareCaseLessSensitive(get(a), get(b))); + continue; + } + + if (values.every(v => typeof v === 'number')) { + sortable.sort((a, b) => get(a) - get(b)); + continue; + } + + sortable.sort((a, b) => + (get(a).toString() < get(b).toString() + ? -1 + : get(a).toString() > get(b).toString() + ? +1 + : 0)); + } + } + + return fresh; + } +} |