diff options
| author | (quasar) nebula <qznebula@protonmail.com> | 2025-11-25 12:03:13 -0400 |
|---|---|---|
| committer | (quasar) nebula <qznebula@protonmail.com> | 2025-11-25 12:04:49 -0400 |
| commit | 95c7c7032556d3adfc3107d11a3e14ab0f4c9145 (patch) | |
| tree | 800d4f7dfe0997d9be1a16cd9586228b1a832dbd /src/data/cacheable-object.js | |
| parent | 3afd5e8f8d6b08ccb9e49e53b0da4423a7d23542 (diff) | |
cacheable-object, data: depend on computed values; initial compat
reaches live-dev-server serve with no errors and serves homepage at all and apparently correctly no page navigation performed no full build performed aimed for preserving existing logic should be no subsequent changes to this commit (amend)
Diffstat (limited to 'src/data/cacheable-object.js')
| -rw-r--r-- | src/data/cacheable-object.js | 86 |
1 files changed, 54 insertions, 32 deletions
diff --git a/src/data/cacheable-object.js b/src/data/cacheable-object.js index 3aa3ecf7..dead009a 100644 --- a/src/data/cacheable-object.js +++ b/src/data/cacheable-object.js @@ -120,18 +120,14 @@ export default class CacheableObject { const dependencies = Object.create(null); for (const key of expose.dependencies ?? []) { - switch (key) { - case 'this': - dependencies.this = this; - break; - - case 'thisProperty': - dependencies.thisProperty = property; - break; - - default: - dependencies[key] = this[CacheableObject.updateValue][key]; - break; + if (key === 'this') { + dependencies.this = this; + } else if (key === 'thisProperty') { + dependencies.thisProperty = property; + } else if (key.startsWith('_')) { + dependencies[key] = this[CacheableObject.updateValue][key.slice(1)]; + } else { + dependencies[key] = this[key]; } } @@ -150,27 +146,11 @@ export default class CacheableObject { if (flags.expose) recordAsDependant: { const dependantsMap = this[CacheableObject.propertyDependants]; - if (flags.update && expose?.transform) { - if (dependantsMap[property]) { - dependantsMap[property].push(property); + for (const dependency of dependenciesOf(property, propertyDescriptors)) { + if (dependantsMap[dependency]) { + dependantsMap[dependency].push(dependency); } else { - dependantsMap[property] = [property]; - } - } - - for (const dependency of expose?.dependencies ?? []) { - switch (dependency) { - case 'this': - case 'thisProperty': - continue; - - default: { - if (dependantsMap[dependency]) { - dependantsMap[dependency].push(property); - } else { - dependantsMap[dependency] = [property]; - } - } + dependantsMap[dependency] = [dependency]; } } } @@ -261,6 +241,7 @@ export class CacheableObjectPropertyValueError extends Error { } // good ol' module-scope utility functions + function validatePropertyValue(property, oldValue, newValue, update) { try { const result = update.validate(newValue); @@ -274,3 +255,44 @@ function validatePropertyValue(property, oldValue, newValue, update) { property, oldValue, newValue, {cause: caughtError}); } } + +function* dependenciesOf(property, propertyDescriptors, cycle = []) { + const descriptor = propertyDescriptors[property]; + + if (descriptor?.flags?.update && descriptor?.expose?.transform) { + yield property; + } + + const dependencies = descriptor?.expose?.dependencies; + if (!dependencies) return; + + for (const dependency of dependencies) { + if (dependency === 'this') continue; + if (dependency === 'thisProperty') continue; + + if (dependency.startsWith('_')) { + yield dependency.slice(1); + continue; + } + + if (dependency === property) { + throw new Error( + `property ${dependency} directly depends on its own computed value`); + } + + if (cycle.includes(dependency)) { + const subcycle = cycle.slice(cycle.indexOf(dependency)); + const supercycle = cycle.slice(0, cycle.indexOf(dependency)); + throw new Error( + `property ${dependency} indirectly depends on its own computed value\n` + + ` via: ` + subcycle.map(p => p + ' -> ').join('') + property + ' -> ' + dependency + + (supercycle.length + ? '\n in: ' + supercycle.join(' -> ') + : '')); + } + + cycle.push(property); + yield* dependenciesOf(dependency, propertyDescriptors, cycle); + cycle.pop(); + } +} |