@javelina/npmhelpers 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 jack-npmhelpers contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # @javelina/npmhelpers
2
+
3
+ 一组日常使用的 JavaScript 小工具函数集合。
4
+
5
+ ## 安装
6
+
7
+ npm install @javelina/npmhelpers
8
+
9
+ ## 使用
10
+
11
+ ```js
12
+ import { slugify, chunked, flatten, truncate, sha256File } from "@javelina/npmhelpers";
13
+
14
+ slugify("Hello, World!"); // 'hello-world'
15
+ [...chunked([0, 1, 2, 3, 4], 2)] // [[0, 1], [2, 3], [4]]
16
+ flatten([[1, 2], [3, 4]]); // [1, 2, 3, 4]
17
+ truncate("a long sentence", 8); // 'a long...'
18
+ sha256File("some-file.bin"); // 'e3b0c442...'
19
+ ```
20
+
21
+ ## 命令行
22
+
23
+ npx npmhelpers slug "Hello, World!" # hello-world
24
+ npx npmhelpers hash <file> # 打印文件的 SHA-256 摘要
25
+
26
+ ## 提供的函数
27
+
28
+ | 函数 | 说明 |
29
+ |------|------|
30
+ | `slugify(text)` | 把文本转换成 URL 安全的 slug |
31
+ | `chunked(iterable, size)` | 把可迭代对象按固定大小分块 |
32
+ | `flatten(nested)` | 展平一层嵌套的数组 |
33
+ | `truncate(text, length)` | 截断文本并追加后缀 |
34
+ | `sha256File(path)` | 计算文件的 SHA-256 摘要 |
35
+
36
+ ## 二进制资源
37
+
38
+ 二进制文件统一放在 `asset/` 目录下,发布 npm 时会随包一起发布。
39
+
40
+ ## 发布
41
+
42
+ 包名是 scoped 包(`@javelina/npmhelpers`),已在 `package.json` 中配置 `publishConfig.access = "public"`,会作为公开包发布:
43
+
44
+ npm login
45
+ npm publish
46
+
47
+ ## 开发
48
+
49
+ npm test
@@ -0,0 +1,17 @@
1
+ # asset
2
+
3
+ 这个文件夹用于存放二进制文件(例如 `.wasm`、`.bin`、图片、模型文件、字体等)。
4
+
5
+ - 放在这里的文件会被一起发布到 npm(`package.json` 的 `files` 字段已经包含 `asset`)。
6
+ - 发布前请确认要发布的二进制文件都放在这个目录下,不要放在其他地方。
7
+ - 较大的二进制文件建议先在 npm 上确认包体积限制,必要时改用 CDN 或按需下载。
8
+
9
+ 示例:
10
+
11
+ asset/
12
+ fonts/
13
+ example.woff2
14
+ wasm/
15
+ helper.wasm
16
+ bin/
17
+ tool.exe
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { main } from "../src/cli.js";
4
+
5
+ process.exitCode = main();
package/index.js ADDED
@@ -0,0 +1 @@
1
+ export { chunked, flatten, sha256File, slugify, truncate } from "./src/helpers.js";
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@javelina/npmhelpers",
3
+ "version": "0.1.0",
4
+ "description": "A small collection of everyday JavaScript helper utilities.",
5
+ "type": "module",
6
+ "main": "./index.js",
7
+ "exports": {
8
+ ".": "./index.js"
9
+ },
10
+ "bin": {
11
+ "npmhelpers": "./bin/npmhelpers.js"
12
+ },
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "files": [
17
+ "index.js",
18
+ "src",
19
+ "bin",
20
+ "asset"
21
+ ],
22
+ "scripts": {
23
+ "test": "node --test"
24
+ },
25
+ "keywords": [
26
+ "helpers",
27
+ "utilities",
28
+ "text",
29
+ "files",
30
+ "hashing"
31
+ ],
32
+ "license": "MIT",
33
+ "engines": {
34
+ "node": ">10"
35
+ }
36
+ }
package/src/cli.js ADDED
@@ -0,0 +1,44 @@
1
+ /** Command-line entry point for npmhelpers. */
2
+
3
+ import { sha256File, slugify } from "./helpers.js";
4
+
5
+ const USAGE = [
6
+ "usage: npmhelpers <command>",
7
+ "",
8
+ "commands:",
9
+ " slug <text> Convert text into a URL-safe slug",
10
+ " hash <file> Print the SHA-256 digest of a file",
11
+ ].join("\n");
12
+
13
+ /**
14
+ * @param {string[]} [argv]
15
+ * @returns {number}
16
+ */
17
+ export function main(argv = process.argv.slice(2)) {
18
+ const [command, ...rest] = argv;
19
+
20
+ switch (command) {
21
+ case "slug": {
22
+ const text = rest.join(" ");
23
+ if (!text) {
24
+ console.error("usage: npmhelpers slug <text>");
25
+ return 2;
26
+ }
27
+ console.log(slugify(text));
28
+ return 0;
29
+ }
30
+ case "hash": {
31
+ const [path] = rest;
32
+ if (!path) {
33
+ console.error("usage: npmhelpers hash <file>");
34
+ return 2;
35
+ }
36
+ console.log(sha256File(path));
37
+ return 0;
38
+ }
39
+ default: {
40
+ console.error(USAGE);
41
+ return command ? 2 : 0;
42
+ }
43
+ }
44
+ }
package/src/helpers.js ADDED
@@ -0,0 +1,88 @@
1
+ /** Everyday helper functions. */
2
+
3
+ import { createHash } from "node:crypto";
4
+ import { readFileSync } from "node:fs";
5
+
6
+ const SEP_REGEX_SPECIALS = /[.*+?^${}()|[\]\\]/g;
7
+
8
+ /**
9
+ * Convert text into a URL-safe slug.
10
+ * @param {string} text
11
+ * @param {string} [sep]
12
+ * @returns {string}
13
+ */
14
+ export function slugify(text, sep = "-") {
15
+ const escapedSep = String(sep).replace(SEP_REGEX_SPECIALS, "\\$&");
16
+ return String(text)
17
+ .normalize("NFKD")
18
+ .replace(/[\u0300-\u036f]/g, "")
19
+ .toLowerCase()
20
+ .replace(/[^a-z0-9]+/g, sep)
21
+ .replace(new RegExp(`^${escapedSep}+|${escapedSep}+$`, "g"), "");
22
+ }
23
+
24
+ /**
25
+ * Yield successive chunks of `size` items from `iterable`.
26
+ * @template T
27
+ * @param {Iterable<T>} iterable
28
+ * @param {number} size
29
+ * @returns {Generator<T[], void, unknown>}
30
+ */
31
+ export function* chunked(iterable, size) {
32
+ if (size <= 0) {
33
+ throw new RangeError("size must be positive");
34
+ }
35
+ /** @type {T[]} */
36
+ let batch = [];
37
+ for (const item of iterable) {
38
+ batch.push(item);
39
+ if (batch.length === size) {
40
+ yield batch;
41
+ batch = [];
42
+ }
43
+ }
44
+ if (batch.length > 0) {
45
+ yield batch;
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Flatten one level of nesting.
51
+ * @template T
52
+ * @param {T[][]} nested
53
+ * @returns {T[]}
54
+ */
55
+ export function flatten(nested) {
56
+ return nested.flat(1);
57
+ }
58
+
59
+ /**
60
+ * Truncate `text` to at most `length` characters, appending `suffix`.
61
+ * @param {string} text
62
+ * @param {number} length
63
+ * @param {string} [suffix]
64
+ * @returns {string}
65
+ */
66
+ export function truncate(text, length, suffix = "...") {
67
+ if (length < 0) {
68
+ throw new RangeError("length must be non-negative");
69
+ }
70
+ const str = String(text);
71
+ if (str.length <= length) {
72
+ return str;
73
+ }
74
+ if (length <= suffix.length) {
75
+ return suffix.slice(0, length);
76
+ }
77
+ return str.slice(0, length - suffix.length) + suffix;
78
+ }
79
+
80
+ /**
81
+ * Return the hex SHA-256 digest of a file.
82
+ * @param {string} path
83
+ * @returns {string}
84
+ */
85
+ export function sha256File(path) {
86
+ const data = readFileSync(path);
87
+ return createHash("sha256").update(data).digest("hex");
88
+ }