@awesomeness-js/utils 1.0.25 → 1.1.2

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/README.md CHANGED
@@ -1,44 +1,51 @@
1
1
  # Nothing Special
2
2
 
3
- Just some <u>zero dependency</u> utils ...
3
+ Just some <u>zero dependency</u>* utils that every [Awesomeness.js](https://github.com/awesomeness-js) project uses.
4
4
 
5
+ **Perfect?** Far from it.
6
+
7
+ Better than what you have now? For sure.
5
8
 
6
9
  ---
7
10
 
8
11
  # 🚀 Auto-Generate API Exports for Your Node.js Project
9
12
 
10
-
11
13
  ## 📌 Why "build" Exists
12
14
 
13
- When working on a Node.js project, you often need to import multiple functions from a directory and structure them in a clean, accessible way. Webpack is overkill for this—it’s designed for browser bundling, not for generating structured API exports in a Node.js environment.
15
+ When you’re building a Node.js project, pulling functions together into a clean, predictable API shouldn’t feel like busywork. But maintaining a manual `index.js` is a waste of time, and Webpack? That’s a browser bundler—great for shipping front-end bundles, useless for building a logical backend export layer.
16
+
17
+ This script takes that grunt work off your plate and does it **right**:
14
18
 
15
- This script **automates** that process. It dynamically scans your source directory (`./src`), imports functions, and generates an `index.js` file that:
19
+ **Consolidates all exports** into a single, perfectly structured API object
20
+ ✅ **Keeps function names and namespaces** exactly as your folder structure dictates—no mystery, no guessing
21
+ ✅ **Pulls in JSDoc comments** so your documentation is baked right into the build. Intellisense loves this.
22
+ ✅ **Runs in plain Node.js**—zero bundlers, zero fluff, zero excuses
23
+
24
+
25
+ Hint: Use the [Awesomeness Intellitip](https://marketplace.visualstudio.com/items?itemName=awesomeness.awesomeness-intellitip) VS Code Extension for classy hover documentation.
16
26
 
17
- ✅ **Consolidates all exports** into a structured API object.
18
- ✅ **Preserves function names and namespaces** based on folder structure.
19
- ✅ **Extracts JSDoc comments** for better documentation.
20
- ✅ **Works in plain Node.js**—no need for Webpack or extra dependencies.
21
27
 
22
28
  ---
23
29
 
24
- ## 🚀 Why Use "build" Instead of Webpack?
30
+ ## 💡 Why Use This Over Webpack or Manual Indexing?
25
31
 
26
- **Webpack is great for frontend bundling, but it’s not ideal for this use case.** Here’s why this script is a better choice:
32
+ Webpack is a great bundler, but it’s not suited for building a structured export layer for backend code. This script offers a focused, ergonomic solution:
27
33
 
28
- ✔ **Zero dependencies**—Runs in plain Node.js, no Webpack or config files required.
29
- ✔ **Automatic function export generation**—No need to manually update an `index.js`.
34
+ ✔ **Automatic export generation** no more maintaining `index.js` by hand
30
35
  ✔ **JSDoc extraction**—Includes comments directly in the generated file.
31
36
  ✔ **Simple and predictable**—You control how exports are structured.
32
37
  ✔ **Namespace support**—Uses folder structure to organize functions logically.
38
+ ✔ **Minimal setup** — one line to generate your exports
39
+ ✔ **Dev-friendly hot rebuild** — optional file watching with HMR-style rebuilds
33
40
 
34
- With this script, you can stop wasting time managing exports and focus on writing code.
41
+ > Uses `chokidar` under the hood for reliable cross-platform file watching.
35
42
 
36
43
  ---
37
44
 
38
- ## How It Works
45
+ ## ⚙️ How It Works
39
46
 
40
- 1. **Scans** the `./src` directory for `.js` files.
41
- 2. **Generates** import statements dynamically.
47
+ 1. **Scans** the `./src` directory for `.js` files
48
+ 2. **Generates** import statements
42
49
  3. **Creates** an API object that mirrors your folder structure.
43
50
  4. **Extracts JSDoc comments** from each file and attaches them to the exports.
44
51
  5. **Outputs** a clean, structured `index.js` file, ready to use.
@@ -47,103 +54,122 @@ With this script, you can stop wasting time managing exports and focus on writin
47
54
 
48
55
  ## 🔧 Usage
49
56
 
50
- Simply run:
51
-
52
- By default, this will:
53
- - Scan `./src` for JavaScript files
54
- - Generate an `index.js` file
55
- - Structure exports based on your folder hierarchy
57
+ To run it:
56
58
 
57
- ```javascript
58
-
59
- import { build } from '@awesomeness-js/utils';
60
-
61
- build();
59
+ ```js
60
+ import build from '@awesomeness-js/utils/build.js';
62
61
 
62
+ await build();
63
63
  ```
64
64
 
65
- If you need custom paths, modify the `src` and `dest` options in the script:
66
-
67
- ```javascript
65
+ This will:
66
+ - Scan the `./src` directory
67
+ - Create or overwrite `./index.js`
68
+ - Structure exports based on your file and folder layout
68
69
 
69
- import { build } from '@awesomeness-js/utils';
70
+ Customize it:
70
71
 
71
- build({
72
- src: './my-functions',
73
- dest: './api.js'
72
+ ```js
73
+ await build({
74
+ src: './my-functions',
75
+ dest: './api.js',
76
+ includeComments: true,
77
+ useTabs: true,
78
+ hotModuleReload: true // Enable hot reload for dev
74
79
  });
75
80
  ```
76
81
 
77
82
  ---
78
83
 
79
- ## 📜 Example Output
84
+ ## 📦 Example Output
80
85
 
81
- If your folder structure looks like this:
86
+ Given this folder structure:
82
87
 
83
88
  ```
84
89
  src/
85
- │── utils/
86
- │ ├── formatDate.js
87
- │ ├── generateId.js
88
- │── services/
89
- │ ├── fetchData.js
90
- │── calculate.js
90
+ ├── roxbury/
91
+ │ ├── didYouJustGrabMyAss.js
92
+ │ ├── areYouGuysBrothers.js
93
+ ├── bros/
94
+ │ ├── didWeJustBecomeBestFriends.js
95
+ │ ├── prestigeWorldwide.js
96
+ ├── rickyBobby/
97
+ │ ├── iWakeUpAndPissExcellence.js
98
+ │ ├── iRaiseWinners.js
99
+ │ ├── shakeAndBake.js
100
+ ├── oldSchool/
101
+ │ ├── youMyBoyBlue.js
102
+ ├── news/
103
+ │ ├── thatEscalatedQuickly.js
104
+ │ ├── stayClassy.js
105
+ │ ├── milkWasABadChoice.js
106
+ ├── tommy/
107
+ │ ├── roomService.js
108
+ │ ├── fatGuyInALittleCoat.js
109
+ ├── menInTights/
110
+ │ ├── youGrewBoobs.js
111
+ │ ├── merryMen/
112
+ │ │ ├── snipTheTip.js
91
113
  ```
92
114
 
93
- Your generated `index.js` will look like this:
94
-
95
- ```javascript
96
- /**
97
- * This file is auto-generated by the build script.
98
- * It consolidates API functions for use in the application.
99
- * Do not edit manually.
100
- */
101
-
102
- import utils_formatDate from './src/utils/formatDate.js';
103
- import utils_generateId from './src/utils/generateId.js';
104
- import services_fetchData from './src/services/fetchData.js';
105
- import calculate from './src/calculate.js';
106
-
107
- export { calculate };
108
- export default {
109
- utils: {
110
- formatDate: utils_formatDate,
111
- generateId: utils_generateId
112
- },
113
- services: {
114
- fetchData: services_fetchData
115
- },
116
- calculate
117
- };
118
- ```
119
115
 
120
- Your api is now neatly organized and ready to use!
121
- and will look like this
122
- ```javascript
123
- import { calculate } from './api.js';
124
- const result = calculate(5, 10);
125
- console.log(result);
126
- ```
116
+ #### Use it like:
127
117
 
128
- or
118
+ ```js
119
+
120
+ // Default import: full API
121
+ import api from './index.js';
122
+
123
+ // Use the full API
124
+ api.roxbury.didYouJustGrabMyAss();
125
+
126
+ // perfect for CTRL+F
127
+ api.rickyBobby.shakeAndBake();
128
+
129
+ // deep
130
+ api.menInTights.youGrewBoobs();
131
+ api.menInTights.merryMen.snipTheTip();
129
132
 
130
- ```javascript
131
- import { utils } from './api.js';
132
- const id = utils.generateId();
133
- console.log(id);
134
133
  ```
135
134
 
135
+ ```js
136
+
137
+ // Named import also work
138
+ import { youMyBoy, roxbury } from './api.js';
136
139
 
140
+ // Use the named group
141
+ youMyBoy.blue();
142
+ roxbury.didYouGrabMyAss();
143
+
144
+ ```
137
145
 
138
146
  ---
139
147
 
140
- ## 🚀 Who Should Use This?
148
+ ## 💪 Who’s This For?
149
+
150
+ - **Teams** who want **clean and consistent** APIs
151
+ - **Expert** ~~developers~~ **architects** obsessed with
152
+ - organization
153
+ - hierarchy
154
+ - explicit namespacing
155
+ - clean code
156
+ - **Champions** who know CTRL+F `app.roxbury.didYouJustGrabMyAss` will <u>always beat</u> any “magic” refactor tool when it comes to finding **every. single. usage.**
157
+ - Developers who refuse to hide functions behind lazy aliases, and instead demand predictable, grep-able APIs that tell you **exactly where the code lives.**
158
+
159
+ If you want a smarter way to manage and structure exports in a Node.js project — without extra tooling bloat — this script was built for you.
141
160
 
142
- - **Node.js developers** who want automatic API exports.
143
- - **Backend teams** managing large function directories.
144
- - **Anyone tired of manually updating `index.js` files.**
161
+ If that makes you hard, you’re in the right place.
145
162
 
146
- If you don’t need Webpacks **complexity** but want **automatic structured exports**, this script is for you.
163
+ > If it makes you mad… youve probably never built a scalable codebase.
164
+
165
+ ---
147
166
 
148
- 👉 **Try it out and let automation handle your exports!** 🚀
167
+ **Ready to make development great again?**
168
+ 👉 [awesomenessjs.com](https://awesomenessjs.com)
149
169
 
170
+ ---
171
+ ✱ disclaimer... *Kinda zero dependencies.*
172
+ Zero **prod** dependencies.
173
+ > dev dependencies:
174
+ > `chokidar` for hot module reloading (HMR)
175
+ > `vitest` for testing
package/build/build.js CHANGED
@@ -4,10 +4,15 @@ build({
4
4
  src: './src',
5
5
  dest: './index.js',
6
6
  dts: false,
7
+ hotModuleReload: false,
8
+ hotCallback: (file) => {
9
+
10
+ console.log(`[build callback] processed ${file}`);
11
+
12
+ },
7
13
  ignore: [
8
14
  'ignoreMe.js',
9
15
  'ignoreFolder/*',
10
- //'namespaceExample/*',
11
16
  ],
12
17
  });
13
18
 
package/index.js CHANGED
@@ -20,13 +20,12 @@ import _each from './src/each.js';
20
20
  import _eachAsync from './src/eachAsync.js';
21
21
  import _encrypt from './src/encrypt.js';
22
22
  import _getAllFiles from './src/getAllFiles.js';
23
- import _ignoreFolder_ignoreMe from './src/ignoreFolder/ignoreMe.js';
24
- import _ignoreMe from './src/ignoreMe.js';
25
23
  import _isUUID from './src/isUUID.js';
26
24
  import _md5 from './src/md5.js';
27
25
  import _password_check from './src/password/check.js';
28
26
  import _password_hash from './src/password/hash.js';
29
27
  import _setLocalEnvs from './src/setLocalEnvs.js';
28
+ import _shouldIgnore from './src/shouldIgnore.js';
30
29
  import _thingType from './src/thingType.js';
31
30
  import _toPennies from './src/toPennies.js';
32
31
  import _utils_buildExportsTree from './src/utils/buildExportsTree.js';
@@ -39,7 +38,7 @@ import _utils_generateImportStatements from './src/utils/generateImportStatement
39
38
  import _utils_generateNamedExports from './src/utils/generateNamedExports.js';
40
39
  import _utils_generateNamespaceCode from './src/utils/generateNamespaceCode.js';
41
40
  import _utils_generateNamespaceExportLines from './src/utils/generateNamespaceExportLines.js';
42
- import _utils_shouldIgnore from './src/utils/shouldIgnore.js';
41
+ import _utils_writeHotWrapper from './src/utils/writeHotWrapper.js';
43
42
  import _uuid from './src/uuid.js';
44
43
  import _validateSchema from './src/validateSchema.js';
45
44
 
@@ -52,15 +51,46 @@ export { _each as each };
52
51
  export { _eachAsync as eachAsync };
53
52
  export { _encrypt as encrypt };
54
53
  export { _getAllFiles as getAllFiles };
55
- export { _ignoreMe as ignoreMe };
56
54
  export { _isUUID as isUUID };
57
55
  export { _md5 as md5 };
58
56
  export { _setLocalEnvs as setLocalEnvs };
57
+ export { _shouldIgnore as shouldIgnore };
59
58
  export { _thingType as thingType };
60
59
  export { _toPennies as toPennies };
61
60
  export { _uuid as uuid };
62
61
  export { _validateSchema as validateSchema };
63
62
 
63
+ export const clean = {
64
+ array: _clean_array,
65
+ boolean: _clean_boolean,
66
+ integer: _clean_integer,
67
+ number: _clean_number,
68
+ object: _clean_object,
69
+ string: _clean_string,
70
+ timestamp: _clean_timestamp,
71
+ uuid: _clean_uuid
72
+ };
73
+
74
+ export const password = {
75
+ check: _password_check,
76
+ hash: _password_hash
77
+ };
78
+
79
+ export const utils = {
80
+ buildExportsTree: _utils_buildExportsTree,
81
+ buildFileDataList: _utils_buildFileDataList,
82
+ clean: _utils_clean,
83
+ extractJSDocComment: _utils_extractJSDocComment,
84
+ generateFile: _utils_generateFile,
85
+ generateFlatExportLines: _utils_generateFlatExportLines,
86
+ generateImportStatements: _utils_generateImportStatements,
87
+ generateNamedExports: _utils_generateNamedExports,
88
+ generateNamespaceCode: _utils_generateNamespaceCode,
89
+ generateNamespaceExportLines: _utils_generateNamespaceExportLines,
90
+ writeHotWrapper: _utils_writeHotWrapper
91
+ };
92
+
93
+
64
94
  export default {
65
95
  /**
66
96
  * Builds a file from the specified source directory and writes it to the destination file.
@@ -99,10 +129,10 @@ export default {
99
129
  eachAsync: _eachAsync,
100
130
  encrypt: _encrypt,
101
131
  getAllFiles: _getAllFiles,
102
- ignoreMe: _ignoreMe,
103
132
  isUUID: _isUUID,
104
133
  md5: _md5,
105
134
  setLocalEnvs: _setLocalEnvs,
135
+ shouldIgnore: _shouldIgnore,
106
136
  thingType: _thingType,
107
137
  toPennies: _toPennies,
108
138
  uuid: _uuid,
@@ -117,9 +147,6 @@ export default {
117
147
  timestamp: _clean_timestamp,
118
148
  uuid: _clean_uuid,
119
149
  },
120
- ignoreFolder: {
121
- ignoreMe: _ignoreFolder_ignoreMe,
122
- },
123
150
  password: {
124
151
  check: _password_check,
125
152
  hash: _password_hash,
@@ -135,6 +162,6 @@ export default {
135
162
  generateNamedExports: _utils_generateNamedExports,
136
163
  generateNamespaceCode: _utils_generateNamespaceCode,
137
164
  generateNamespaceExportLines: _utils_generateNamespaceExportLines,
138
- shouldIgnore: _utils_shouldIgnore,
165
+ writeHotWrapper: _utils_writeHotWrapper,
139
166
  },
140
167
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awesomeness-js/utils",
3
- "version": "1.0.25",
3
+ "version": "1.1.2",
4
4
  "description": "Awesomeness - Utils",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,6 +21,7 @@
21
21
  "access": "public"
22
22
  },
23
23
  "devDependencies": {
24
- "vitest": "^3.0.9"
24
+ "vitest": "^3.0.9",
25
+ "chokidar": "^4.0.3"
25
26
  }
26
27
  }
package/schemas.js CHANGED
@@ -9,6 +9,7 @@ import _schema2 from './schemas/schema2.js';
9
9
  export { _schema1 as schema1 };
10
10
  export { _schema2 as schema2 };
11
11
 
12
+
12
13
  export default {
13
14
  schema1: _schema1,
14
15
  schema2: _schema2,
package/src/build.js CHANGED
@@ -12,6 +12,7 @@
12
12
  */
13
13
  import { writeFileSync } from 'fs';
14
14
  import generateFile from './utils/generateFile.js';
15
+ import writeHotWrapper from './utils/writeHotWrapper.js';
15
16
 
16
17
  async function build({
17
18
  src = './src',
@@ -20,10 +21,85 @@ async function build({
20
21
  ignore = [],
21
22
  includeComments = true,
22
23
  dts = false,
23
- useTabs = true
24
+ useTabs = true,
25
+ hotModuleReload = false,
26
+ hotCallback = null,
27
+ hotSource = './hot-source.js' // generated only when hot is enabled
24
28
  } = {}) {
25
29
 
26
- writeFileSync(dest, generateFile(src, exportRoots, ignore, includeComments, dts, useTabs));
30
+ const gen = () => generateFile({
31
+ src,
32
+ exportRoots,
33
+ ignore,
34
+ includeComments,
35
+ dts,
36
+ useTabs
37
+ });
38
+
39
+ const buildHot = () => {
40
+
41
+ // 1) write payload that the wrapper imports
42
+ writeFileSync(hotSource, gen());
43
+ console.log(`[build] wrote ${hotSource}`);
44
+
45
+ // 2) ensure index.js is a hot wrapper
46
+ writeHotWrapper({
47
+ dest,
48
+ hotSource
49
+ });
50
+
51
+ console.log(`[build] ensured hot wrapper ${dest}`);
52
+
53
+ };
54
+
55
+ const buildCold = () => {
56
+
57
+ // single-file classic output (no second file)
58
+ writeFileSync(dest, gen());
59
+ console.log(`[build] wrote ${dest}`);
60
+
61
+ };
62
+
63
+ if (hotModuleReload) {
64
+
65
+ buildHot();
66
+
67
+ // watch only src; each change regenerates hot-source.js (wrapper auto-reloads it)
68
+ const chokidar = (await import('chokidar')).default;
69
+
70
+ console.log(`[build] watching ${src} for changes...`);
71
+ const watcher = chokidar.watch(src, {
72
+ ignoreInitial: true,
73
+ ignored: ignore
74
+ });
75
+
76
+ let timeout;
77
+
78
+ watcher.on('all', (_event, file) => {
79
+
80
+ clearTimeout(timeout);
81
+ timeout = setTimeout(() => {
82
+
83
+ console.log(`[build] change detected in ${file}, rebuilding payload...`);
84
+ writeFileSync(hotSource, gen());
85
+
86
+ if(typeof hotCallback === 'function') {
87
+
88
+ hotCallback(file);
89
+
90
+ }
91
+
92
+ console.log(`[build] ready.`);
93
+
94
+ }, 50);
95
+
96
+ });
97
+
98
+ } else {
99
+
100
+ buildCold();
101
+
102
+ }
27
103
 
28
104
  return true;
29
105
 
@@ -2,7 +2,7 @@ import {
2
2
  readdirSync, statSync
3
3
  } from 'fs';
4
4
  import { join } from 'path';
5
- import shouldIgnore from './utils/shouldIgnore.js';
5
+ import shouldIgnore from './shouldIgnore.js';
6
6
 
7
7
  export default function getAllFiles(base, {
8
8
  dir = '.',
@@ -0,0 +1,99 @@
1
+ export default function shouldIgnore(filePath, ignorePatterns) {
2
+
3
+ const normalizePath = (p) => {
4
+
5
+ let v = String(p).replace(/\\/g, '/'); // Windows → POSIX
6
+
7
+ v = v.replace(/^\.\/+/, ''); // strip leading ./
8
+ v = v.replace(/\/+/g, '/'); // collapse multiple slashes
9
+ // if the path includes /src/, make it relative to src
10
+ v = v.replace(/^.*\/src(\/|$)/, '/'); // ".../src/foo" → "/foo"
11
+ if (!v.startsWith('/')) v = '/' + v; // ensure leading slash
12
+ // strip trailing slash except for root
13
+ if (v.length > 1 && v.endsWith('/')) v = v.slice(0, -1);
14
+
15
+ return v.toLowerCase(); // case-insensitive
16
+
17
+ };
18
+
19
+ const normalizePattern = (p) => {
20
+
21
+ let v = String(p).replace(/\\/g, '/').replace(/^\.\/+/, '').replace(/\/+/g, '/');
22
+
23
+ if (!v.includes('*') && !v.includes('.') && !v.endsWith('/')) v += '/';
24
+ if (!v.startsWith('/')) v = '/' + v;
25
+
26
+ return v.toLowerCase(); // case-insensitive
27
+
28
+ };
29
+
30
+ const pathCandidates = (() => {
31
+
32
+ const p = normalizePath(filePath);
33
+ const noSrc = String(filePath).replace(/\\/g, '/').replace(/^\.\/+/, '');
34
+ const alt = (noSrc.startsWith('/') ? noSrc : '/' + noSrc).toLowerCase();
35
+
36
+
37
+ return Array.from(new Set([ p, alt ]));
38
+
39
+ })();
40
+
41
+ const matches = (fp, pat) => {
42
+
43
+ // 1) "*.ext" anywhere
44
+ if (/^\/\*\.[^/]+$/.test(pat)) {
45
+
46
+ const ext = pat.slice(2); // "*.js" -> ".js"
47
+
48
+
49
+ return fp.endsWith(ext);
50
+
51
+ }
52
+
53
+ // 2) "folder/*" => only immediate children (no subfolders)
54
+ if (pat.endsWith('/*')) {
55
+
56
+ const base = pat.slice(0, -2);
57
+
58
+
59
+ return fp.startsWith(base + '/') && !fp.slice(base.length + 1).includes('/');
60
+
61
+ }
62
+
63
+ // 3) "folder/*.ext" => files with ext in that folder (no subfolders)
64
+ if (pat.includes('/*')) {
65
+
66
+ const [ base, tail ] = pat.split('/*');
67
+
68
+
69
+ return fp.startsWith(base + '/') &&
70
+ fp.endsWith(tail) &&
71
+ !fp.slice(base.length + 1).includes('/');
72
+
73
+ }
74
+
75
+ // 4) Plain directory "folder/" => whole dir + subdirs
76
+ if (pat.endsWith('/')) {
77
+
78
+ const base = pat.slice(0, -1);
79
+
80
+
81
+ return fp === base || fp.startsWith(base + '/');
82
+
83
+ }
84
+
85
+ // 5) Exact file
86
+ return fp === pat;
87
+
88
+ };
89
+
90
+ return ignorePatterns.some((raw) => {
91
+
92
+ const pat = normalizePattern(raw);
93
+
94
+
95
+ return pathCandidates.some((fp) => matches(fp, pat));
96
+
97
+ });
98
+
99
+ }
@@ -2,7 +2,11 @@ import getAllFiles from '../getAllFiles.js';
2
2
  import extractJSDocComment from './extractJSDocComment.js';
3
3
  import { join } from 'path';
4
4
 
5
- export default function buildFileDataList(src, ignore, includeComments) {
5
+ export default function buildFileDataList({
6
+ src,
7
+ ignore,
8
+ includeComments
9
+ }) {
6
10
 
7
11
  const allFiles = getAllFiles(src, {
8
12
  ignore,