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
2 changes: 1 addition & 1 deletion bin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { createRequire } from "node:module";
import { fileURLToPath } from "node:url";

// Import Third-party Dependencies
import kleur from "kleur";
import sade from "sade";
import semver from "semver";
import * as i18n from "@nodesecure/i18n";
Expand All @@ -17,6 +16,7 @@ import { loadRegistryURLFromLocalSystem } from "@nodesecure/npm-registry-sdk";

// Import Internal Dependencies
import * as commands from "../src/commands/index.js";
import kleur from "../src/utils/styleText.js";

// CONSTANTS
const __dirname = path.dirname(fileURLToPath(import.meta.url));
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@
"highlightjs-line-numbers.js": "^2.8.0",
"ini": "^6.0.0",
"json-diff-ts": "^4.8.1",
"kleur": "^4.1.5",
"lit": "^3.3.1",
"ms": "^2.1.3",
"open": "^11.0.0",
Expand Down
4 changes: 3 additions & 1 deletion src/commands/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import { spawn } from "node:child_process";

// Import Third-party Dependencies
import * as RC from "@nodesecure/rc";
import kleur from "kleur";

// Import Internal Dependencies
import kleur from "../utils/styleText.js";

const K_HOME_PATH = path.join(os.homedir(), "nodesecure");

Expand Down
2 changes: 1 addition & 1 deletion src/commands/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import path from "node:path";
import crypto from "node:crypto";

// Import Third-party Dependencies
import kleur from "kleur";
import open from "open";
import * as SemVer from "semver";
import * as i18n from "@nodesecure/i18n";
Expand All @@ -18,6 +17,7 @@ import {
// Import Internal Dependencies
import english from "../../i18n/english.js";
import french from "../../i18n/french.js";
import kleur from "../utils/styleText.js";

// CONSTANTS
const kRequiredScannerRange = ">=5.1.0";
Expand Down
4 changes: 3 additions & 1 deletion src/commands/lang.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Import Third-party Dependencies
import * as i18n from "@nodesecure/i18n";
import { select } from "@topcli/prompts";
import kleur from "kleur";

// Import Internal Dependencies
import kleur from "../utils/styleText.js";

export async function set() {
const langs = await i18n.getLanguages();
Expand Down
2 changes: 1 addition & 1 deletion src/commands/scanner.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import path from "node:path";
import events from "node:events";

// Import Third-party Dependencies
import kleur from "kleur";
import semver from "semver";
import filenamify from "filenamify";
import { Spinner } from "@topcli/spinner";
Expand All @@ -14,6 +13,7 @@ import * as scanner from "@nodesecure/scanner";
import { cache } from "@nodesecure/server";

// Import Internal Dependencies
import kleur from "../utils/styleText.js";
import * as http from "./http.js";
import { parseContacts } from "./parsers/contacts.js";

Expand Down
4 changes: 3 additions & 1 deletion src/commands/scorecard.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import fs from "node:fs";

// Import Third-party Dependencies
import cliui from "@topcli/cliui";
import kleur from "kleur";
import * as scorecard from "@nodesecure/ossf-scorecard-sdk";
import ini from "ini";
import { Ok, Err } from "@openally/result";

// Import Internal Dependencies
import kleur from "../utils/styleText.js";

// VARS
const { yellow, grey, cyan, white } = kleur;

Expand Down
4 changes: 3 additions & 1 deletion src/commands/summary.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import path from "node:path";

// Import Third-party Dependencies
import cliui from "@topcli/cliui";
import kleur from "kleur";
import * as i18n from "@nodesecure/i18n";
import { formatBytes } from "@nodesecure/utils";

// Import Internal Dependencies
import kleur from "../utils/styleText.js";

// VARS
const { yellow, grey, white, green, cyan, red } = kleur;

Expand Down
4 changes: 3 additions & 1 deletion src/commands/verify.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// Import Third-party Dependencies
import cliui from "@topcli/cliui";
import kleur from "kleur";
import { verify } from "@nodesecure/scanner";
import { formatBytes, locationToString } from "@nodesecure/utils";

// Import Internal Dependencies
import kleur from "../utils/styleText.js";

// VARS
const { yellow, grey, white, green, cyan, red, magenta } = kleur;

Expand Down
40 changes: 40 additions & 0 deletions src/utils/styleText.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Import Node.js Dependencies
import { styleText } from "node:util";

/**
* @typedef {import("node:util").ForegroundColors} ForegroundColors
* @typedef {import("node:util").BackgroundColors} BackgroundColors
* @typedef {import("node:util").Modifiers} Modifiers
* @typedef {ForegroundColors | BackgroundColors | Modifiers} StyleName
*/

/**
* @typedef {((text: string) => string) & Record<StyleName, Formatter>} Formatter
*/

/**
* Creates a chainable formatter for terminal styling using Node.js styleText
* @param {StyleName[]} styles - Array of styles to apply
* @returns {Formatter}
*/
function createFormatter(styles = []) {
function fn(text) {
// When called without arguments, return the formatter for chaining
if (text === undefined) {
return formatter;
}

// Convert to string since styleText only accepts strings
return styleText(styles, String(text));
}

const formatter = new Proxy(fn, {
get: (_, prop) => createFormatter([...styles, prop])
});

return formatter;
}

const formatter = createFormatter();

export default formatter;
82 changes: 82 additions & 0 deletions test/utils/styleText.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Import Node.js Dependencies
import assert from "node:assert";
import { describe, it } from "node:test";

// Import Internal Dependencies
import kleur from "../../src/utils/styleText.js";

describe("styleText utility", () => {
describe("direct style calls", () => {
it("should apply a single style", () => {
const result = kleur.red("hello");
assert.ok(result.includes("hello"), "should contain the text");
assert.strictEqual(typeof result, "string", "should return a string");
});

it("should apply bold modifier", () => {
const result = kleur.bold("hello");
assert.ok(result.includes("hello"), "should contain the text");
});

it("should apply multiple styles via chaining property access", () => {
const result = kleur.red.bold("hello");
assert.ok(result.includes("hello"), "should contain the text");
});
});

describe("chaining with empty call", () => {
it("should support kleur.color() empty call then method", () => {
const result = kleur.green().bold("hello");
assert.ok(result.includes("hello"), "should contain the text");
});

it("should support multiple empty calls in chain", () => {
const result = kleur.cyan().bold().underline("hello");
assert.ok(result.includes("hello"), "should contain the text");
});
});

describe("non-string value handling", () => {
it("should convert numbers to strings", () => {
const result = kleur.yellow(42);
assert.ok(result.includes("42"), "should contain the number as string");
});

it("should handle zero", () => {
const result = kleur.red(0);
assert.ok(result.includes("0"), "should contain zero as string");
});

it("should handle negative numbers", () => {
const result = kleur.blue(-5);
assert.ok(result.includes("-5"), "should contain negative number as string");
});
});

describe("destructuring support", () => {
it("should work with destructured colors", () => {
const { red, green, blue } = kleur;
assert.ok(red("test").includes("test"), "red should work");
assert.ok(green("test").includes("test"), "green should work");
assert.ok(blue("test").includes("test"), "blue should work");
});

it("should work with destructured modifiers", () => {
const { bold, italic } = kleur;
assert.ok(bold("test").includes("test"), "bold should work");
assert.ok(italic("test").includes("test"), "italic should work");
});
});

describe("edge cases", () => {
it("should handle empty string", () => {
const result = kleur.red("");
assert.strictEqual(typeof result, "string", "should return a string");
});

it("should handle special characters", () => {
const result = kleur.green("hello\nworld");
assert.ok(result.includes("hello\nworld"), "should preserve special characters");
});
});
});