Security News
Node.js EOL Versions CVE Dubbed the "Worst CVE of the Year" by Security Experts
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
Declarative side-effects
npm install affection
Affection is a library for describing side-effects as plain data and providing composition utilities. This project aims to improve on similar libraries by not using generators.
Generators make testing difficult in that:
next()
isn't as simple as function calling.So Affection is all about functions, with the goals:
Let's see how we do.
This first example does not use any composition.
import { run, call, callMethod } from 'affection'
const getJSON = url => [
call(fetch, url),
resp => [callMethod(resp, 'json')]
]
async function main () {
const payload = await run(getJSON('http://example.com'))
console.log(payload)
}
This second example does the same as the first. Here we are using the composition utilities.
import { step, runStep, batchSteps, call, callMethod } from 'affection'
const fetchUrl = url => call(fetch, [url])
const readJSON = resp => callMethod(resp, 'json')
const getJSON = batchSteps([fetchUrl, readJSON].map(step))
async function main () {
const payload = await runStep(getJSON, 'http://example.com')
console.log(payload)
}
The package contains the following:
See defaultHandle
for adding more.
call
call(func: function, args: Array<any>, context: any): Effect
Describes a function call of func.apply(context, args)
.
callMethod
callMethod(obj: any, method: String, args: Array<any>): Effect
Describes a method call of obj[method].apply(obj, args)
all
all(effects: Array<Effect>): Effect
Describes combining effects. Like Promise.all
.
race
race(effects: Array<Effect>): Effect
Describes racing effects. Like Promise.race
.
itself
itself(value: any): Effect
Describes a value. This is an identity function for Effects.
defaultHandle
defaultHandle(effect: Effect, handle: function): any
Performs the action described by a particular effect.
defaultHandle
provides the handling for the effects included in Affection.
To add more, create a new handle that wraps defaultHandle
and pass that to run
.
For example, say we want to add a timeout effect:
import { defaultHandle } from 'affection'
export function timeout (duration) {
return { type: 'timeout', duration }
}
export function myHandle (effect, handle) {
if (effect.type === 'timeout') {
return new Promise(resolve => setTimeout(resolve, effect.duration))
}
return defaultHandle(effect, handle)
}
// Later...
async function main () {
await run([timeout(1000)], myHandler)
// Will have waited a second
}
run
run(plan: [Effect, function?], handle: function = defaultHandle): any
Executes a plan.
A plan is an array where the first element is an Effect to be handled using handle
and the second element is a function to call with the result of the Effect.
If the function is not provided, execution terminates and the result is returned.
step
step(makeEffect: any -> Effect): Step
Creates a step.
A step is a means of encapsulating an effect without needing a plan (as described by run
).
This is hard to understand without an understanding of how run
works.
The run
function is recursively executing plans until there is nothing more to do.
A step is a way of saying, "Execute this effect; we might be done, might not."
There could be 5 more effects to run or it's the end result; the step doesn't need to know.
This is for code reuse: effects should be decoupled from their consumers.
mapStep
mapStep(step: Step, transform: function): Step
Creates a new step which will return the result of transform
called with the input to the step
makeEffect
and the result of the Effect.
This is good for passing along context without mucking up simple steps. For example, we are building a dictionary of the most used word for each country. We want to retain the country we are querying about in the result.
const getMostUsedWordInCountry = country => call(MyAPI, country)
const countryWordStep = step(getMostUsedWordInCountry)
const getCountryWord = mapStep(countryWordStep, (result, country) => ({ country, word: result }))
runStep(getCountryWord, 'Canada').then(result => {
console.log(result)
// => { country: 'Canada', word: 'Sorry' }
})
batchSteps
batchSteps(steps: Array<Step>): Step
Creates a new step which will call each step passing the result of first step to the next and so on.
runStep
runStep(step: Step, input: any, handle: function = defaultHandle): any
Executes a step
with a given input
.
Uses run
so handle
works in the same way.
FAQs
Declarative side-effects
The npm package affection receives a total of 1 weekly downloads. As such, affection popularity was classified as not popular.
We found that affection demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
Security News
cURL and Go security teams are publicly rejecting CVSS as flawed for assessing vulnerabilities and are calling for more accurate, context-aware approaches.
Security News
Bun 1.2 enhances its JavaScript runtime with 90% Node.js compatibility, built-in S3 and Postgres support, HTML Imports, and faster, cloud-first performance.