@squeep/log-helper 1.0.0 → 1.0.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
@@ -30,10 +30,10 @@ Utilities for standardized logging.
30
30
  - `prefix` A field included before the package name.
31
31
 
32
32
  Defaults, based on directory existing in project:
33
- | | `src` | `lib` | other |
33
+ | precedence -> | `lib` | `src` | other |
34
34
  |----------------|-------|-------|-------|
35
- | includePackage | false | true | false |
36
- | includeVersion | false | true | false |
35
+ | includePackage | true | false | false |
36
+ | includeVersion | true | false | false |
37
37
  | includePath | true | true | false |
38
38
  | leftTrim | 4 | 4 | 0 |
39
39
 
package/lib/file-scope.js CHANGED
@@ -8,6 +8,32 @@
8
8
  const path = require('node:path');
9
9
  const fs = require('node:fs');
10
10
 
11
+
12
+ /**
13
+ * @typedef {object} FileScopeOptions
14
+ * @property {boolean=} includePackage full package name
15
+ * @property {boolean=} includeVersion package version
16
+ * @property {boolean=} includePath when indicating filename
17
+ * @property {string=} prefix static string to include
18
+ * @property {number=} leftTrim characters to omit from start of path/filename
19
+ * @property {string=} errorPrefix string to include at start if an error was encountered
20
+ * @property {string=} delimiter joining selected components
21
+ */
22
+
23
+
24
+ /**
25
+ * @typedef {FileScopeOptions} FileScopeOptionsInternal
26
+ * @property {boolean=} _errorEncountered flag if error while setting defaults
27
+ */
28
+
29
+
30
+ /**
31
+ * @typedef {object} PackageDetails
32
+ * @property {string} name package name
33
+ * @property {string} version package version
34
+ */
35
+
36
+
11
37
  /**
12
38
  * Internal exception
13
39
  */
@@ -25,14 +51,14 @@ class FileScopeError extends Error {
25
51
 
26
52
  /**
27
53
  * Read and parse package.json from a path.
28
- * @param {String} packagePath
29
- * @returns {Object}
54
+ * @param {string} packagePath path to package.json
55
+ * @returns {PackageDetails} selected details from package.json
30
56
  */
31
57
  function readPackageJSON(packagePath) {
32
58
  try {
33
59
  const content = fs.readFileSync(path.join(packagePath, 'package.json')); // eslint-disable-line security/detect-non-literal-fs-filename
34
60
  return JSON.parse(content);
35
- } catch (e) {
61
+ } catch (e) { // eslint-disable-line no-unused-vars
36
62
  return {
37
63
  name: '(unknown)',
38
64
  version: '(unknown)',
@@ -42,16 +68,16 @@ function readPackageJSON(packagePath) {
42
68
 
43
69
 
44
70
  /**
45
- * Returns whether path p exists.
46
- * @param {String} p
47
- * @returns {Boolean}
71
+ * Returns whether path p exists and is accessible.
72
+ * @param {string} p path
73
+ * @returns {boolean} exists
48
74
  */
49
75
  function pathExists(p) {
50
76
  try {
51
77
  fs.statSync(p); // eslint-disable-line security/detect-non-literal-fs-filename
52
78
  return true;
53
79
  } catch (e) {
54
- if (e.code !== 'ENOENT') {
80
+ if (!(['ENOENT', 'EACCES'].includes(e.code))) {
55
81
  throw e;
56
82
  }
57
83
  return false;
@@ -62,20 +88,15 @@ function pathExists(p) {
62
88
  /**
63
89
  * Walk up the path of provided filename until directory with
64
90
  * package.json is located. We assume this is the package root.
65
- * @param {String} filename
66
- * @returns {String}
91
+ * @param {string} filename path to file
92
+ * @returns {string} path to package root
67
93
  */
68
94
  function locatePackageBase(filename) {
69
95
  let currentPath = filename;
70
96
  do {
71
97
  const d = path.dirname(currentPath);
72
- try {
73
- fs.statSync(path.join(d, 'package.json')); // eslint-disable-line security/detect-non-literal-fs-filename
98
+ if (pathExists(path.join(d, 'package.json'))) {
74
99
  return d + '/';
75
- } catch (e) {
76
- if (e.code !== 'ENOENT') {
77
- throw e;
78
- }
79
100
  }
80
101
  currentPath = d;
81
102
  } while (currentPath !== '/');
@@ -85,8 +106,8 @@ function locatePackageBase(filename) {
85
106
 
86
107
  /**
87
108
  * Get default options based on package directory structure.
88
- * @param {String} packageBase
89
- * @returns {Object}
109
+ * @param {string} packageBase path to package root
110
+ * @returns {FileScopeOptionsInternal} options
90
111
  */
91
112
  function defaultOptions(packageBase) {
92
113
  const options = {
@@ -109,7 +130,7 @@ function defaultOptions(packageBase) {
109
130
  } else if (pathExists(path.join(packageBase, 'src'))) {
110
131
  options.leftTrim = 4;
111
132
  }
112
- } catch (e) {
133
+ } catch (e) { // eslint-disable-line no-unused-vars
113
134
  options._errorEncountered = true;
114
135
  options.includePath = false;
115
136
  }
@@ -122,23 +143,16 @@ function defaultOptions(packageBase) {
122
143
  /**
123
144
  * Returns a function suitable for decorating a function name with
124
145
  * package information and details of the source file.
125
- * @param {String} filepath full path from __filename
126
- * @param {Object=} options
127
- * @param {Boolean=} options.includePackage
128
- * @param {Boolean=} options.includeVersion
129
- * @param {Boolean=} options.includePath
130
- * @param {String=} options.prefix
131
- * @param {Number=} options.leftTrim
132
- * @param {String=} options.errorPrefix
133
- * @param {String=} options.delimiter
134
- * @returns {Function}
146
+ * @param {string} filepath full path from __filename
147
+ * @param {FileScopeOptions=} options controlling component inclusion
148
+ * @returns {(name: string) => string} marks up provided string with selected components
135
149
  */
136
150
  function fileScope(filepath, options) {
137
151
  let errorEncountered = false;
138
152
  let packageBase = '';
139
153
  try {
140
154
  packageBase = locatePackageBase(filepath);
141
- } catch (e) {
155
+ } catch (e) { // eslint-disable-line no-unused-vars
142
156
  errorEncountered = true;
143
157
  }
144
158
  const defaults = defaultOptions(packageBase);
@@ -159,7 +173,7 @@ function fileScope(filepath, options) {
159
173
  let packageIdentifier;
160
174
  if (includePackage || includeVersion) {
161
175
  const { name: packageName, version: packageVersion } = readPackageJSON(packageBase);
162
- // including version implies including package
176
+ // Including version implies including package
163
177
  packageIdentifier = includeVersion ? `${packageName}@${packageVersion}` : packageName;
164
178
  }
165
179
 
@@ -176,7 +190,7 @@ function fileScope(filepath, options) {
176
190
  const trimmedFilename = rightTrimmed.slice(trim);
177
191
 
178
192
  const components = [errorEncountered ? errorPrefix : '', prefix, packageIdentifier, trimmedFilename]
179
- .filter((x) => x);
193
+ .filter(Boolean);
180
194
 
181
195
  const scope = components.join(delimiter);
182
196
 
package/package.json CHANGED
@@ -1,37 +1,30 @@
1
1
  {
2
2
  "name": "@squeep/log-helper",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Simple helpers for standardized logging",
5
5
  "main": "index.js",
6
6
  "engines": {
7
- "node": ">=14"
8
- },
9
- "directories": {
10
- "lib": "lib",
11
- "test": "test"
7
+ "node": ">=20.13.0"
12
8
  },
9
+ "files": [
10
+ "lib/*.js"
11
+ ],
13
12
  "scripts": {
13
+ "audit": "npm audit",
14
14
  "coverage": "nyc npm test",
15
15
  "coverage-check": "nyc check-coverage",
16
- "eslint": "eslint *.js lib test",
17
- "test": "mocha --recursive"
16
+ "eslint": "eslint index.js lib test",
17
+ "test": "node --test",
18
+ "prepare": "husky"
18
19
  },
19
20
  "keywords": [],
20
21
  "author": "Justin Wind <jwind-npm@squeep.com>",
21
22
  "license": "ISC",
22
- "pre-commit": [
23
- "eslint",
24
- "coverage",
25
- "coverage-check"
26
- ],
27
23
  "devDependencies": {
28
- "eslint": "^8.53.0",
29
- "eslint-plugin-node": "^11.1.0",
30
- "eslint-plugin-security": "^1.7.1",
31
- "eslint-plugin-sonarjs": "^0.23.0",
32
- "mocha": "^10.2.0",
33
- "nyc": "^15.1.0",
34
- "pre-commit": "^1.2.2",
35
- "sinon": "^17.0.1"
24
+ "@squeep/eslint-config": "^1",
25
+ "eslint": "^9",
26
+ "husky": "^9",
27
+ "nyc": "^17",
28
+ "sinon": "^21"
36
29
  }
37
30
  }
package/.eslintrc.json DELETED
@@ -1,89 +0,0 @@
1
- {
2
- "env": {
3
- "browser": false,
4
- "es6": true,
5
- "node": true
6
- },
7
- "extends": [
8
- "eslint:recommended",
9
- "plugin:node/recommended",
10
- "plugin:security/recommended",
11
- "plugin:sonarjs/recommended"
12
- ],
13
- "parserOptions": {
14
- "ecmaVersion": "latest"
15
- },
16
- "plugins": [
17
- "node",
18
- "security",
19
- "sonarjs"
20
- ],
21
- "rules": {
22
- "array-element-newline": [
23
- "error",
24
- "consistent"
25
- ],
26
- "arrow-parens": [
27
- "error",
28
- "always"
29
- ],
30
- "arrow-spacing": [
31
- "error",
32
- {
33
- "after": true,
34
- "before": true
35
- }
36
- ],
37
- "block-scoped-var": "error",
38
- "block-spacing": "error",
39
- "brace-style": "error",
40
- "callback-return": "error",
41
- "camelcase": "error",
42
- "class-methods-use-this": "error",
43
- "comma-dangle": [
44
- "error",
45
- "always-multiline"
46
- ],
47
- "comma-spacing": [
48
- "error",
49
- {
50
- "after": true,
51
- "before": false
52
- }
53
- ],
54
- "comma-style": [
55
- "error",
56
- "last"
57
- ],
58
- "indent": [
59
- "warn",
60
- 2,
61
- {
62
- "SwitchCase": 1
63
- }
64
- ],
65
- "sonarjs/cognitive-complexity": "warn",
66
- "sonarjs/no-duplicate-string": "warn",
67
- "keyword-spacing": "error",
68
- "linebreak-style": [
69
- "error",
70
- "unix"
71
- ],
72
- "no-unused-vars": [
73
- "error", {
74
- "varsIgnorePattern": "^_"
75
- }
76
- ],
77
- "object-curly-spacing": [
78
- "error",
79
- "always"
80
- ],
81
- "prefer-const": "error",
82
- "quotes": [
83
- "warn",
84
- "single"
85
- ],
86
- "strict": "error",
87
- "vars-on-top": "error"
88
- }
89
- }
package/.nycrc.json DELETED
@@ -1,6 +0,0 @@
1
- {
2
- "reporter": [
3
- "lcov",
4
- "text"
5
- ]
6
- }
@@ -1,282 +0,0 @@
1
- /* eslint-env mocha */
2
- 'use strict';
3
-
4
- const assert = require('assert');
5
- const sinon = require('sinon'); // eslint-disable-line node/no-unpublished-require
6
- const fs = require('fs');
7
- const {
8
- readPackageJSON,
9
- fileScope,
10
- locatePackageBase,
11
- defaultOptions,
12
- pathExists,
13
- FileScopeError,
14
- } = require('../../lib/file-scope');
15
-
16
- describe('File Scope', function () {
17
- let noentError;
18
-
19
- before(function () {
20
- noentError = new Error('ENOENT: no such file or directory');
21
- Object.assign(noentError, {
22
- errno: -2,
23
- syscall: 'stat',
24
- code: 'ENOENT',
25
- });
26
- });
27
-
28
- afterEach(function () {
29
- sinon.restore();
30
- });
31
-
32
- describe('FileScopeError', function () {
33
- it('covers', function () {
34
- const e = new FileScopeError('beep');
35
- assert.strictEqual(e.name, 'FileScopeError');
36
- });
37
- }); // FileScopeError
38
-
39
- describe('readPackageJSON', function () {
40
- let filepath;
41
- beforeEach(function () {
42
- filepath = '/path/to/package.json';
43
- sinon.stub(fs, 'readFileSync').returns(`{
44
- "name": "@example/package",
45
- "version": "3.1.4"
46
- }`);
47
- });
48
- it('covers success', function () {
49
- const result = readPackageJSON(filepath);
50
- assert.strictEqual(result.name, '@example/package');
51
- assert.strictEqual(result.version, '3.1.4');
52
- });
53
- it('covers failure', function () {
54
- fs.readFileSync.throws();
55
- const result = readPackageJSON(filepath);
56
- assert.strictEqual(result.name, '(unknown)');
57
- assert.strictEqual(result.version, '(unknown)');
58
- });
59
- }); // readJSONFile
60
-
61
- describe('pathExists', function () {
62
- let p;
63
- beforeEach(function () {
64
- p = '/path/to/package';
65
- sinon.stub(fs, 'statSync').returns();
66
- });
67
- it('returns true when path exists', function () {
68
- const result = pathExists(p);
69
- assert.strictEqual(result, true);
70
- });
71
- it('returns false when path does not exist', function () {
72
- fs.statSync.throws(noentError);
73
- const result = pathExists(p);
74
- assert.strictEqual(result, false);
75
- });
76
- it('raises other error', function () {
77
- const expectedError = new Error('oh no');
78
- fs.statSync.throws(expectedError);
79
- assert.throws(() => pathExists(p), expectedError);
80
- });
81
- }); // pathExists
82
-
83
- describe('locatePackageBase', function () {
84
- let filepath;
85
-
86
- beforeEach(function () {
87
- filepath = '/path/to/package/lib/file.js';
88
- sinon.stub(fs, 'statSync');
89
- });
90
-
91
- it('covers unstubbed result', function () {
92
- sinon.restore();
93
- locatePackageBase(__filename);
94
- });
95
-
96
- it('locates the package base', function () {
97
- fs.statSync
98
- .onCall(0).throws(noentError)
99
- .onCall(1).returns()
100
- ;
101
- const result = locatePackageBase(filepath);
102
- assert.strictEqual(result, '/path/to/package/');
103
- });
104
-
105
- it('cannot locate the package base', function () {
106
- fs.statSync.throws(noentError);
107
- assert.throws(() => locatePackageBase(filepath), FileScopeError);
108
- });
109
-
110
- it('propagates unknown error', function () {
111
- const expectedException = new Error('oh no');
112
- fs.statSync
113
- .onCall(0).throws(noentError)
114
- .onCall(1).throws(expectedException)
115
- ;
116
- assert.throws(() => locatePackageBase(filepath), expectedException);
117
- });
118
- }); // locatePackageBase
119
-
120
- describe('defaultOptions', function () {
121
- let packageBase, expected;
122
- beforeEach(function () {
123
- packageBase = '/path/to/package';
124
- sinon.stub(fs, 'statSync').returns();
125
- expected = {
126
- includePath: false,
127
- includePackage: false,
128
- includeVersion: false,
129
- leftTrim: 0,
130
- _errorEncountered: false,
131
- errorPrefix: '?',
132
- delimiter: ':',
133
- };
134
- });
135
- it('covers no path', function () {
136
- const options = defaultOptions();
137
- assert.deepStrictEqual(options, expected);
138
- });
139
- it('covers default', function () {
140
- expected.includePath = true;
141
- fs.statSync.throws(noentError);
142
- const options = defaultOptions(packageBase);
143
- assert.deepStrictEqual(options, expected);
144
- });
145
- it('covers lib package', function () {
146
- expected.includePath = true;
147
- expected.includePackage = true;
148
- expected.includeVersion = true;
149
- expected.leftTrim = 4;
150
- const options = defaultOptions(packageBase);
151
- assert.deepStrictEqual(options, expected);
152
- });
153
- it('covers src package', function () {
154
- expected.includePath = true;
155
- expected.leftTrim = 4;
156
- fs.statSync.onCall(0).throws(noentError);
157
- const options = defaultOptions(packageBase);
158
- assert.deepStrictEqual(options, expected);
159
- });
160
- it('covers error', function () {
161
- const expectedError = new Error('oh no');
162
- fs.statSync.throws(expectedError);
163
- expected._errorEncountered = true;
164
- const options = defaultOptions(packageBase);
165
- assert.deepStrictEqual(options, expected);
166
- });
167
- }); // defaultOptions
168
-
169
- describe('fileScope', function () {
170
- let filepath, options, method;
171
- beforeEach(function () {
172
- filepath = '/path/to/package/lib/deep/file.js';
173
- sinon.stub(fs, 'statSync')
174
- .onCall(0).throws(noentError) // deep
175
- .onCall(1).throws(noentError) // lib
176
- .onCall(2).returns() // packageBase
177
- ;
178
- sinon.stub(fs, 'readFileSync').returns(`{
179
- "name": "@example/package",
180
- "version": "3.1.4"
181
- }`);
182
- options = {
183
- includePath: true,
184
- includePackage: false,
185
- includeVersion: false,
186
- };
187
- method = 'method';
188
- });
189
-
190
- it('defaults', function () {
191
- filepath = '/path/to/package/code/module/file.js';
192
- fs.statSync
193
- .onCall(3).throws(noentError) // no lib
194
- .onCall(4).throws(noentError) // no src
195
- ;
196
- const result = fileScope(filepath)(method);
197
- assert.strictEqual(result, 'code/module/file:method');
198
- });
199
-
200
- it('everything', function () {
201
- options.includePath = true;
202
- options.includePackage = true;
203
- options.includeVersion = true;
204
- const result = fileScope(filepath, options)(method);
205
- assert.strictEqual(result, '@example/package@3.1.4:deep/file:method');
206
- });
207
-
208
- it('minimal', function () {
209
- options.includePath = false;
210
- options.includePackage = false;
211
- options.includeVersion = false;
212
- const result = fileScope(filepath, options)(method);
213
- assert.strictEqual(result, 'file:method');
214
- });
215
-
216
- it('package only', function () {
217
- options.includePath = false;
218
- options.includePackage = true;
219
- options.includeVersion = false;
220
- const result = fileScope(filepath, options)(method);
221
- assert.strictEqual(result, '@example/package:file:method');
222
- });
223
-
224
- it('covers no package root', function () {
225
- options.includePackage = true;
226
- fs.statSync.restore()
227
- sinon.stub(fs, 'statSync').throws(noentError);
228
- fs.readFileSync.throws(noentError);
229
- const result = fileScope(filepath, options)(method);
230
- assert.strictEqual(result, '?:(unknown):file:method');
231
- });
232
-
233
- it('covers exception while finding package root', function () {
234
- const expectedException = new Error('oh no');
235
- options.includePackage = true;
236
- fs.statSync.restore()
237
- sinon.stub(fs, 'statSync').throws(expectedException);
238
- fs.readFileSync.throws(noentError);
239
- const result = fileScope(filepath, options)(method);
240
- assert.strictEqual(result, '?:(unknown):file:method');
241
- });
242
-
243
- it('handles index.js', function () {
244
- filepath = '/path/to/package/src/deep/index.js';
245
- fs.statSync
246
- .onCall(3).throws(noentError) // no lib
247
- .onCall(4).returns() // src
248
- ;
249
- const result = fileScope(filepath)(method);
250
- assert.strictEqual(result, 'deep:method');
251
- });
252
-
253
- it('handles index.js when including path', function () {
254
- filepath = '/path/to/package/code/folder/deep/index.js';
255
- fs.statSync.restore();
256
- sinon.stub(fs, 'statSync')
257
- .throws(noentError)
258
- .onCall(3).returns() // packageBase found
259
- // no lib
260
- // no src
261
- ;
262
- const result = fileScope(filepath)(method);
263
- assert.strictEqual(result, 'code/folder/deep:method');
264
- });
265
-
266
- it('handles index.js when not including path', function () {
267
- filepath = '/path/to/package/code/folder/deep/index.ts';
268
- fs.statSync.restore();
269
- sinon.stub(fs, 'statSync')
270
- .throws(noentError)
271
- .onCall(3).returns() // packageBase found
272
- // no lib
273
- // no src
274
- ;
275
- const result = fileScope(filepath, { includePath: false })(method);
276
- assert.strictEqual(result, 'deep:method');
277
- });
278
-
279
- }); // fileScope
280
-
281
-
282
- }); // File Scope