Installations
npm install velona
Developer Guide
Typescript
Yes
Module System
CommonJS, ESM
Node Version
18.17.0
NPM Version
9.6.7
Releases
Contributors
Unable to fetch Contributors
Languages
TypeScript (97.65%)
JavaScript (2.35%)
Developer
Download Statistics
Total Downloads
217,072
Last Day
22
Last Week
1,028
Last Month
4,328
Last Year
67,680
GitHub Statistics
100 Stars
56 Commits
3 Forks
3 Watching
1 Branches
4 Contributors
Package Meta Information
Latest Version
0.8.0
Package Id
velona@0.8.0
Unpacked Size
13.56 kB
Size
4.30 kB
File Count
11
NPM Version
9.6.7
Node Version
18.17.0
Publised On
05 Aug 2023
Total Downloads
Cumulative downloads
Total Downloads
217,072
Last day
-12%
22
Compared to previous day
Last week
8.8%
1,028
Compared to previous week
Last month
-13.4%
4,328
Compared to previous month
Last year
14.2%
67,680
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
Dev Dependencies
19
Velona is TypeScript DI helper for functional programming.
Table of Contents
- Installation
- Usage
- DI to browser API callback
- Comparison with no DI
- Usage with fs
- Usage with prisma
- Integration test
Installation
Usage
index.ts
1import { depend } from "velona"; 2 3const add = (a: number, b: number) => a + b; 4 5export const basicFn = depend({ add }, ({ add }, a: number, b: number, c: number) => add(a, b) * c);
sample.ts
1import { basicFn } from "./"; 2 3console.log(basicFn(2, 3, 4)); // 20
index.spec.ts
1import { basicFn } from "./"; 2 3const injectedFn = basicFn.inject({ add: (a, b) => a * b }); 4 5expect(injectedFn(2, 3, 4)).toBe(2 * 3 * 4); // pass 6expect(basicFn(2, 3, 4)).toBe((2 + 3) * 4); // pass
DI to browser API callback
handler.ts
1import { depend } from "velona"; 2 3export const handler = depend( 4 { print: (text: string) => alert(text) }, 5 ({ print }, e: Pick<MouseEvent, "type" | "x" | "y">) => 6 print(`type: ${e.type}, x: ${e.x}, y: ${e.y}`) 7);
index.ts
1import { handler } from "./handler"; 2 3document.body.addEventListener("click", handler, false); 4document.body.click(); // alert('type: click, x: 0, y: 0')
index.spec.ts
1import { handler } from "./handler";
2
3const event = { type: "click", x: 1, y: 2 };
4
5expect(() => handler(event)).toThrow(); // ReferenceError: alert is not defined (on Node.js)
6
7const injectedHandler = handler.inject({ print: text => text });
8
9expect(injectedHandler(event)).toBe(`type: ${event.type}, x: ${event.x}, y: ${event.y}`); // pass
Comparison with no DI
add.ts
1export const add = (a: number, b: number) => a + b;
noDI.ts
1import { add } from "./add"; 2 3export const noDIFn = (a: number, b: number, c: number) => add(a, b) * c;
index.ts
1import { depend } from "velona"; 2import { add } from "./add"; 3 4export const basicFn = depend({ add }, ({ add }, a: number, b: number, c: number) => add(a, b) * c);
sample.ts
1import { basicFn } from "./"; 2import { noDIFn } from "./noDI"; 3 4console.log(basicFn(2, 3, 4)); // 20 5console.log(noDIFn(2, 3, 4)); // 20
index.spec.ts
1import { basicFn } from "./"; 2import { noDIFn } from "./noDI"; 3 4const injectedFn = basicFn.inject({ add: (a, b) => a * b }); 5 6expect(injectedFn(2, 3, 4)).toBe(2 * 3 * 4); // pass 7expect(basicFn(2, 3, 4)).toBe((2 + 3) * 4); // pass 8expect(noDIFn(2, 3, 4)).toBe((2 + 3) * 4); // pass
Usage with fs
index.ts
1import fs from "fs";
2import { depend } from "velona";
3
4type FS = {
5 readFile(path: string, option: "utf8"): Promise<string>;
6 writeFile(path: string, text: string, option: "utf8"): Promise<void>;
7};
8
9export const basicFn = depend(
10 fs.promises as FS, // downcast for injection
11 async (dependencies, path: string, text: string) => {
12 await dependencies.writeFile(path, text, "utf8");
13 return dependencies.readFile(path, "utf8");
14 }
15);
sample.ts
1import { basicFn } from "./"; 2 3const text = await basicFn("sample.txt", "Hello world!"); // create sample.txt 4console.log(text); // 'Hello world!'
index.spec.ts
1import { basicFn } from "./";
2
3const data: Record<string, string> = {};
4const injectedFn = basicFn.inject({
5 readFile: path => Promise.resolve(data[path]),
6 writeFile: (path, text) => {
7 data[path] = text;
8 return Promise.resolve();
9 },
10});
11
12const text = "Hello world!";
13await expect(injectedFn("test.txt", text)).resolves.toBe(text);
Usage with prisma
tasks.ts
1import { depend } from "velona"; 2import { PrismaClient } from "@prisma/client"; 3 4type Task = { 5 id: number; 6 label: string; 7 done: boolean; 8}; 9 10const prisma = new PrismaClient(); 11 12export const getTasks = depend( 13 { prisma: prisma as { task: { findMany(): Promise<Task[]> } } }, // inject prisma 14 ({ prisma }) => prisma.task.findMany() // prisma is injected object 15);
tasks.spec.ts
1import { getTasks } from "$/service/tasks"; 2 3const injectedGetTasks = getTasks.inject({ 4 prisma: { 5 task: { 6 findMany: () => 7 Promise.resolve([ 8 { id: 0, label: "task1", done: false }, 9 { id: 1, label: "task2", done: false }, 10 { id: 2, label: "task3", done: true }, 11 { id: 3, label: "task4", done: true }, 12 { id: 4, label: "task5", done: false }, 13 ]), 14 }, 15 }, 16}); 17 18await expect(injectedGetTasks()).resolves.toHaveLength(5);
Integration test
add.ts
1export const add = (a: number, b: number) => a + b;
grandchild.ts
1import { depend } from "velona"; 2import { add } from "./add"; 3 4export const grandchild = depend({ add }, ({ add }, a: number, b: number) => add(a, b));
child.ts
1import { depend } from "velona"; 2import { grandchild } from "./grandchild"; 3 4export const child = depend( 5 { grandchild }, 6 ({ grandchild }, a: number, b: number, c: number) => grandchild(a, b) * c 7);
parentFn.ts
1import { depend } from "velona"; 2import { child } from "./child"; 3 4export const parentFn = depend( 5 { child, print: (data: number) => alert(data) }, 6 ({ child, print }, a: number, b: number, c: number) => print(child(a, b, c)) 7);
index.ts
1import { parentFn } from "./parentFn"; 2 3parentFn(2, 3, 4); // alert(20)
parentFn.spec.ts
1import { parentFn } from "./parentFn"; 2 3const injectedFn = parentFn.inject(parentDeps => ({ 4 child: parentDeps.child.inject(childDeps => ({ 5 grandchild: clildDeps.grandchild.inject({ 6 add: (a, b) => a * b, 7 }), 8 })), 9 print: data => data, 10})); 11 12expect(injectedFn(2, 3, 4)).toBe(2 * 3 * 4); // pass
License
Velona is licensed under a MIT License.
No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
license file detected
Details
- Info: project has a license file: LICENSE:0
- Info: FSF or OSI recognized license: MIT License: LICENSE:0
Reason
4 existing vulnerabilities detected
Details
- Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92
- Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg
- Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275
- Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv
Reason
Found 2/18 approved changesets -- score normalized to 1
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
detected GitHub workflow tokens with excessive permissions
Details
- Warn: no topLevel permission defined: .github/workflows/nodejs.yml:1
- Warn: no topLevel permission defined: .github/workflows/release-drafter-main.yml:1
- Warn: no topLevel permission defined: .github/workflows/release-drafter.yml:1
- Info: no jobLevel write permissions found
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/nodejs.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/frouriojs/velona/nodejs.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/nodejs.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/frouriojs/velona/nodejs.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/nodejs.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/frouriojs/velona/nodejs.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/nodejs.yml:40: update your workflow using https://app.stepsecurity.io/secureworkflow/frouriojs/velona/nodejs.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/nodejs.yml:42: update your workflow using https://app.stepsecurity.io/secureworkflow/frouriojs/velona/nodejs.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/nodejs.yml:46: update your workflow using https://app.stepsecurity.io/secureworkflow/frouriojs/velona/nodejs.yml/main?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/release-drafter-main.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/frouriojs/velona/release-drafter-main.yml/main?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/release-drafter.yml:11: update your workflow using https://app.stepsecurity.io/secureworkflow/frouriojs/velona/release-drafter.yml/main?enable=pin
- Warn: npmCommand not pinned by hash: .github/workflows/nodejs.yml:28
- Warn: npmCommand not pinned by hash: .github/workflows/nodejs.yml:52
- Info: 0 out of 6 GitHub-owned GitHubAction dependencies pinned
- Info: 0 out of 2 third-party GitHubAction dependencies pinned
- Info: 0 out of 2 npmCommand dependencies pinned
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Reason
security policy file not detected
Details
- Warn: no security policy file detected
- Warn: no security file to analyze
- Warn: no security file to analyze
- Warn: no security file to analyze
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
- Warn: 0 commits out of 14 are checked with a SAST tool
Score
3.5
/10
Last Scanned on 2024-12-16
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More