utilium 2.5.2 → 2.5.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "utilium",
3
- "version": "2.5.2",
3
+ "version": "2.5.3",
4
4
  "description": "Typescript utilities",
5
5
  "funding": {
6
6
  "type": "individual",
package/scripts/lice.js CHANGED
@@ -2,37 +2,78 @@
2
2
  // SPDX-License-Identifier: LGPL-3.0-or-later
3
3
  // Copyright (c) 2025 James Prevett
4
4
 
5
- import { readdirSync } from 'node:fs';
5
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
6
6
  import { readFile, writeFile } from 'node:fs/promises';
7
- import { join, matchesGlob, relative } from 'node:path';
7
+ import { dirname, join, matchesGlob, relative } from 'node:path';
8
8
  import { parseArgs, styleText } from 'node:util';
9
9
 
10
- const {
11
- positionals: dirs,
12
- values: { license: expectedLicense, write, verbose, force, exclude },
13
- } = parseArgs({
10
+ const { positionals: dirs, values: opts } = parseArgs({
14
11
  allowPositionals: true,
15
12
  options: {
16
- license: { type: 'string', short: 'L' },
17
- write: { type: 'boolean', short: 'w', default: false },
18
- verbose: { type: 'boolean', short: 'v', default: false },
13
+ auto: { type: 'boolean', short: 'a', default: false },
14
+ exclude: { type: 'string', short: 'x', default: [], multiple: true },
19
15
  force: { type: 'boolean', short: 'f', default: false },
20
- exclude: { type: 'string', short: 'x', default: '' },
16
+ help: { type: 'boolean', short: 'h', default: false },
17
+ license: { type: 'string', short: 'l' },
18
+ verbose: { type: 'boolean', short: 'v', default: false },
19
+ write: { type: 'boolean', short: 'w', default: false },
21
20
  },
22
21
  });
23
22
 
24
- if (write && !expectedLicense) {
25
- console.error(styleText('red', 'You must specify a license to write with --license/-L'));
23
+ if (opts.help) {
24
+ console.error(`Usage: lice [options] <dirs...>
25
+
26
+ Options:
27
+ -f, --force Force overwrite of existing license headers
28
+ -h, --help Show this help message
29
+ -a, --auto Detect the SPDX identifier in package.json
30
+ -l, --license Specify the SPDX license identifier to check for.
31
+ -v, --verbose Enable verbose output
32
+ -w, --write Write the license header if missing
33
+ -x, --exclude Glob pattern to exclude files
34
+ `);
35
+ process.exit(0);
36
+ }
37
+
38
+ /**
39
+ *
40
+ * @returns {string|null}
41
+ */
42
+ function get_license() {
43
+ for (let dir = process.cwd(); dir != '/'; dir = dirname(dir)) {
44
+ const pkgPath = join(dir, 'package.json');
45
+ if (!existsSync(pkgPath)) continue;
46
+
47
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
48
+ if (pkg.spdx) return pkg.spdx;
49
+ if (pkg.spdxLicense) return pkg.spdxLicense;
50
+ if (pkg.license) return pkg.license;
51
+ }
52
+
53
+ return null;
54
+ }
55
+
56
+ const expectedLicense = opts.license || (opts.auto && get_license());
57
+
58
+ if (opts.write && !expectedLicense) {
59
+ console.error(styleText('red', 'You must specify a license to write.'));
26
60
  process.exit(1);
27
61
  }
28
62
 
63
+ function should_exclude(path, display) {
64
+ for (const pattern of opts.exclude) {
65
+ if (!matchesGlob(path, pattern)) continue;
66
+ console.log(styleText('whiteBright', 'Skipped:'), display);
67
+ return true;
68
+ }
69
+
70
+ return false;
71
+ }
72
+
29
73
  const licenseSpec = /^\s*\/(?:\/|\*) SPDX-License-Identifier: (.+)/;
30
74
 
31
75
  async function check_file(path, display) {
32
- if (matchesGlob(path, exclude)) {
33
- console.log(styleText('whiteBright', 'Skipped:'), display);
34
- return 'skipped';
35
- }
76
+ if (should_exclude(path, display)) return 'skipped';
36
77
 
37
78
  const content = await readFile(path, 'utf-8');
38
79
 
@@ -44,14 +85,14 @@ async function check_file(path, display) {
44
85
  }
45
86
 
46
87
  if (!expectedLicense) {
47
- if (verbose) console.log(styleText(['dim'], 'Found:'), display);
88
+ if (opts.verbose) console.log(styleText(['dim'], 'Found:'), display);
48
89
  return 'with license';
49
90
  }
50
91
 
51
92
  const [, license] = match;
52
93
 
53
94
  if (license == expectedLicense) {
54
- if (verbose) console.log(styleText(['green', 'dim'], 'Correct:'), display);
95
+ if (opts.verbose) console.log(styleText(['green', 'dim'], 'Correct:'), display);
55
96
  return 'correct';
56
97
  }
57
98
 
@@ -60,10 +101,7 @@ async function check_file(path, display) {
60
101
  }
61
102
 
62
103
  async function write_file(path, display) {
63
- if (matchesGlob(path, exclude)) {
64
- console.log(styleText('whiteBright', 'Skipped:'), display);
65
- return 'skipped';
66
- }
104
+ if (should_exclude(path, display)) return 'skipped';
67
105
 
68
106
  const content = await readFile(path, 'utf-8');
69
107
 
@@ -79,13 +117,13 @@ async function write_file(path, display) {
79
117
  const [, license] = match;
80
118
 
81
119
  if (license == expectedLicense) {
82
- if (verbose) console.log(styleText(['green', 'dim'], 'Correct:'), display);
120
+ if (opts.verbose) console.log(styleText(['green', 'dim'], 'Correct:'), display);
83
121
  return 'correct';
84
122
  }
85
123
 
86
124
  process.stdout.write(styleText('yellow', 'Mismatch: ') + display);
87
125
 
88
- if (!force) {
126
+ if (!opts.force) {
89
127
  console.log(styleText('whiteBright', ' (skipped)'));
90
128
  return 'skipped';
91
129
  }
@@ -96,6 +134,8 @@ async function write_file(path, display) {
96
134
  }
97
135
 
98
136
  function check_dir(dir, display) {
137
+ if (should_exclude(dir, display)) return 'skipped';
138
+
99
139
  const entries = readdirSync(dir, { withFileTypes: true });
100
140
 
101
141
  const results = [];
@@ -108,7 +148,7 @@ function check_dir(dir, display) {
108
148
 
109
149
  if (!entry.isFile()) continue;
110
150
 
111
- const op = write ? write_file : check_file;
151
+ const op = opts.write ? write_file : check_file;
112
152
  results.push(op(join(dir, entry.name), join(display, entry.name)));
113
153
  }
114
154
 
@@ -120,7 +160,7 @@ if (!dirs.length) {
120
160
  process.exit(1);
121
161
  }
122
162
 
123
- if (verbose) console.log('Checking:', dirs.join(', '));
163
+ if (opts.verbose) console.log('Checking:', dirs.join(', '));
124
164
 
125
165
  const promises = [];
126
166
 
@@ -147,7 +187,7 @@ try {
147
187
  results[result]++;
148
188
  }
149
189
  console.log(
150
- write ? 'Wrote' : 'Checked',
190
+ opts.write ? 'Wrote' : 'Checked',
151
191
  styleText('blueBright', raw_results.length.toString()),
152
192
  'files:',
153
193
  Object.entries(results)
@@ -0,0 +1,10 @@
1
+ {
2
+ "compilerOptions": {
3
+ "checkJs": true,
4
+ "noEmit": true,
5
+ "lib": ["ESNext"],
6
+ "module": "NodeNext",
7
+ "moduleResolution": "NodeNext"
8
+ },
9
+ "include": ["*.js"]
10
+ }