Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/early-ads-appear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@nodesecure/size-satisfies": major
---

Migrate codebase to TypeScript
3 changes: 3 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
},
{
"path": "./workspaces/server"
},
{
"path": "./workspaces/size-satisfies"
}
]
}
69 changes: 56 additions & 13 deletions workspaces/size-satisfies/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ Scorecard](https://api.securityscorecards.dev/projects/github.com/NodeSecure/cli
![size](https://img.shields.io/github/languages/code-size/NodeSecure/size-satisfies?style=for-the-badge)
[![build](https://img.shields.io/github/actions/workflow/status/NodeSecure/cli/size-satisfies.yml?style=for-the-badge)](https://github.com/NodeSecure/cli/actions?query=workflow%3A%22Size+Satisfies+CI%22)

Same as SemVer.satisfies but for file size!
Check whether a file size satisfies a given constraint — like `semver.satisfies` but for bytes.

## Requirements

- [Node.js](https://nodejs.org/en/) v20 or higher
- [Node.js](https://nodejs.org/en/) v18 or higher

## Getting Started

Expand All @@ -26,25 +26,68 @@ $ yarn add @nodesecure/size-satisfies
## Usage example

```js
import { strict } from "assert";
import sizeSatisfies from "size-satisfies";
import sizeSatisfies from "@nodesecure/size-satisfies";

// String sizes are parsed using the `bytes` package (B, KB, MB, GB, …)
console.log(sizeSatisfies(">= 45KB", "20MB")); // true — 20 MB is >= 45 KB
console.log(sizeSatisfies("<= 45KB", "10B")); // true — 10 B is <= 45 KB
console.log(sizeSatisfies("= 1MB", "1MB")); // true — exact match
console.log(sizeSatisfies("> 45KB", "45KB")); // false — not strictly greater

// Numeric sizes are treated as bytes
console.log(sizeSatisfies(">= 45KB", 46080)); // true — 46 080 B == 45 KB
console.log(sizeSatisfies("= 45KB", 2000)); // false — 2 000 B != 45 KB
console.log(sizeSatisfies("< 45KB", 0)); // true — 0 B < 45 KB

// Invalid patterns always return false
console.log(sizeSatisfies("", "45KB")); // false — empty pattern
console.log(sizeSatisfies("45KB", "45KB")); // false — missing operator
console.log(sizeSatisfies("!! 45KB", "45KB")); // false — unknown operator

// Unparseable sizes fall back to 0
console.log(sizeSatisfies("> 0KB", "not_a_size")); // false — 0 > 0 is false
console.log(sizeSatisfies("= 0KB", "not_a_size")); // true — 0 == 0
console.log(sizeSatisfies(">= not_a_size", "10KB")); // true — 10 KB >= 0
```

## API

const { strictEqual } = strict;
### `sizeSatisfies(pattern, size)`

strictEqual(sizeSatisfies(">= 45KB", "20MB"), true);
strictEqual(sizeSatisfies("= 1MB", "1MB"), true);
strictEqual(sizeSatisfies("= 1MB", 2000), false);
```ts
function sizeSatisfies(pattern: string, size: number | string): boolean
```

The first argument of the `sizeSatisfies` method is the pattern with the operator + size. Available operators are `>=`, `<=`, `>`, `<`, `=`.
Returns `true` when `size` satisfies the constraint expressed by `pattern`, `false` otherwise.

## API
#### `pattern`

A string composed of an **operator** followed by a **size value** (with an optional space between them):

```
">= 45KB"
"< 1MB"
"= 512B"
```

| Operator | Meaning |
|----------|--------------------------|
| `>=` | greater than or equal to |
| `<=` | less than or equal to |
| `>` | strictly greater than |
| `<` | strictly less than |
| `=` | exactly equal to |

The size value in the pattern is parsed by the [`bytes`](https://www.npmjs.com/package/bytes) package and therefore supports the same units: `B`, `KB`, `MB`, `GB`, `TB`, `PB` (case-insensitive). An unparseable size value falls back to `0`.

A pattern that is empty, has no operator, or uses an unrecognised operator causes the function to return `false` immediately.

### sizeSatisfies(pattern: string, size: number | string): boolean
#### `size`

When the size is a string we convert it to a bytes number. When the argument is a number we consider the value as bytes.
The actual size to test against the pattern.

Invalid pattern will always return **false**.
- **`number`** — interpreted as a raw byte count.
- **`string`** — parsed by the [`bytes`](https://www.npmjs.com/package/bytes) package (e.g. `"45KB"`, `"1.5MB"`). An unparseable string falls back to `0`.

## License

Expand Down
3 changes: 0 additions & 3 deletions workspaces/size-satisfies/index.d.ts

This file was deleted.

17 changes: 11 additions & 6 deletions workspaces/size-satisfies/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
"version": "1.1.0",
"description": "Same as SemVer.satisfies but for file size!",
"type": "module",
"exports": "./index.js",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"scripts": {
"lint": "eslint index.js",
"test-only": "node --test test/test.js",
"build": "tsc",
"prepublishOnly": "npm run build",
"lint": "eslint src/index.ts test",
"test-only": "node --test test/test.ts",
"test": "npm run lint && npm run test-only"
},
"publishConfig": {
Expand All @@ -20,8 +23,7 @@
"directory": "workspaces/size-satisfies"
},
"files": [
"index.js",
"index.d.ts"
"src"
],
"keywords": [
"size",
Expand All @@ -42,6 +44,9 @@
},
"homepage": "https://github.com/NodeSecure/cli/master/workspaces/size-satisfies#readme",
"dependencies": {
"bytes": "^3.1.2"
"bytes": "3.1.2"
},
"devDependencies": {
"@types/bytes": "3.1.5"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,29 @@ const kOperators = {
">": (lh, rh) => lh > rh,
"<": (lh, rh) => lh < rh,
"=": (lh, rh) => lh === rh
};
} satisfies Record<string, (lh: number, rh: number) => boolean>;

export function sizeSatisfies(
pattern: string,
size: number | string
): boolean {
const localSize = typeof size === "number" ?
size :
bytes(size) ?? 0;

/**
* @function sizeSatisfies
* @param {!string} pattern
* @param {!(number | string)} size
* @returns {boolean}
*/
function sizeSatisfies(pattern, size) {
const localSize = typeof size === "number" ? size : bytes(size);
const regexResult = /^(?<operator>[><=]{1,2})\s*(?<patternSize>.*)/g.exec(pattern);
if (regexResult === null) {
if (
regexResult === null ||
regexResult.groups === undefined
) {
return false;
}
const { operator, patternSize } = regexResult.groups;

return kOperators[operator](localSize, bytes(patternSize));
return kOperators[operator as keyof typeof kOperators](
localSize,
bytes(patternSize) ?? 0
);
}

export default sizeSatisfies;
22 changes: 0 additions & 22 deletions workspaces/size-satisfies/test/test.js

This file was deleted.

74 changes: 74 additions & 0 deletions workspaces/size-satisfies/test/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Import Node.js Dependencies
import { test } from "node:test";
import assert from "node:assert";

// Import Internal Dependencies
import sizeSatisfies from "../src/index.ts";

test("return false for empty pattern", () => {
assert.strictEqual(sizeSatisfies("", "45KB"), false);
});

test("return false for pattern without operator", () => {
assert.strictEqual(sizeSatisfies("45KB", "45KB"), false);
});

test("return false for invalid operator", () => {
assert.strictEqual(sizeSatisfies("!! 45KB", "45KB"), false);
});

test("pattern with only an operator treats patternSize as 0", () => {
assert.strictEqual(sizeSatisfies(">=", "45KB"), true);
assert.strictEqual(sizeSatisfies(">", "0KB"), false);
assert.strictEqual(sizeSatisfies("=", "0KB"), true);
assert.strictEqual(sizeSatisfies("<", "45KB"), false);
});

test("size as a numeric value", () => {
assert.strictEqual(sizeSatisfies(">= 45KB", 46080), true);
assert.strictEqual(sizeSatisfies("= 45KB", 46080), true);
assert.strictEqual(sizeSatisfies("= 45KB", 2000), false);
assert.strictEqual(sizeSatisfies("< 45KB", 0), true);
});

test("size as an unparseable string falls back to 0", () => {
assert.strictEqual(sizeSatisfies("> 0KB", "not_a_size"), false);
assert.strictEqual(sizeSatisfies("= 0KB", "not_a_size"), true);
assert.strictEqual(sizeSatisfies("<= 10KB", "not_a_size"), true);
});

test("unparseable patternSize falls back to 0", () => {
assert.strictEqual(sizeSatisfies(">= not_a_size", "10KB"), true);
assert.strictEqual(sizeSatisfies("= not_a_size", 0), true);
assert.strictEqual(sizeSatisfies("> not_a_size", 0), false);
});

test(">= operator", () => {
assert.strictEqual(sizeSatisfies(">= 45KB", "20MB"), true);
assert.strictEqual(sizeSatisfies(">= 45KB", "45KB"), true);
assert.strictEqual(sizeSatisfies(">= 45KB", "10B"), false);
});

test("<= operator", () => {
assert.strictEqual(sizeSatisfies("<= 45KB", "10B"), true);
assert.strictEqual(sizeSatisfies("<= 45KB", "45KB"), true);
assert.strictEqual(sizeSatisfies("<= 45KB", "20MB"), false);
});

test("= operator", () => {
assert.strictEqual(sizeSatisfies("= 45KB", "45KB"), true);
assert.strictEqual(sizeSatisfies("= 45KB", "46KB"), false);
});

test("> operator", () => {
assert.strictEqual(sizeSatisfies("> 45KB", "46KB"), true);
assert.strictEqual(sizeSatisfies("> 45KB", "45KB"), false);
assert.strictEqual(sizeSatisfies("> 45KB", "44KB"), false);
});

test("< operator", () => {
assert.strictEqual(sizeSatisfies("< 45KB", "44KB"), true);
assert.strictEqual(sizeSatisfies("< 45KB", "45KB"), false);
assert.strictEqual(sizeSatisfies("< 45KB", "46KB"), false);
});

9 changes: 9 additions & 0 deletions workspaces/size-satisfies/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src",
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
Loading