@theunwalked/cardigantime 0.0.1

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.
Files changed (45) hide show
  1. package/.gitcarve/config.yaml +10 -0
  2. package/.gitcarve/context/content.md +1 -0
  3. package/LICENSE +65 -0
  4. package/README.md +2 -0
  5. package/dist/cardigantime.cjs +40 -0
  6. package/dist/cardigantime.cjs.map +1 -0
  7. package/dist/cardigantime.d.ts +9 -0
  8. package/dist/cardigantime.js +373 -0
  9. package/dist/cardigantime.js.map +1 -0
  10. package/dist/configure.cjs +12 -0
  11. package/dist/configure.cjs.map +1 -0
  12. package/dist/configure.d.ts +6 -0
  13. package/dist/configure.js +8 -0
  14. package/dist/configure.js.map +1 -0
  15. package/dist/constants.cjs +35 -0
  16. package/dist/constants.cjs.map +1 -0
  17. package/dist/constants.d.ts +8 -0
  18. package/dist/constants.js +27 -0
  19. package/dist/constants.js.map +1 -0
  20. package/dist/error/ArgumentError.d.ts +5 -0
  21. package/dist/read.cjs +69 -0
  22. package/dist/read.cjs.map +1 -0
  23. package/dist/read.d.ts +3 -0
  24. package/dist/read.js +46 -0
  25. package/dist/read.js.map +1 -0
  26. package/dist/types.cjs +13 -0
  27. package/dist/types.cjs.map +1 -0
  28. package/dist/types.d.ts +40 -0
  29. package/dist/types.js +9 -0
  30. package/dist/types.js.map +1 -0
  31. package/dist/util/storage.cjs +149 -0
  32. package/dist/util/storage.cjs.map +1 -0
  33. package/dist/util/storage.d.ts +31 -0
  34. package/dist/util/storage.js +126 -0
  35. package/dist/util/storage.js.map +1 -0
  36. package/dist/validate.cjs +130 -0
  37. package/dist/validate.cjs.map +1 -0
  38. package/dist/validate.d.ts +18 -0
  39. package/dist/validate.js +123 -0
  40. package/dist/validate.js.map +1 -0
  41. package/eslint.config.mjs +82 -0
  42. package/nodemon.json +14 -0
  43. package/package.json +65 -0
  44. package/vite.config.ts +98 -0
  45. package/vitest.config.ts +17 -0
@@ -0,0 +1,35 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+
5
+ const DEFAULT_ENCODING = 'utf8';
6
+ const DEFAULT_CONFIG_FILE = 'config.yaml';
7
+ const DEFAULT_OPTIONS = {
8
+ configFile: DEFAULT_CONFIG_FILE,
9
+ isRequired: false,
10
+ encoding: DEFAULT_ENCODING
11
+ };
12
+ const DEFAULT_FEATURES = [
13
+ 'config'
14
+ ];
15
+ const DEFAULT_LOGGER = {
16
+ // eslint-disable-next-line no-console
17
+ debug: console.debug,
18
+ // eslint-disable-next-line no-console
19
+ info: console.info,
20
+ // eslint-disable-next-line no-console
21
+ warn: console.warn,
22
+ // eslint-disable-next-line no-console
23
+ error: console.error,
24
+ // eslint-disable-next-line no-console
25
+ verbose: console.log,
26
+ // eslint-disable-next-line no-console
27
+ silly: console.log
28
+ };
29
+
30
+ exports.DEFAULT_CONFIG_FILE = DEFAULT_CONFIG_FILE;
31
+ exports.DEFAULT_ENCODING = DEFAULT_ENCODING;
32
+ exports.DEFAULT_FEATURES = DEFAULT_FEATURES;
33
+ exports.DEFAULT_LOGGER = DEFAULT_LOGGER;
34
+ exports.DEFAULT_OPTIONS = DEFAULT_OPTIONS;
35
+ //# sourceMappingURL=constants.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.cjs","sources":["../src/constants.ts"],"sourcesContent":["import { DefaultOptions, Feature, Logger } from \"./types\";\n\nexport const VERSION = '__VERSION__ (__GIT_BRANCH__/__GIT_COMMIT__ __GIT_TAGS__ __GIT_COMMIT_DATE__) __SYSTEM_INFO__';\nexport const PROGRAM_NAME = 'cardigantime';\nexport const DEFAULT_ENCODING = 'utf8';\nexport const DEFAULT_CONFIG_FILE = 'config.yaml';\n\nexport const DEFAULT_OPTIONS: Partial<DefaultOptions> = {\n configFile: DEFAULT_CONFIG_FILE,\n isRequired: false,\n encoding: DEFAULT_ENCODING,\n}\n\nexport const DEFAULT_FEATURES: Feature[] = ['config'];\n\nexport const DEFAULT_LOGGER: Logger = {\n // eslint-disable-next-line no-console\n debug: console.debug,\n // eslint-disable-next-line no-console\n info: console.info,\n // eslint-disable-next-line no-console\n warn: console.warn,\n // eslint-disable-next-line no-console\n error: console.error,\n // eslint-disable-next-line no-console\n verbose: console.log,\n // eslint-disable-next-line no-console\n silly: console.log,\n}\n"],"names":["DEFAULT_ENCODING","DEFAULT_CONFIG_FILE","DEFAULT_OPTIONS","configFile","isRequired","encoding","DEFAULT_FEATURES","DEFAULT_LOGGER","debug","console","info","warn","error","verbose","log","silly"],"mappings":";;;;AAIO,MAAMA,mBAAmB;AACzB,MAAMC,sBAAsB;MAEtBC,eAA2C,GAAA;IACpDC,UAAYF,EAAAA,mBAAAA;IACZG,UAAY,EAAA,KAAA;IACZC,QAAUL,EAAAA;AACd;MAEaM,gBAA8B,GAAA;AAAC,IAAA;;MAE/BC,cAAyB,GAAA;;AAElCC,IAAAA,KAAAA,EAAOC,QAAQD,KAAK;;AAEpBE,IAAAA,IAAAA,EAAMD,QAAQC,IAAI;;AAElBC,IAAAA,IAAAA,EAAMF,QAAQE,IAAI;;AAElBC,IAAAA,KAAAA,EAAOH,QAAQG,KAAK;;AAEpBC,IAAAA,OAAAA,EAASJ,QAAQK,GAAG;;AAEpBC,IAAAA,KAAAA,EAAON,QAAQK;AACnB;;;;;;;;"}
@@ -0,0 +1,8 @@
1
+ import { DefaultOptions, Feature, Logger } from './types';
2
+ export declare const VERSION = "__VERSION__ (__GIT_BRANCH__/__GIT_COMMIT__ __GIT_TAGS__ __GIT_COMMIT_DATE__) __SYSTEM_INFO__";
3
+ export declare const PROGRAM_NAME = "cardigantime";
4
+ export declare const DEFAULT_ENCODING = "utf8";
5
+ export declare const DEFAULT_CONFIG_FILE = "config.yaml";
6
+ export declare const DEFAULT_OPTIONS: Partial<DefaultOptions>;
7
+ export declare const DEFAULT_FEATURES: Feature[];
8
+ export declare const DEFAULT_LOGGER: Logger;
@@ -0,0 +1,27 @@
1
+ const DEFAULT_ENCODING = 'utf8';
2
+ const DEFAULT_CONFIG_FILE = 'config.yaml';
3
+ const DEFAULT_OPTIONS = {
4
+ configFile: DEFAULT_CONFIG_FILE,
5
+ isRequired: false,
6
+ encoding: DEFAULT_ENCODING
7
+ };
8
+ const DEFAULT_FEATURES = [
9
+ 'config'
10
+ ];
11
+ const DEFAULT_LOGGER = {
12
+ // eslint-disable-next-line no-console
13
+ debug: console.debug,
14
+ // eslint-disable-next-line no-console
15
+ info: console.info,
16
+ // eslint-disable-next-line no-console
17
+ warn: console.warn,
18
+ // eslint-disable-next-line no-console
19
+ error: console.error,
20
+ // eslint-disable-next-line no-console
21
+ verbose: console.log,
22
+ // eslint-disable-next-line no-console
23
+ silly: console.log
24
+ };
25
+
26
+ export { DEFAULT_CONFIG_FILE, DEFAULT_ENCODING, DEFAULT_FEATURES, DEFAULT_LOGGER, DEFAULT_OPTIONS };
27
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sources":["../src/constants.ts"],"sourcesContent":["import { DefaultOptions, Feature, Logger } from \"./types\";\n\nexport const VERSION = '__VERSION__ (__GIT_BRANCH__/__GIT_COMMIT__ __GIT_TAGS__ __GIT_COMMIT_DATE__) __SYSTEM_INFO__';\nexport const PROGRAM_NAME = 'cardigantime';\nexport const DEFAULT_ENCODING = 'utf8';\nexport const DEFAULT_CONFIG_FILE = 'config.yaml';\n\nexport const DEFAULT_OPTIONS: Partial<DefaultOptions> = {\n configFile: DEFAULT_CONFIG_FILE,\n isRequired: false,\n encoding: DEFAULT_ENCODING,\n}\n\nexport const DEFAULT_FEATURES: Feature[] = ['config'];\n\nexport const DEFAULT_LOGGER: Logger = {\n // eslint-disable-next-line no-console\n debug: console.debug,\n // eslint-disable-next-line no-console\n info: console.info,\n // eslint-disable-next-line no-console\n warn: console.warn,\n // eslint-disable-next-line no-console\n error: console.error,\n // eslint-disable-next-line no-console\n verbose: console.log,\n // eslint-disable-next-line no-console\n silly: console.log,\n}\n"],"names":["DEFAULT_ENCODING","DEFAULT_CONFIG_FILE","DEFAULT_OPTIONS","configFile","isRequired","encoding","DEFAULT_FEATURES","DEFAULT_LOGGER","debug","console","info","warn","error","verbose","log","silly"],"mappings":"AAIO,MAAMA,mBAAmB;AACzB,MAAMC,sBAAsB;MAEtBC,eAA2C,GAAA;IACpDC,UAAYF,EAAAA,mBAAAA;IACZG,UAAY,EAAA,KAAA;IACZC,QAAUL,EAAAA;AACd;MAEaM,gBAA8B,GAAA;AAAC,IAAA;;MAE/BC,cAAyB,GAAA;;AAElCC,IAAAA,KAAAA,EAAOC,QAAQD,KAAK;;AAEpBE,IAAAA,IAAAA,EAAMD,QAAQC,IAAI;;AAElBC,IAAAA,IAAAA,EAAMF,QAAQE,IAAI;;AAElBC,IAAAA,KAAAA,EAAOH,QAAQG,KAAK;;AAEpBC,IAAAA,OAAAA,EAASJ,QAAQK,GAAG;;AAEpBC,IAAAA,KAAAA,EAAON,QAAQK;AACnB;;;;"}
@@ -0,0 +1,5 @@
1
+ export declare class ArgumentError extends Error {
2
+ private argumentName;
3
+ constructor(argumentName: string, message: string);
4
+ get argument(): string;
5
+ }
package/dist/read.cjs ADDED
@@ -0,0 +1,69 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+
5
+ const yaml = require('js-yaml');
6
+ const path = require('path');
7
+ const storage = require('./util/storage.cjs');
8
+
9
+ function _interopNamespaceDefault(e) {
10
+ const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } });
11
+ if (e) {
12
+ for (const k in e) {
13
+ if (k !== 'default') {
14
+ const d = Object.getOwnPropertyDescriptor(e, k);
15
+ Object.defineProperty(n, k, d.get ? d : {
16
+ enumerable: true,
17
+ get: () => e[k]
18
+ });
19
+ }
20
+ }
21
+ }
22
+ n.default = e;
23
+ return Object.freeze(n);
24
+ }
25
+
26
+ const yaml__namespace = /*#__PURE__*/_interopNamespaceDefault(yaml);
27
+
28
+ function clean(obj) {
29
+ return Object.fromEntries(Object.entries(obj).filter(([_, v])=>v !== undefined));
30
+ }
31
+ const read = async (args, options)=>{
32
+ var _options_defaults;
33
+ const logger = options.logger;
34
+ const storage$1 = storage.create({
35
+ log: logger.debug
36
+ });
37
+ const resolvedConfigDir = args.configDirectory || ((_options_defaults = options.defaults) === null || _options_defaults === void 0 ? void 0 : _options_defaults.configDirectory);
38
+ logger.debug(`Resolved config directory: ${resolvedConfigDir}`);
39
+ const configFile = path.join(resolvedConfigDir, options.defaults.configFile);
40
+ logger.debug(`Attempting to load config file for cardigantime: ${configFile}`);
41
+ let rawFileConfig = {};
42
+ try {
43
+ const yamlContent = await storage$1.readFile(configFile, options.defaults.encoding);
44
+ const parsedYaml = yaml__namespace.load(yamlContent);
45
+ if (parsedYaml !== null && typeof parsedYaml === 'object') {
46
+ rawFileConfig = parsedYaml;
47
+ logger.debug('Loaded Raw File Config for getValuesFromFile: \n\n%s\n\n', JSON.stringify(rawFileConfig, null, 2));
48
+ } else if (parsedYaml !== null) {
49
+ logger.warn(`Ignoring invalid configuration format in ${configFile} for cardigantime. Expected an object, got ${typeof parsedYaml}.`);
50
+ }
51
+ } catch (error) {
52
+ if (error.code === 'ENOENT' || /not found|no such file/i.test(error.message)) {
53
+ logger.debug(`Configuration file not found at ${configFile} for cardigantime. Returning empty object.`);
54
+ } else {
55
+ // Log error but don't throw, just return empty object as per the goal of just *getting* values
56
+ logger.error(`Failed to load or parse configuration from ${configFile} for getValuesFromFile: ${error.message}`);
57
+ }
58
+ }
59
+ const config = clean({
60
+ ...rawFileConfig,
61
+ ...{
62
+ configDirectory: resolvedConfigDir
63
+ }
64
+ });
65
+ return config;
66
+ };
67
+
68
+ exports.read = read;
69
+ //# sourceMappingURL=read.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.cjs","sources":["../src/read.ts"],"sourcesContent":["import * as yaml from 'js-yaml';\nimport path from 'path';\nimport { z, ZodObject } from 'zod';\nimport { Args, ConfigSchema, Options } from './types';\nimport * as Storage from './util/storage';\n\nfunction clean(obj: any) {\n return Object.fromEntries(\n Object.entries(obj).filter(([_, v]) => v !== undefined)\n );\n}\n\nexport const read = async <T extends z.ZodRawShape>(args: Args, options: Options<T>): Promise<z.infer<ZodObject<T & typeof ConfigSchema.shape>>> => {\n const logger = options.logger;\n const storage = Storage.create({ log: logger.debug });\n\n const resolvedConfigDir = args.configDirectory || options.defaults?.configDirectory;\n logger.debug(`Resolved config directory: ${resolvedConfigDir}`);\n\n const configFile = path.join(resolvedConfigDir, options.defaults.configFile);\n logger.debug(`Attempting to load config file for cardigantime: ${configFile}`);\n\n let rawFileConfig: object = {};\n\n try {\n const yamlContent = await storage.readFile(configFile, options.defaults.encoding);\n const parsedYaml = yaml.load(yamlContent);\n if (parsedYaml !== null && typeof parsedYaml === 'object') {\n rawFileConfig = parsedYaml;\n logger.debug('Loaded Raw File Config for getValuesFromFile: \\n\\n%s\\n\\n', JSON.stringify(rawFileConfig, null, 2));\n } else if (parsedYaml !== null) {\n logger.warn(`Ignoring invalid configuration format in ${configFile} for cardigantime. Expected an object, got ${typeof parsedYaml}.`);\n }\n } catch (error: any) {\n if (error.code === 'ENOENT' || /not found|no such file/i.test(error.message)) {\n logger.debug(`Configuration file not found at ${configFile} for cardigantime. Returning empty object.`);\n } else {\n // Log error but don't throw, just return empty object as per the goal of just *getting* values\n logger.error(`Failed to load or parse configuration from ${configFile} for getValuesFromFile: ${error.message}`);\n }\n }\n\n const config: z.infer<ZodObject<T & typeof ConfigSchema.shape>> = clean({\n ...rawFileConfig,\n ...{\n configDirectory: resolvedConfigDir,\n }\n }) as z.infer<ZodObject<T & typeof ConfigSchema.shape>>;\n\n return config;\n}"],"names":["clean","obj","Object","fromEntries","entries","filter","_","v","undefined","read","args","options","logger","storage","Storage","log","debug","resolvedConfigDir","configDirectory","defaults","configFile","path","join","rawFileConfig","yamlContent","readFile","encoding","parsedYaml","yaml","load","JSON","stringify","warn","error","code","test","message","config"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,SAASA,MAAMC,GAAQ,EAAA;AACnB,IAAA,OAAOC,MAAOC,CAAAA,WAAW,CACrBD,MAAAA,CAAOE,OAAO,CAACH,GAAAA,CAAAA,CAAKI,MAAM,CAAC,CAAC,CAACC,CAAGC,EAAAA,CAAAA,CAAE,GAAKA,CAAMC,KAAAA,SAAAA,CAAAA,CAAAA;AAErD;AAEO,MAAMC,IAAO,GAAA,OAAgCC,IAAYC,EAAAA,OAAAA,GAAAA;AAIVA,IAAAA,IAAAA,iBAAAA;IAHlD,MAAMC,MAAAA,GAASD,QAAQC,MAAM;IAC7B,MAAMC,SAAAA,GAAUC,cAAc,CAAC;AAAEC,QAAAA,GAAAA,EAAKH,OAAOI;AAAM,KAAA,CAAA;IAEnD,MAAMC,iBAAAA,GAAoBP,IAAKQ,CAAAA,eAAe,KAAIP,CAAAA,iBAAAA,GAAAA,QAAQQ,QAAQ,MAAA,IAAA,IAAhBR,iBAAAA,KAAAA,MAAAA,GAAAA,MAAAA,GAAAA,iBAAAA,CAAkBO,eAAe,CAAA;AACnFN,IAAAA,MAAAA,CAAOI,KAAK,CAAC,CAAC,2BAA2B,EAAEC,iBAAmB,CAAA,CAAA,CAAA;IAE9D,MAAMG,UAAAA,GAAaC,KAAKC,IAAI,CAACL,mBAAmBN,OAAQQ,CAAAA,QAAQ,CAACC,UAAU,CAAA;AAC3ER,IAAAA,MAAAA,CAAOI,KAAK,CAAC,CAAC,iDAAiD,EAAEI,UAAY,CAAA,CAAA,CAAA;AAE7E,IAAA,IAAIG,gBAAwB,EAAC;IAE7B,IAAI;QACA,MAAMC,WAAAA,GAAc,MAAMX,SAAQY,CAAAA,QAAQ,CAACL,UAAYT,EAAAA,OAAAA,CAAQQ,QAAQ,CAACO,QAAQ,CAAA;QAChF,MAAMC,UAAAA,GAAaC,eAAKC,CAAAA,IAAI,CAACL,WAAAA,CAAAA;AAC7B,QAAA,IAAIG,UAAe,KAAA,IAAA,IAAQ,OAAOA,UAAAA,KAAe,QAAU,EAAA;YACvDJ,aAAgBI,GAAAA,UAAAA;AAChBf,YAAAA,MAAAA,CAAOI,KAAK,CAAC,0DAAA,EAA4Dc,KAAKC,SAAS,CAACR,eAAe,IAAM,EAAA,CAAA,CAAA,CAAA;SAC1G,MAAA,IAAII,eAAe,IAAM,EAAA;YAC5Bf,MAAOoB,CAAAA,IAAI,CAAC,CAAC,yCAAyC,EAAEZ,UAAW,CAAA,2CAA2C,EAAE,OAAOO,UAAW,CAAA,CAAC,CAAC,CAAA;AACxI;AACJ,KAAA,CAAE,OAAOM,KAAY,EAAA;QACjB,IAAIA,KAAAA,CAAMC,IAAI,KAAK,QAAA,IAAY,0BAA0BC,IAAI,CAACF,KAAMG,CAAAA,OAAO,CAAG,EAAA;AAC1ExB,YAAAA,MAAAA,CAAOI,KAAK,CAAC,CAAC,gCAAgC,EAAEI,UAAAA,CAAW,0CAA0C,CAAC,CAAA;SACnG,MAAA;;YAEHR,MAAOqB,CAAAA,KAAK,CAAC,CAAC,2CAA2C,EAAEb,WAAW,wBAAwB,EAAEa,KAAMG,CAAAA,OAAO,CAAE,CAAA,CAAA;AACnH;AACJ;AAEA,IAAA,MAAMC,SAA4DrC,KAAM,CAAA;AACpE,QAAA,GAAGuB,aAAa;QAChB,GAAG;YACCL,eAAiBD,EAAAA;;AAEzB,KAAA,CAAA;IAEA,OAAOoB,MAAAA;AACX;;;;"}
package/dist/read.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { z, ZodObject } from 'zod';
2
+ import { Args, ConfigSchema, Options } from './types';
3
+ export declare const read: <T extends z.ZodRawShape>(args: Args, options: Options<T>) => Promise<z.infer<ZodObject<T & typeof ConfigSchema.shape>>>;
package/dist/read.js ADDED
@@ -0,0 +1,46 @@
1
+ import * as yaml from 'js-yaml';
2
+ import path from 'path';
3
+ import { create } from './util/storage.js';
4
+
5
+ function clean(obj) {
6
+ return Object.fromEntries(Object.entries(obj).filter(([_, v])=>v !== undefined));
7
+ }
8
+ const read = async (args, options)=>{
9
+ var _options_defaults;
10
+ const logger = options.logger;
11
+ const storage = create({
12
+ log: logger.debug
13
+ });
14
+ const resolvedConfigDir = args.configDirectory || ((_options_defaults = options.defaults) === null || _options_defaults === void 0 ? void 0 : _options_defaults.configDirectory);
15
+ logger.debug(`Resolved config directory: ${resolvedConfigDir}`);
16
+ const configFile = path.join(resolvedConfigDir, options.defaults.configFile);
17
+ logger.debug(`Attempting to load config file for cardigantime: ${configFile}`);
18
+ let rawFileConfig = {};
19
+ try {
20
+ const yamlContent = await storage.readFile(configFile, options.defaults.encoding);
21
+ const parsedYaml = yaml.load(yamlContent);
22
+ if (parsedYaml !== null && typeof parsedYaml === 'object') {
23
+ rawFileConfig = parsedYaml;
24
+ logger.debug('Loaded Raw File Config for getValuesFromFile: \n\n%s\n\n', JSON.stringify(rawFileConfig, null, 2));
25
+ } else if (parsedYaml !== null) {
26
+ logger.warn(`Ignoring invalid configuration format in ${configFile} for cardigantime. Expected an object, got ${typeof parsedYaml}.`);
27
+ }
28
+ } catch (error) {
29
+ if (error.code === 'ENOENT' || /not found|no such file/i.test(error.message)) {
30
+ logger.debug(`Configuration file not found at ${configFile} for cardigantime. Returning empty object.`);
31
+ } else {
32
+ // Log error but don't throw, just return empty object as per the goal of just *getting* values
33
+ logger.error(`Failed to load or parse configuration from ${configFile} for getValuesFromFile: ${error.message}`);
34
+ }
35
+ }
36
+ const config = clean({
37
+ ...rawFileConfig,
38
+ ...{
39
+ configDirectory: resolvedConfigDir
40
+ }
41
+ });
42
+ return config;
43
+ };
44
+
45
+ export { read };
46
+ //# sourceMappingURL=read.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.js","sources":["../src/read.ts"],"sourcesContent":["import * as yaml from 'js-yaml';\nimport path from 'path';\nimport { z, ZodObject } from 'zod';\nimport { Args, ConfigSchema, Options } from './types';\nimport * as Storage from './util/storage';\n\nfunction clean(obj: any) {\n return Object.fromEntries(\n Object.entries(obj).filter(([_, v]) => v !== undefined)\n );\n}\n\nexport const read = async <T extends z.ZodRawShape>(args: Args, options: Options<T>): Promise<z.infer<ZodObject<T & typeof ConfigSchema.shape>>> => {\n const logger = options.logger;\n const storage = Storage.create({ log: logger.debug });\n\n const resolvedConfigDir = args.configDirectory || options.defaults?.configDirectory;\n logger.debug(`Resolved config directory: ${resolvedConfigDir}`);\n\n const configFile = path.join(resolvedConfigDir, options.defaults.configFile);\n logger.debug(`Attempting to load config file for cardigantime: ${configFile}`);\n\n let rawFileConfig: object = {};\n\n try {\n const yamlContent = await storage.readFile(configFile, options.defaults.encoding);\n const parsedYaml = yaml.load(yamlContent);\n if (parsedYaml !== null && typeof parsedYaml === 'object') {\n rawFileConfig = parsedYaml;\n logger.debug('Loaded Raw File Config for getValuesFromFile: \\n\\n%s\\n\\n', JSON.stringify(rawFileConfig, null, 2));\n } else if (parsedYaml !== null) {\n logger.warn(`Ignoring invalid configuration format in ${configFile} for cardigantime. Expected an object, got ${typeof parsedYaml}.`);\n }\n } catch (error: any) {\n if (error.code === 'ENOENT' || /not found|no such file/i.test(error.message)) {\n logger.debug(`Configuration file not found at ${configFile} for cardigantime. Returning empty object.`);\n } else {\n // Log error but don't throw, just return empty object as per the goal of just *getting* values\n logger.error(`Failed to load or parse configuration from ${configFile} for getValuesFromFile: ${error.message}`);\n }\n }\n\n const config: z.infer<ZodObject<T & typeof ConfigSchema.shape>> = clean({\n ...rawFileConfig,\n ...{\n configDirectory: resolvedConfigDir,\n }\n }) as z.infer<ZodObject<T & typeof ConfigSchema.shape>>;\n\n return config;\n}"],"names":["clean","obj","Object","fromEntries","entries","filter","_","v","undefined","read","args","options","logger","storage","Storage","log","debug","resolvedConfigDir","configDirectory","defaults","configFile","path","join","rawFileConfig","yamlContent","readFile","encoding","parsedYaml","yaml","load","JSON","stringify","warn","error","code","test","message","config"],"mappings":";;;;AAMA,SAASA,MAAMC,GAAQ,EAAA;AACnB,IAAA,OAAOC,MAAOC,CAAAA,WAAW,CACrBD,MAAAA,CAAOE,OAAO,CAACH,GAAAA,CAAAA,CAAKI,MAAM,CAAC,CAAC,CAACC,CAAGC,EAAAA,CAAAA,CAAE,GAAKA,CAAMC,KAAAA,SAAAA,CAAAA,CAAAA;AAErD;AAEO,MAAMC,IAAO,GAAA,OAAgCC,IAAYC,EAAAA,OAAAA,GAAAA;AAIVA,IAAAA,IAAAA,iBAAAA;IAHlD,MAAMC,MAAAA,GAASD,QAAQC,MAAM;IAC7B,MAAMC,OAAAA,GAAUC,MAAc,CAAC;AAAEC,QAAAA,GAAAA,EAAKH,OAAOI;AAAM,KAAA,CAAA;IAEnD,MAAMC,iBAAAA,GAAoBP,IAAKQ,CAAAA,eAAe,KAAIP,CAAAA,iBAAAA,GAAAA,QAAQQ,QAAQ,MAAA,IAAA,IAAhBR,iBAAAA,KAAAA,MAAAA,GAAAA,MAAAA,GAAAA,iBAAAA,CAAkBO,eAAe,CAAA;AACnFN,IAAAA,MAAAA,CAAOI,KAAK,CAAC,CAAC,2BAA2B,EAAEC,iBAAmB,CAAA,CAAA,CAAA;IAE9D,MAAMG,UAAAA,GAAaC,KAAKC,IAAI,CAACL,mBAAmBN,OAAQQ,CAAAA,QAAQ,CAACC,UAAU,CAAA;AAC3ER,IAAAA,MAAAA,CAAOI,KAAK,CAAC,CAAC,iDAAiD,EAAEI,UAAY,CAAA,CAAA,CAAA;AAE7E,IAAA,IAAIG,gBAAwB,EAAC;IAE7B,IAAI;QACA,MAAMC,WAAAA,GAAc,MAAMX,OAAQY,CAAAA,QAAQ,CAACL,UAAYT,EAAAA,OAAAA,CAAQQ,QAAQ,CAACO,QAAQ,CAAA;QAChF,MAAMC,UAAAA,GAAaC,IAAKC,CAAAA,IAAI,CAACL,WAAAA,CAAAA;AAC7B,QAAA,IAAIG,UAAe,KAAA,IAAA,IAAQ,OAAOA,UAAAA,KAAe,QAAU,EAAA;YACvDJ,aAAgBI,GAAAA,UAAAA;AAChBf,YAAAA,MAAAA,CAAOI,KAAK,CAAC,0DAAA,EAA4Dc,KAAKC,SAAS,CAACR,eAAe,IAAM,EAAA,CAAA,CAAA,CAAA;SAC1G,MAAA,IAAII,eAAe,IAAM,EAAA;YAC5Bf,MAAOoB,CAAAA,IAAI,CAAC,CAAC,yCAAyC,EAAEZ,UAAW,CAAA,2CAA2C,EAAE,OAAOO,UAAW,CAAA,CAAC,CAAC,CAAA;AACxI;AACJ,KAAA,CAAE,OAAOM,KAAY,EAAA;QACjB,IAAIA,KAAAA,CAAMC,IAAI,KAAK,QAAA,IAAY,0BAA0BC,IAAI,CAACF,KAAMG,CAAAA,OAAO,CAAG,EAAA;AAC1ExB,YAAAA,MAAAA,CAAOI,KAAK,CAAC,CAAC,gCAAgC,EAAEI,UAAAA,CAAW,0CAA0C,CAAC,CAAA;SACnG,MAAA;;YAEHR,MAAOqB,CAAAA,KAAK,CAAC,CAAC,2CAA2C,EAAEb,WAAW,wBAAwB,EAAEa,KAAMG,CAAAA,OAAO,CAAE,CAAA,CAAA;AACnH;AACJ;AAEA,IAAA,MAAMC,SAA4DrC,KAAM,CAAA;AACpE,QAAA,GAAGuB,aAAa;QAChB,GAAG;YACCL,eAAiBD,EAAAA;;AAEzB,KAAA,CAAA;IAEA,OAAOoB,MAAAA;AACX;;;;"}
package/dist/types.cjs ADDED
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+
5
+ const zod = require('zod');
6
+
7
+ // Base schema for core options
8
+ const ConfigSchema = zod.z.object({
9
+ configDirectory: zod.z.string()
10
+ });
11
+
12
+ exports.ConfigSchema = ConfigSchema;
13
+ //# sourceMappingURL=types.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.cjs","sources":["../src/types.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { ZodObject } from \"zod\";\n\nimport { z } from \"zod\";\n\nexport type Feature = 'config';\n\nexport interface DefaultOptions {\n configDirectory: string;\n configFile: string;\n isRequired: boolean;\n encoding: string;\n}\n\n// Use ZodRawShape for easier merging later\nexport interface Options<T extends z.ZodRawShape> {\n defaults: DefaultOptions,\n features: Feature[],\n configShape: T; // User-defined configuration shape\n logger: Logger;\n}\n\nexport interface Logger {\n debug: (message: string, ...args: any[]) => void;\n info: (message: string, ...args: any[]) => void;\n warn: (message: string, ...args: any[]) => void;\n error: (message: string, ...args: any[]) => void;\n verbose: (message: string, ...args: any[]) => void;\n silly: (message: string, ...args: any[]) => void;\n}\n\n// Make interface generic\nexport interface Cardigantime<T extends z.ZodRawShape> {\n configure: (command: Command) => Promise<Command>;\n setLogger: (logger: Logger) => void;\n read: (args: Args) => Promise<z.infer<ZodObject<T & typeof ConfigSchema.shape>>>;\n validate: (config: z.infer<ZodObject<T & typeof ConfigSchema.shape>>) => Promise<void>;\n}\n\nexport interface Args {\n [key: string]: any;\n}\n\n// Base schema for core options\nexport const ConfigSchema = z.object({\n configDirectory: z.string(),\n});\n\nexport type Config = z.infer<typeof ConfigSchema>;\n"],"names":["ConfigSchema","z","object","configDirectory","string"],"mappings":";;;;;;AA2CA;AACaA,MAAAA,YAAAA,GAAeC,KAAEC,CAAAA,MAAM,CAAC;AACjCC,IAAAA,eAAAA,EAAiBF,MAAEG,MAAM;AAC7B,CAAG;;;;"}
@@ -0,0 +1,40 @@
1
+ import { Command } from 'commander';
2
+ import { ZodObject, z } from 'zod';
3
+ export type Feature = 'config';
4
+ export interface DefaultOptions {
5
+ configDirectory: string;
6
+ configFile: string;
7
+ isRequired: boolean;
8
+ encoding: string;
9
+ }
10
+ export interface Options<T extends z.ZodRawShape> {
11
+ defaults: DefaultOptions;
12
+ features: Feature[];
13
+ configShape: T;
14
+ logger: Logger;
15
+ }
16
+ export interface Logger {
17
+ debug: (message: string, ...args: any[]) => void;
18
+ info: (message: string, ...args: any[]) => void;
19
+ warn: (message: string, ...args: any[]) => void;
20
+ error: (message: string, ...args: any[]) => void;
21
+ verbose: (message: string, ...args: any[]) => void;
22
+ silly: (message: string, ...args: any[]) => void;
23
+ }
24
+ export interface Cardigantime<T extends z.ZodRawShape> {
25
+ configure: (command: Command) => Promise<Command>;
26
+ setLogger: (logger: Logger) => void;
27
+ read: (args: Args) => Promise<z.infer<ZodObject<T & typeof ConfigSchema.shape>>>;
28
+ validate: (config: z.infer<ZodObject<T & typeof ConfigSchema.shape>>) => Promise<void>;
29
+ }
30
+ export interface Args {
31
+ [key: string]: any;
32
+ }
33
+ export declare const ConfigSchema: ZodObject<{
34
+ configDirectory: z.ZodString;
35
+ }, "strip", z.ZodTypeAny, {
36
+ configDirectory: string;
37
+ }, {
38
+ configDirectory: string;
39
+ }>;
40
+ export type Config = z.infer<typeof ConfigSchema>;
package/dist/types.js ADDED
@@ -0,0 +1,9 @@
1
+ import { z } from 'zod';
2
+
3
+ // Base schema for core options
4
+ const ConfigSchema = z.object({
5
+ configDirectory: z.string()
6
+ });
7
+
8
+ export { ConfigSchema };
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sources":["../src/types.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { ZodObject } from \"zod\";\n\nimport { z } from \"zod\";\n\nexport type Feature = 'config';\n\nexport interface DefaultOptions {\n configDirectory: string;\n configFile: string;\n isRequired: boolean;\n encoding: string;\n}\n\n// Use ZodRawShape for easier merging later\nexport interface Options<T extends z.ZodRawShape> {\n defaults: DefaultOptions,\n features: Feature[],\n configShape: T; // User-defined configuration shape\n logger: Logger;\n}\n\nexport interface Logger {\n debug: (message: string, ...args: any[]) => void;\n info: (message: string, ...args: any[]) => void;\n warn: (message: string, ...args: any[]) => void;\n error: (message: string, ...args: any[]) => void;\n verbose: (message: string, ...args: any[]) => void;\n silly: (message: string, ...args: any[]) => void;\n}\n\n// Make interface generic\nexport interface Cardigantime<T extends z.ZodRawShape> {\n configure: (command: Command) => Promise<Command>;\n setLogger: (logger: Logger) => void;\n read: (args: Args) => Promise<z.infer<ZodObject<T & typeof ConfigSchema.shape>>>;\n validate: (config: z.infer<ZodObject<T & typeof ConfigSchema.shape>>) => Promise<void>;\n}\n\nexport interface Args {\n [key: string]: any;\n}\n\n// Base schema for core options\nexport const ConfigSchema = z.object({\n configDirectory: z.string(),\n});\n\nexport type Config = z.infer<typeof ConfigSchema>;\n"],"names":["ConfigSchema","z","object","configDirectory","string"],"mappings":";;AA2CA;AACaA,MAAAA,YAAAA,GAAeC,CAAEC,CAAAA,MAAM,CAAC;AACjCC,IAAAA,eAAAA,EAAiBF,EAAEG,MAAM;AAC7B,CAAG;;;;"}
@@ -0,0 +1,149 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+
5
+ const fs = require('fs');
6
+ const glob = require('glob');
7
+ const path = require('path');
8
+ const crypto = require('crypto');
9
+
10
+ function _interopNamespaceDefault(e) {
11
+ const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } });
12
+ if (e) {
13
+ for (const k in e) {
14
+ if (k !== 'default') {
15
+ const d = Object.getOwnPropertyDescriptor(e, k);
16
+ Object.defineProperty(n, k, d.get ? d : {
17
+ enumerable: true,
18
+ get: () => e[k]
19
+ });
20
+ }
21
+ }
22
+ }
23
+ n.default = e;
24
+ return Object.freeze(n);
25
+ }
26
+
27
+ const fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
28
+
29
+ // eslint-disable-next-line no-restricted-imports
30
+ const create = (params)=>{
31
+ // eslint-disable-next-line no-console
32
+ const log = params.log || console.log;
33
+ const exists = async (path)=>{
34
+ try {
35
+ await fs__namespace.promises.stat(path);
36
+ return true;
37
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
38
+ } catch (error) {
39
+ return false;
40
+ }
41
+ };
42
+ const isDirectory = async (path)=>{
43
+ const stats = await fs__namespace.promises.stat(path);
44
+ if (!stats.isDirectory()) {
45
+ log(`${path} is not a directory`);
46
+ return false;
47
+ }
48
+ return true;
49
+ };
50
+ const isFile = async (path)=>{
51
+ const stats = await fs__namespace.promises.stat(path);
52
+ if (!stats.isFile()) {
53
+ log(`${path} is not a file`);
54
+ return false;
55
+ }
56
+ return true;
57
+ };
58
+ const isReadable = async (path)=>{
59
+ try {
60
+ await fs__namespace.promises.access(path, fs__namespace.constants.R_OK);
61
+ } catch (error) {
62
+ log(`${path} is not readable: %s %s`, error.message, error.stack);
63
+ return false;
64
+ }
65
+ return true;
66
+ };
67
+ const isWritable = async (path)=>{
68
+ try {
69
+ await fs__namespace.promises.access(path, fs__namespace.constants.W_OK);
70
+ } catch (error) {
71
+ log(`${path} is not writable: %s %s`, error.message, error.stack);
72
+ return false;
73
+ }
74
+ return true;
75
+ };
76
+ const isFileReadable = async (path)=>{
77
+ return await exists(path) && await isFile(path) && await isReadable(path);
78
+ };
79
+ const isDirectoryWritable = async (path)=>{
80
+ return await exists(path) && await isDirectory(path) && await isWritable(path);
81
+ };
82
+ const isDirectoryReadable = async (path)=>{
83
+ return await exists(path) && await isDirectory(path) && await isReadable(path);
84
+ };
85
+ const createDirectory = async (path)=>{
86
+ try {
87
+ await fs__namespace.promises.mkdir(path, {
88
+ recursive: true
89
+ });
90
+ } catch (mkdirError) {
91
+ throw new Error(`Failed to create output directory ${path}: ${mkdirError.message} ${mkdirError.stack}`);
92
+ }
93
+ };
94
+ const readFile = async (path, encoding)=>{
95
+ return await fs__namespace.promises.readFile(path, {
96
+ encoding: encoding
97
+ });
98
+ };
99
+ const writeFile = async (path, data, encoding)=>{
100
+ await fs__namespace.promises.writeFile(path, data, {
101
+ encoding: encoding
102
+ });
103
+ };
104
+ const forEachFileIn = async (directory, callback, options = {
105
+ pattern: '*.*'
106
+ })=>{
107
+ try {
108
+ const files = await glob.glob(options.pattern, {
109
+ cwd: directory,
110
+ nodir: true
111
+ });
112
+ for (const file of files){
113
+ await callback(path.join(directory, file));
114
+ }
115
+ } catch (err) {
116
+ throw new Error(`Failed to glob pattern ${options.pattern} in ${directory}: ${err.message}`);
117
+ }
118
+ };
119
+ const readStream = async (path)=>{
120
+ return fs__namespace.createReadStream(path);
121
+ };
122
+ const hashFile = async (path, length)=>{
123
+ const file = await readFile(path, 'utf8');
124
+ return crypto.createHash('sha256').update(file).digest('hex').slice(0, length);
125
+ };
126
+ const listFiles = async (directory)=>{
127
+ return await fs__namespace.promises.readdir(directory);
128
+ };
129
+ return {
130
+ exists,
131
+ isDirectory,
132
+ isFile,
133
+ isReadable,
134
+ isWritable,
135
+ isFileReadable,
136
+ isDirectoryWritable,
137
+ isDirectoryReadable,
138
+ createDirectory,
139
+ readFile,
140
+ readStream,
141
+ writeFile,
142
+ forEachFileIn,
143
+ hashFile,
144
+ listFiles
145
+ };
146
+ };
147
+
148
+ exports.create = create;
149
+ //# sourceMappingURL=storage.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.cjs","sources":["../../src/util/storage.ts"],"sourcesContent":["// eslint-disable-next-line no-restricted-imports\nimport * as fs from 'fs';\nimport { glob } from 'glob';\nimport path from 'path';\nimport crypto from 'crypto';\n/**\n * This module exists to isolate filesystem operations from the rest of the codebase.\n * This makes testing easier by avoiding direct fs mocking in jest configuration.\n * \n * Additionally, abstracting storage operations allows for future flexibility - \n * this export utility may need to work with storage systems other than the local filesystem\n * (e.g. S3, Google Cloud Storage, etc).\n */\n\nexport interface Utility {\n exists: (path: string) => Promise<boolean>;\n isDirectory: (path: string) => Promise<boolean>;\n isFile: (path: string) => Promise<boolean>;\n isReadable: (path: string) => Promise<boolean>;\n isWritable: (path: string) => Promise<boolean>;\n isFileReadable: (path: string) => Promise<boolean>;\n isDirectoryWritable: (path: string) => Promise<boolean>;\n isDirectoryReadable: (path: string) => Promise<boolean>;\n createDirectory: (path: string) => Promise<void>;\n readFile: (path: string, encoding: string) => Promise<string>;\n readStream: (path: string) => Promise<fs.ReadStream>;\n writeFile: (path: string, data: string | Buffer, encoding: string) => Promise<void>;\n forEachFileIn: (directory: string, callback: (path: string) => Promise<void>, options?: { pattern: string }) => Promise<void>;\n hashFile: (path: string, length: number) => Promise<string>;\n listFiles: (directory: string) => Promise<string[]>;\n}\n\nexport const create = (params: { log?: (message: string, ...args: any[]) => void }): Utility => {\n\n // eslint-disable-next-line no-console\n const log = params.log || console.log;\n\n const exists = async (path: string): Promise<boolean> => {\n try {\n await fs.promises.stat(path);\n return true;\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n } catch (error: any) {\n return false;\n }\n }\n\n const isDirectory = async (path: string): Promise<boolean> => {\n const stats = await fs.promises.stat(path);\n if (!stats.isDirectory()) {\n log(`${path} is not a directory`);\n return false;\n }\n return true;\n }\n\n const isFile = async (path: string): Promise<boolean> => {\n const stats = await fs.promises.stat(path);\n if (!stats.isFile()) {\n log(`${path} is not a file`);\n return false;\n }\n return true;\n }\n\n const isReadable = async (path: string): Promise<boolean> => {\n try {\n await fs.promises.access(path, fs.constants.R_OK);\n } catch (error: any) {\n log(`${path} is not readable: %s %s`, error.message, error.stack);\n return false;\n }\n return true;\n }\n\n const isWritable = async (path: string): Promise<boolean> => {\n try {\n await fs.promises.access(path, fs.constants.W_OK);\n } catch (error: any) {\n log(`${path} is not writable: %s %s`, error.message, error.stack);\n return false;\n }\n return true;\n }\n\n const isFileReadable = async (path: string): Promise<boolean> => {\n return await exists(path) && await isFile(path) && await isReadable(path);\n }\n\n const isDirectoryWritable = async (path: string): Promise<boolean> => {\n return await exists(path) && await isDirectory(path) && await isWritable(path);\n }\n\n const isDirectoryReadable = async (path: string): Promise<boolean> => {\n return await exists(path) && await isDirectory(path) && await isReadable(path);\n }\n\n const createDirectory = async (path: string): Promise<void> => {\n try {\n await fs.promises.mkdir(path, { recursive: true });\n } catch (mkdirError: any) {\n throw new Error(`Failed to create output directory ${path}: ${mkdirError.message} ${mkdirError.stack}`);\n }\n }\n\n const readFile = async (path: string, encoding: string): Promise<string> => {\n return await fs.promises.readFile(path, { encoding: encoding as BufferEncoding });\n }\n\n const writeFile = async (path: string, data: string | Buffer, encoding: string): Promise<void> => {\n await fs.promises.writeFile(path, data, { encoding: encoding as BufferEncoding });\n }\n\n const forEachFileIn = async (directory: string, callback: (file: string) => Promise<void>, options: { pattern: string | string[] } = { pattern: '*.*' }): Promise<void> => {\n try {\n const files = await glob(options.pattern, { cwd: directory, nodir: true });\n for (const file of files) {\n await callback(path.join(directory, file));\n }\n } catch (err: any) {\n throw new Error(`Failed to glob pattern ${options.pattern} in ${directory}: ${err.message}`);\n }\n }\n\n const readStream = async (path: string): Promise<fs.ReadStream> => {\n return fs.createReadStream(path);\n }\n\n const hashFile = async (path: string, length: number): Promise<string> => {\n const file = await readFile(path, 'utf8');\n return crypto.createHash('sha256').update(file).digest('hex').slice(0, length);\n }\n\n const listFiles = async (directory: string): Promise<string[]> => {\n return await fs.promises.readdir(directory);\n }\n\n return {\n exists,\n isDirectory,\n isFile,\n isReadable,\n isWritable,\n isFileReadable,\n isDirectoryWritable,\n isDirectoryReadable,\n createDirectory,\n readFile,\n readStream,\n writeFile,\n forEachFileIn,\n hashFile,\n listFiles,\n };\n}"],"names":["create","params","log","console","exists","path","fs","promises","stat","error","isDirectory","stats","isFile","isReadable","access","constants","R_OK","message","stack","isWritable","W_OK","isFileReadable","isDirectoryWritable","isDirectoryReadable","createDirectory","mkdir","recursive","mkdirError","Error","readFile","encoding","writeFile","data","forEachFileIn","directory","callback","options","pattern","files","glob","cwd","nodir","file","join","err","readStream","createReadStream","hashFile","length","crypto","createHash","update","digest","slice","listFiles","readdir"],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import * as fs from 'fs';
2
+ /**
3
+ * This module exists to isolate filesystem operations from the rest of the codebase.
4
+ * This makes testing easier by avoiding direct fs mocking in jest configuration.
5
+ *
6
+ * Additionally, abstracting storage operations allows for future flexibility -
7
+ * this export utility may need to work with storage systems other than the local filesystem
8
+ * (e.g. S3, Google Cloud Storage, etc).
9
+ */
10
+ export interface Utility {
11
+ exists: (path: string) => Promise<boolean>;
12
+ isDirectory: (path: string) => Promise<boolean>;
13
+ isFile: (path: string) => Promise<boolean>;
14
+ isReadable: (path: string) => Promise<boolean>;
15
+ isWritable: (path: string) => Promise<boolean>;
16
+ isFileReadable: (path: string) => Promise<boolean>;
17
+ isDirectoryWritable: (path: string) => Promise<boolean>;
18
+ isDirectoryReadable: (path: string) => Promise<boolean>;
19
+ createDirectory: (path: string) => Promise<void>;
20
+ readFile: (path: string, encoding: string) => Promise<string>;
21
+ readStream: (path: string) => Promise<fs.ReadStream>;
22
+ writeFile: (path: string, data: string | Buffer, encoding: string) => Promise<void>;
23
+ forEachFileIn: (directory: string, callback: (path: string) => Promise<void>, options?: {
24
+ pattern: string;
25
+ }) => Promise<void>;
26
+ hashFile: (path: string, length: number) => Promise<string>;
27
+ listFiles: (directory: string) => Promise<string[]>;
28
+ }
29
+ export declare const create: (params: {
30
+ log?: (message: string, ...args: any[]) => void;
31
+ }) => Utility;
@@ -0,0 +1,126 @@
1
+ import * as fs from 'fs';
2
+ import { glob } from 'glob';
3
+ import path from 'path';
4
+ import crypto from 'crypto';
5
+
6
+ // eslint-disable-next-line no-restricted-imports
7
+ const create = (params)=>{
8
+ // eslint-disable-next-line no-console
9
+ const log = params.log || console.log;
10
+ const exists = async (path)=>{
11
+ try {
12
+ await fs.promises.stat(path);
13
+ return true;
14
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
15
+ } catch (error) {
16
+ return false;
17
+ }
18
+ };
19
+ const isDirectory = async (path)=>{
20
+ const stats = await fs.promises.stat(path);
21
+ if (!stats.isDirectory()) {
22
+ log(`${path} is not a directory`);
23
+ return false;
24
+ }
25
+ return true;
26
+ };
27
+ const isFile = async (path)=>{
28
+ const stats = await fs.promises.stat(path);
29
+ if (!stats.isFile()) {
30
+ log(`${path} is not a file`);
31
+ return false;
32
+ }
33
+ return true;
34
+ };
35
+ const isReadable = async (path)=>{
36
+ try {
37
+ await fs.promises.access(path, fs.constants.R_OK);
38
+ } catch (error) {
39
+ log(`${path} is not readable: %s %s`, error.message, error.stack);
40
+ return false;
41
+ }
42
+ return true;
43
+ };
44
+ const isWritable = async (path)=>{
45
+ try {
46
+ await fs.promises.access(path, fs.constants.W_OK);
47
+ } catch (error) {
48
+ log(`${path} is not writable: %s %s`, error.message, error.stack);
49
+ return false;
50
+ }
51
+ return true;
52
+ };
53
+ const isFileReadable = async (path)=>{
54
+ return await exists(path) && await isFile(path) && await isReadable(path);
55
+ };
56
+ const isDirectoryWritable = async (path)=>{
57
+ return await exists(path) && await isDirectory(path) && await isWritable(path);
58
+ };
59
+ const isDirectoryReadable = async (path)=>{
60
+ return await exists(path) && await isDirectory(path) && await isReadable(path);
61
+ };
62
+ const createDirectory = async (path)=>{
63
+ try {
64
+ await fs.promises.mkdir(path, {
65
+ recursive: true
66
+ });
67
+ } catch (mkdirError) {
68
+ throw new Error(`Failed to create output directory ${path}: ${mkdirError.message} ${mkdirError.stack}`);
69
+ }
70
+ };
71
+ const readFile = async (path, encoding)=>{
72
+ return await fs.promises.readFile(path, {
73
+ encoding: encoding
74
+ });
75
+ };
76
+ const writeFile = async (path, data, encoding)=>{
77
+ await fs.promises.writeFile(path, data, {
78
+ encoding: encoding
79
+ });
80
+ };
81
+ const forEachFileIn = async (directory, callback, options = {
82
+ pattern: '*.*'
83
+ })=>{
84
+ try {
85
+ const files = await glob(options.pattern, {
86
+ cwd: directory,
87
+ nodir: true
88
+ });
89
+ for (const file of files){
90
+ await callback(path.join(directory, file));
91
+ }
92
+ } catch (err) {
93
+ throw new Error(`Failed to glob pattern ${options.pattern} in ${directory}: ${err.message}`);
94
+ }
95
+ };
96
+ const readStream = async (path)=>{
97
+ return fs.createReadStream(path);
98
+ };
99
+ const hashFile = async (path, length)=>{
100
+ const file = await readFile(path, 'utf8');
101
+ return crypto.createHash('sha256').update(file).digest('hex').slice(0, length);
102
+ };
103
+ const listFiles = async (directory)=>{
104
+ return await fs.promises.readdir(directory);
105
+ };
106
+ return {
107
+ exists,
108
+ isDirectory,
109
+ isFile,
110
+ isReadable,
111
+ isWritable,
112
+ isFileReadable,
113
+ isDirectoryWritable,
114
+ isDirectoryReadable,
115
+ createDirectory,
116
+ readFile,
117
+ readStream,
118
+ writeFile,
119
+ forEachFileIn,
120
+ hashFile,
121
+ listFiles
122
+ };
123
+ };
124
+
125
+ export { create };
126
+ //# sourceMappingURL=storage.js.map